UNPKG

@universis/dining

Version:

Universis api for dining

211 lines (203 loc) 6.45 kB
import { DataObjectState, DataConfigurationStrategy } from '@themost/data'; import { ApplicationService, TraceUtils } from '@themost/common'; import path from 'path'; class ValidationResult { /** * @param {boolean} success * @param {string=} code * @param {string=} message * @param {string=} innerMessage * @param {any=} data */ constructor(success, code, message, innerMessage, data) { Object.defineProperty(this, 'type', { value: this.constructor.name, writable: true, enumerable: true, }); this.success = typeof success !== 'undefined' && success !== null ? success : false; this.statusCode = this.success ? 200 : 422; this.code = code; this.message = message; this.innerMessage = innerMessage; this.data = data; } } function instanceOf(any, ctor) { // validate constructor if (typeof ctor !== 'function') { return false; } // validate with instanceof if (any instanceof ctor) { return true; } return !!(any && any.constructor && any.constructor.name === ctor.name); } /** * * @param {DataEventArgs} event */ async function beforeSaveAsync(event) { // operate only on insert if (event.state !== DataObjectState.Insert) { return; } const context = event.model.context, student = context.model('Student').convert(event.target.student), translateService = context .getApplication() .getStrategy(function TranslateService() {}); // validate student request configuration rules // note: unattended context (registration save) replaces the context.user with the unattendedExecutionAccount // and so the validate-student-request-configuration after execute listener does not return a validationResult const studentRequestConfiguration = await context .model('StudentRequestConfiguration') .where('additionalType') .equal('DiningRequestAction') .select('id') .silent() .getTypedItem(); if (studentRequestConfiguration) { // assign student to request (for validation) Object.assign(studentRequestConfiguration, { student, }); const validationResult = await new Promise((resolve) => { return studentRequestConfiguration.validate(function (err, result) { if (err) { if (instanceOf(err, ValidationResult)) { return resolve(err); } else { return resolve( new ValidationResult( false, 'EFAIL', context.__('An internal server error occurred.'), err.message ) ); } } return resolve(result); }); }); // if the student cannot apply for dining due to rules, exit if (validationResult && validationResult.success === false) { return; } } // get student dining preference effective status const diningPreferenceEffectiveStatus = await student.getDiningPreferenceEffectiveStatus(); // validate effective status existance (edge case) if (diningPreferenceEffectiveStatus == null) { return; } // switch on the status code // important note here: The REQUEST_REQUIRED code will only be returned // if the institute sets the configuration forceRequestOnPositivePreference to true // otherwise, just an REQUEST_OPTIONAL will be returned switch (diningPreferenceEffectiveStatus.code) { case 'NO_ACTION': return; case 'REQUEST_OPTIONAL': return; case 'PREFERENCE_REQUIRED': // get dining settings const diningSettings = context .getApplication() .getConfiguration() .getSourceAt('settings/universis/dining'); const forcePreferenceDeclaration = typeof ( diningSettings && diningSettings.forcePreferenceBeforePeriodRegistration ) === 'boolean' ? diningSettings.forcePreferenceBeforePeriodRegistration : false; if (forcePreferenceDeclaration) { return new ValidationResult( false, 'EFAIL', translateService.translate( 'The registration creation failed because the student has not declared their dining request preference.' ) ); } return; case 'REQUEST_REQUIRED': return new ValidationResult( false, 'EFAIL', translateService.translate( 'The registration creation failed because the student has declared a positive dining preference, but has not yet applied for dining.' ) ); default: return; } } /** * @param {DataEventArgs} event * @param {Function} callback */ function beforeSave(event, callback) { return beforeSaveAsync(event) .then((validationResult) => { if (validationResult && !validationResult.success) { return callback(validationResult); } return callback(); }) .catch((err) => { return callback(err); }); } class ValidatePreferenceOnPeriodRegistration extends ApplicationService { constructor(app) { super(app); this.install(); } install() { /** * get data configuration * @type {DataConfigurationStrategy} */ const configuration = this.getApplication() .getConfiguration() .getStrategy(DataConfigurationStrategy); // get StudentRequestAction model definition const model = configuration.getModelDefinition('StudentPeriodRegistration'); // 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 (Dining): ${this.constructor.name} service has been successfully installed` ); } } } export { beforeSave, ValidatePreferenceOnPeriodRegistration };