UNPKG

@universis/candidates

Version:

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

216 lines (211 loc) 7.07 kB
import { DataConfigurationStrategy, DataObjectState } from '@themost/data'; import { ApplicationService, DataError, TraceUtils } from '@themost/common'; import { inc, valid, coerce } from 'semver'; import path from 'path'; import { insertListener } from './utils/insertListener'; /** * * @param {DataEventArgs} event */ async function afterSaveAsync(event) { // operate only on update (active to completed status) if ( !( event.state === DataObjectState.Update && Object.prototype.hasOwnProperty.call(event.target, 'actionStatus') ) ) { return; } const context = event.model.context; // before everything, validate the required service/models that this listener handles // first, the dining service itself const diningService = context .getApplication() .getStrategy(function DiningService() {}); if (diningService == null) { TraceUtils.info( '[StudentCarePreferenceService]: DiningService is not enabled and thus a DiningRequestPreference cannot be created.' ); return; } // then, validate DiningPreference // note: at a later stage, the getDiningPreferenceEffective student status method is validated // which covers the existance of all the other related models const diningPreferenceModel = context.model('DiningRequestPreference'); if (diningPreferenceModel == null) { TraceUtils.info( '[StudentCarePreferenceService]: DiningRequestPreference model is absent in the current application context and thus a DiningRequestPreference cannot be created/validated.' ); return; } // get previous action status const previousActionStatus = event.previous && event.previous.actionStatus; if (previousActionStatus == null) { throw new DataError( 'E_PREVIOUS_STATUS', 'The previous action status of the object cannot be empty at this context.', null, 'StudyProgramRegisterAction' ); } // and target action status const targetActionStatus = await context .model('ActionStatusType') .find(event.target.actionStatus) .select('alternateName') .value(); // if this is not an accept action, exit if ( !( previousActionStatus.alternateName === 'ActiveActionStatus' && targetActionStatus === 'CompletedActionStatus' ) ) { return; } // get the dining preference value from the register action const enrollmentDiningPreference = await context .model('StudyProgramRegisterAction') .where('id') .equal(event.target.id) .select('intendsToApplyForDining') .silent() .value(); // important: proceed only if enrollmentDiningPreference is of type boolean // which means that it has actually been declared by the student // this field, of course, does not have a default value and may be null if (typeof enrollmentDiningPreference !== 'boolean') { return; } // ensure that a student has been created for the candidate const student = context .model('Student') .convert( await context .model('CandidateStudent') .find(event.previous.candidate) .select('student as id') .flatten() .getItem() ); if (student == null) { return; } // validate getDiningPreferenceEffectiveStatus method if (typeof student.getDiningPreferenceEffectiveStatus !== 'function') { TraceUtils.info( '[StudentCarePreferenceService]: The DiningPreference creation is not supported by the current DiningService version.' ); return; } // get diningRequestEvent event from effective status method const { diningRequestEvent } = await student.getDiningPreferenceEffectiveStatus(); // and validate it if (diningRequestEvent == null) { return; } // create a dining preference const diningRequestPreference = { student: student.id, diningRequestEvent, preference: enrollmentDiningPreference, }; // and save silently await diningPreferenceModel.silent().save(diningRequestPreference); } /** * @param {DataEventArgs} event * @param {Function} callback */ function afterSave(event, callback) { return afterSaveAsync(event) .then(() => { return callback(); }) .catch((err) => { return callback(err); }); } class StudentCarePreferenceService extends ApplicationService { constructor(app) { super(app); this.install(); } install() { try { /** * get data configuration * @type {DataConfigurationStrategy} */ const configuration = this.getApplication() .getConfiguration() .getStrategy(DataConfigurationStrategy); // get StudyProgramRegisterAction model definition const model = configuration.getModelDefinition( 'StudyProgramRegisterAction' ); if (model == null) { throw new Error( 'The StudyProgramRegisterAction model cannot be found in the current application context, or it has not been loaded yet.' ); } // ensure model fields model.fields = model.fields || []; let updateModelDefinition = false; // apply extra attributes/fields [ { name: 'intendsToApplyForDining', title: 'Dining preference', description: 'Indicates whether the student intends to receive dining services from the university facilities.', type: 'Boolean', }, { name: 'intendsToApplyForHousing', title: 'Housing preference', description: 'Indicates whether the student intends to receive housing services from the university facilities.', type: 'Boolean', }, ].forEach((attribute) => { // try to find attribute const attributeExists = model.fields.find( (field) => field.name === attribute.name ); if (attributeExists) { return; } // if it does not exist, add it to the fields collection model.fields.push(attribute); updateModelDefinition = true; }); // prepare listener const listener = { // get this file path relative to application execution path type: './' + path.relative(this.getApplication().getConfiguration().getExecutionPath(), __filename), insertBefore: 'send-mail-after-status-change' } // insert listener updateModelDefinition = insertListener(listener, model) || updateModelDefinition; if (!updateModelDefinition) { return; } // update model version for migrations model.version = inc(valid(coerce(model.version || '1.0.0')), 'minor'); configuration.setModelDefinition(model); // write to log TraceUtils.info( `Services: ${this.constructor.name} service has been successfully installed.` ); } catch (err) { TraceUtils.error( `An error occured while trying to install ${this.constructor.name} service.` ); TraceUtils.error(err); } } } export { afterSave, StudentCarePreferenceService };