UNPKG

@universis/candidates

Version:

Universis api server plugin for study program candidates, internship selection etc

175 lines (170 loc) 7.23 kB
// eslint-disable-next-line no-unused-vars import { DataObjectState, DataConfigurationStrategy, DataContext } from '@themost/data'; import { ApplicationService, TraceUtils, DataError, DataNotFoundError } from '@themost/common'; import path from 'path'; import { getMailer } from '@themost/mailer'; /** * * @param {DataEventArgs} event */ async function afterSaveAsync(event) { const context = event.model.context; let shouldContinue = false; // get candidate student user const user = await context.model(event.model.name) .where('id').equal(event.target.id) .select('user').silent().value(); if (event.state === DataObjectState.Insert) { shouldContinue = (user != null); } else if (event.state === DataObjectState.Update) { const previous = event.previous; if (previous == null) { throw new DataError('E_STATE', 'Invalid configuration. The previous state of an object cannot be determined.', null, 'CandidateStudent'); } shouldContinue = (previous.user == null) && (user != null); } if (shouldContinue === false) { // exit return; } // validate sms service const service = context.getApplication().getService(function SmsService() {}); if (service == null) { throw new Error('Invalid application configuration. Messaging service is missing or is inaccessible state.'); } // send sms message // first of all get register web application const application = await context.model('WebApplication') .where('alternateName').equal('register') .and('applicationSuite').equal('universis') .silent().getItem(); if (application == null) { throw new DataNotFoundError('A required object for account activation notification is missing. User cannot be notified for this action.', null, 'WebApplication'); } // get candidate const candidate = await context.model('CandidateStudent') .where('user').equal(user).expand('person').silent().getItem(); const candidateUser = await context.model('CandidateUser') .where('id').equal(user).silent().getItem(); // assign user Object.assign(candidate, { user: candidateUser }); if (candidate.user == null) { throw new DataNotFoundError('Candidate user cannot be found. The operation cannot be completed.', null, 'CandidateUser', 'activationCode'); } if (candidate.user.activationCode == null) { throw new DataError('E_USER', 'User state is invalid. The operation cannot be completed.', null, 'CandidateUser', 'activationCode'); } const mailer = getMailer(context); let mailTemplate = await context.model('MailConfiguration') .where('target').equal('NotifyCandidateUserAction') .and('state').equal(DataObjectState.Update) .silent().getItem(); if (mailTemplate == null) { // throw error throw new DataNotFoundError('Sms template for account activation notification is missing. User cannot be notified for this action.', null, 'MailConfiguration'); } const result = await new Promise((resolve, reject) => { mailer.template(mailTemplate.template) .test(true) .send({ model: { candidate, application } }, (err, body) => { if (err) { TraceUtils.error('NotifyCandidateUserAction', 'An error occurred while trying to send an sms notification for account activation.'); return reject(err); } // send message return resolve(body); }); }); // create message await context.model('SMS').silent().save({ sender: context.user, recipient: user, body: result.html }); } /** * @param {DataEventArgs} event * @param {Function} callback */ function afterSave(event, callback) { return afterSaveAsync(event).then(() => { return callback(); }).catch((err) => { return callback(err); }); } class SendSmsAfterCreateCandidateUser extends ApplicationService { /** * @param {*=} app */ constructor(app) { // call super constructor super(app); if (app != null) { // if application is defined, install service this.install('CandidateUser', __filename); } } install() { /** * get data configuration * @type {DataConfigurationStrategy} */ const configuration = this.getApplication().getConfiguration().getStrategy(DataConfigurationStrategy); // get StudentRequestAction model definition const model = configuration.getModelDefinition('CandidateStudent'); // get this file path relative to application execution path const listenerType = './' + path.relative(this.getApplication().getConfiguration().getExecutionPath(), __filename); // ensure model event listeners model.eventListeners = model.eventListeners || []; // try to find event listener const findIndex = model.eventListeners.findIndex(listener => { return listener.type === listenerType || listener.type === listenerType.replace(/\.js$/, ''); }); if (findIndex < 0) { // add event listener model.eventListeners.push({ type: listenerType }); // update StudentRequestAction model definition configuration.setModelDefinition(model); // write to log TraceUtils.info(`Services: ${this.constructor.name} service has been successfully installed`); } } /** * @param {DataContext} context * @param {{id: number, user: *}} candidate */ async send(context, candidate) { const CandidateStudents = context.model('CandidateStudent'); // get candidate and validate const target = await CandidateStudents.where('id').equal(candidate).getTypedItem(); if (target == null) { TraceUtils.error('SendSmsAfterCreateCandidateUser', 'An attempt of sending sms notification to a candidate failed because the specified candidate was not found.'); throw new DataNotFoundError('Candidate cannot be found or is inaccessible', null, 'CandidateStudent'); } if (target.user == null) { TraceUtils.error('SendSmsAfterCreateCandidateUser', 'An attempt of sending sms notification to a candidate failed because the specified candidate does not have an associated user or user was not found.'); throw new DataNotFoundError('User cannot be found or is inaccessible', null, 'CandidateUser'); } await afterSaveAsync({ model: CandidateStudents, // set event model state: DataObjectState.Insert, // set state to insert to force sending message target: target // set candidate as target object }); return true; } } export { afterSave, SendSmsAfterCreateCandidateUser }