@universis/candidates
Version:
Universis api server plugin for study program candidates, internship selection etc
168 lines (166 loc) • 5.13 kB
JavaScript
import { DataError, DataNotFoundError } from '@themost/common';
import { DataObjectState } from '@themost/data';
import { Guid } from '@themost/common';
/**
* @param {DataEventArgs} event
*/
async function beforeSaveAsync(event) {
// operate only on insert
if (event.state !== DataObjectState.Insert) {
return;
}
if (!event.target.hasOwnProperty('candidate')) {
return;
}
const context = event.model.context;
const candidate = event.target.candidate;
// if candidate is set on insert, exit
if (
typeof candidate === 'number' ||
typeof candidate === 'string' ||
(typeof candidate === 'object' && candidate.hasOwnProperty('id'))
) {
return;
}
// validate isAccessibleForFree property of event
if (event.target.studyProgramEnrollmentEvent == null) {
throw new DataError(
'E_ENROLLMENT_EVENT',
'The study program enrollment event cannot be empty at this context.'
);
}
const enrollmentEvent = await context
.model('StudyProgramEnrollmentEvent')
.where('id')
.equal(
event.target.studyProgramEnrollmentEvent.id ||
event.target.studyProgramEnrollmentEvent
)
.select('id', 'isAccessibleForFree', 'studyProgram', 'inscriptionMode')
.flatten()
.silent()
.getItem();
if (enrollmentEvent == null) {
throw new DataNotFoundError(
'The specified enrollment event cannot be found'
);
}
if (!enrollmentEvent.isAccessibleForFree) {
throw new DataError(
'E_ACCESS',
'The study program does not accept self-registration.'
);
}
if (enrollmentEvent.inscriptionMode == null) {
throw new DataError(
'E_DEFAULT_INSCR_MODE',
'The default inscription mode is not set for the event.'
);
}
// find study program and always validate it
if (!candidate.studyProgram) {
throw new DataError(
'E_STUDY_PROGRAM',
'The candidate study program cannot be empty at this context'
);
}
const studyProgram = await context
.model('StudyProgram')
.where('id')
.equal(candidate.studyProgram.id || candidate.studyProgram)
.and('isActive')
.equal(true)
.expand('specialties')
.getItem();
if (studyProgram == null) {
throw new DataNotFoundError(
'The (active) study program cannot be found or is inaccessible.'
);
}
// validate that study program
// indeed belongs to the event
if (enrollmentEvent.studyProgram !== studyProgram.id) {
throw new DataError(
'E_STUDY_PROGRAM',
'The provided study program is invalid.'
);
}
// if no specialization is set
if (!candidate.specialtyId || !candidate.studyProgramSpecialty) {
const specialtyId =
candidate.specialtyId != null ? candidate.specialtyId : -1;
// find study program specialty
const studyProgramSpecialty = studyProgram.specialties.find(
(specialization) => specialization.specialty === specialtyId
);
if (studyProgramSpecialty == null) {
throw new DataNotFoundError(
'The study program specialty cannot be found or is inaccessible.'
);
}
// assign data to candidate
candidate.studyProgramSpecialty = studyProgramSpecialty;
candidate.specialtyId = specialtyId;
// also, append specialization to study program register action
event.target.specialization = studyProgramSpecialty;
} else {
// if provided, always validate that study program and specialization match
const trueSpecialty = studyProgram.specialties.find(
(specialization) => specialization.specialty == candidate.specialtyId
);
const studyProgramSpecialty =
candidate.studyProgramSpecialty.id || candidate.studyProgramSpecialty;
if (studyProgramSpecialty != trueSpecialty.id) {
throw new DataError('E_SPECIALTY', 'The provided specialty is invalid.');
}
}
// check if candidate has already enrolled in this study program and specialty
const alreadyEnrolled = await context
.model('StudyProgramRegisterAction')
.where('studyProgram')
.equal(enrollmentEvent.studyProgram)
.and('actionStatus/alternateName')
.notEqual('CancelledActionStatus')
.and('owner')
.equal(event.target.owner)
.and('specialization')
.equal(candidate.studyProgramSpecialty.id || candidate.studyProgramSpecialty)
.select('id')
.silent()
.count();
if (alreadyEnrolled) {
throw new DataError(
'E_ALREADY_ENROLLED',
'The user has already enrolled (or has a pending enrollment request) in the specified study program and specialty.'
);
}
// assign extra attributes
Object.assign(candidate, {
// note: active studentStatus is forced when converting candidate to student
studentStatus: {
alternateName: 'candidate',
},
// first semester and inscriptionSemester
semester: 1,
inscriptionSemester: 1,
// a guid for inscriptionNumber
inscriptionNumber: Guid.newGuid().toString(),
// and the event's default inscriptionMode
inscriptionMode: enrollmentEvent.inscriptionMode,
});
// and emulate nested attribute by saving candidate
await context.model('CandidateStudent').save(candidate);
}
/**
* @param {DataEventArgs} event
* @param {Function} callback
*/
export function beforeSave(event, callback) {
return beforeSaveAsync(event)
.then(() => {
return callback();
})
.catch((err) => {
return callback(err);
});
}