155 lines
4.8 KiB
TypeScript
155 lines
4.8 KiB
TypeScript
import { exec } from 'child_process';
|
|
// @ts-ignore
|
|
import fs from 'fs';
|
|
import { ShellLdapUserProvider } from './user/shell_ldap_user';
|
|
import { TwakeDriveClient, TwakeDriveUser } from './twake_client';
|
|
import path from 'path';
|
|
import { logger } from "./logger"
|
|
import { User, UserProvider, UserProviderFactory, UserProviderType } from "./user/user_privider";
|
|
|
|
export interface NextcloudMigrationConfiguration {
|
|
shell: {
|
|
baseDn: string,
|
|
url: string,
|
|
},
|
|
lemon: {
|
|
url: string,
|
|
auth: string,
|
|
}
|
|
drive: {
|
|
url: string,
|
|
credentials: {
|
|
appId: string,
|
|
secret: string,
|
|
}
|
|
},
|
|
tmpDir: string,
|
|
nextcloudUrl: string
|
|
userProvider: UserProviderType
|
|
}
|
|
|
|
export class NextcloudMigration {
|
|
|
|
private config: NextcloudMigrationConfiguration;
|
|
|
|
private userProvider: UserProvider;
|
|
|
|
driveClient: TwakeDriveClient;
|
|
|
|
constructor(config: NextcloudMigrationConfiguration) {
|
|
this.config = config;
|
|
this.userProvider = (new UserProviderFactory()).get(config.userProvider, config[config.userProvider]);
|
|
this.driveClient = new TwakeDriveClient(this.config.drive);
|
|
}
|
|
|
|
async migrate(username: string, password: string) {
|
|
const dir = this.createTmpDir(username);
|
|
try {
|
|
const user = await this.getLDAPUser(username);
|
|
//create user if needed Twake Drive
|
|
const driveUser = await this.driveClient.createUser(user);
|
|
console.log(`Drive user ${driveUser.id} created`);
|
|
//download all files from nextcloud to tmp dir
|
|
await this.download(username, password, dir);
|
|
//upload files to the Twake Drive
|
|
await this.upload(driveUser, dir);
|
|
} catch (e) {
|
|
console.error('Error downloading files from next cloud', e);
|
|
throw e;
|
|
} finally {
|
|
this.deleteDir(dir);
|
|
}
|
|
}
|
|
|
|
async download(username: string, password: string, dir: string) {
|
|
return new Promise((resolve, reject) => {
|
|
let cmd = `nextcloudcmd -s --non-interactive -u '${username}' -p '${password}' ${dir} ${this.config.nextcloudUrl}`;
|
|
console.log('Start downloading data from Nextcloud');
|
|
exec(cmd, (error, stdout, stderr) => {
|
|
if (stderr) {
|
|
console.log('ERROR: ' + stderr);
|
|
}
|
|
if (stdout) {
|
|
console.log('OUT: ' + stdout);
|
|
}
|
|
if (error) {
|
|
console.log(`ERROR running sync for the user: ${error.message}`);
|
|
reject(error.message);
|
|
} else {
|
|
console.log('Download finished');
|
|
resolve('');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
async getLDAPUser(username: string): Promise<User> {
|
|
const user = await this.userProvider.find(username);
|
|
if (!user.email) {
|
|
throw new Error(`User ${username} not found`);
|
|
}
|
|
return user;
|
|
}
|
|
|
|
createTmpDir(username: string) {
|
|
console.log('Creating tmp directory for the user data');
|
|
const dir = this.config.tmpDir + '/' + username + '_' + new Date().getTime();
|
|
if (!fs.existsSync(dir)) {
|
|
console.log(`Creating directory ${dir} ...`);
|
|
fs.mkdirSync(dir);
|
|
console.log(`Directory ${dir} created`);
|
|
} else {
|
|
this.deleteDir(dir);
|
|
}
|
|
return dir;
|
|
}
|
|
|
|
deleteDir(dir: string) {
|
|
console.log(`Deleting directory ${dir} ...`);
|
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
console.log(`Directory ${dir} deleted`);
|
|
}
|
|
|
|
async upload(user: TwakeDriveUser, sourceDirPath: string, parentDirId = "user_" + user.id) {
|
|
const dirsToUpload: Map<string, string> = new Map<string, string>();
|
|
const filesToUpload: string[] = [];
|
|
|
|
const parent = await this.driveClient.getDocument(parentDirId);
|
|
|
|
const exists = (filename: string) => {
|
|
return parent.children.filter(i => i.name.startsWith(path.parse(filename).name)).length > 0;
|
|
}
|
|
|
|
logger.debug(`Reading content of the directory ${sourceDirPath} ...`)
|
|
fs.readdirSync(sourceDirPath).forEach(function (name) {
|
|
const filePath = path.join(sourceDirPath, name);
|
|
const stat = fs.statSync(filePath);
|
|
if (exists(name)) {
|
|
logger.info(`File ${name} already exists`);
|
|
} else {
|
|
if (stat.isFile()) {
|
|
logger.info(`Add file for future upload ${filePath}`);
|
|
filesToUpload.push(filePath)
|
|
} else if (stat.isDirectory()) {
|
|
logger.info(`Add directory for the future upload ${filePath}`);
|
|
dirsToUpload.set(name, filePath);
|
|
}
|
|
}
|
|
});
|
|
|
|
//upload all files
|
|
logger.debug(`UPLOAD FILES FOR ${sourceDirPath}`)
|
|
for (const file of filesToUpload) {
|
|
logger.debug(`Upload file ${file}`)
|
|
await this.driveClient.createFile(file, parentDirId);
|
|
}
|
|
|
|
logger.debug(`UPLOAD DIRS FOR ${sourceDirPath}`)
|
|
for (const [name, path] of dirsToUpload) {
|
|
logger.info(`Create directory ${name}`);
|
|
const dir = await this.driveClient.createDirectory(name, parentDirId)
|
|
await this.upload(user, path, dir.id);
|
|
}
|
|
}
|
|
|
|
} |