const app = require('vn-loopback/server/server'); module.exports = Self => { Object.assign(Self, { synchronizers: [], addSynchronizer(synchronizer) { this.synchronizers.push(synchronizer); }, async getInstance() { let instance = await Self.findOne({ fields: ['homedir', 'shell', 'idBase'] }); await instance.synchronizerInit(); return instance; }, async syncUsers() { let instance = await Self.getInstance(); let usersToSync = await instance.synchronizerGetUsers(); usersToSync = Array.from(usersToSync.values()) .sort((a, b) => a.localeCompare(b)); for (let userName of usersToSync) { try { console.log(`Synchronizing user '${userName}'`); await instance.synchronizerSyncUser(userName); console.log(` -> User '${userName}' sinchronized`); } catch (err) { console.error(` -> User '${userName}' synchronization error:`, err.message); } } await instance.synchronizerDeinit(); await Self.syncRoles(); }, async syncUser(userName, password) { let instance = await Self.getInstance(); try { await instance.synchronizerSyncUser(userName, password, true); } finally { await instance.synchronizerDeinit(); } }, async syncRoles() { let instance = await Self.getInstance(); try { await instance.synchronizerSyncRoles(); } finally { await instance.synchronizerDeinit(); } }, async getSynchronizer() { return await Self.findOne(); } }); Object.assign(Self.prototype, { async synchronizerInit() { let mailConfig = await app.models.MailConfig.findOne({ fields: ['domain'] }); let synchronizers = []; for (let Synchronizer of Self.synchronizers) { let synchronizer = await Synchronizer.getSynchronizer(); if (!synchronizer) continue; Object.assign(synchronizer, { accountConfig: this }); await synchronizer.init(); synchronizers.push(synchronizer); } Object.assign(this, { synchronizers, domain: mailConfig.domain }); }, async synchronizerDeinit() { for (let synchronizer of this.synchronizers) await synchronizer.deinit(); }, async synchronizerSyncUser(userName, password, syncGroups) { let $ = app.models; if (!userName) return; userName = userName.toLowerCase(); // Skip conflicting users if (['administrator', 'root'].indexOf(userName) >= 0) return; let user = await $.Account.findOne({ where: {name: userName}, fields: [ 'id', 'nickname', 'email', 'lang', 'roleFk', 'sync', 'active', 'created', 'bcryptPassword', 'updated' ], include: { relation: 'roles', scope: { include: { relation: 'inherits', scope: { fields: ['name'] } } } } }); let info = { user, hasAccount: false }; if (user) { let exists = await $.UserAccount.exists(user.id); Object.assign(info, { hasAccount: user.active && exists, corporateMail: `${userName}@${this.domain}`, uidNumber: this.idBase + user.id }); } let errs = []; for (let synchronizer of this.synchronizers) { try { await synchronizer.syncUser(userName, info, password); if (syncGroups) await synchronizer.syncUserGroups(userName, info); } catch (err) { errs.push(err); } } if (errs.length) throw errs[0]; }, async synchronizerGetUsers() { let usersToSync = new Set(); for (let synchronizer of this.synchronizers) await synchronizer.getUsers(usersToSync); return usersToSync; }, async synchronizerSyncRoles() { for (let synchronizer of this.synchronizers) await synchronizer.syncRoles(); }, async syncUser(userName, info, password) { if (info.user && password) await app.models.user.setPassword(info.user.id, password); }, async getUsers(usersToSync) { let accounts = await app.models.UserAccount.find({ fields: ['id'], include: { relation: 'user', scope: { fields: ['name'], where: {active: true} } } }); for (let account of accounts) { let user = account.user(); if (!user) continue; usersToSync.add(user.name); } } }); };