import { Get , Post , Delete , Param , BodyParam , CurrentUser , Authorized , UseBefore , JsonController , BadRequestError , ForbiddenError , NotFoundError , InternalServerError } from 'routing-controllers' ; import passportJwtMiddleware from '../security/passportJwtMiddleware' ; import { NotificationSettings , API_NOTIFICATION_TYPE_ALL_CHANGES } from '../models/NotificationSettings' ; import { Notification } from '../models/Notification' ; import { Course , ICourseModel } from '../models/Course' ; import { Lecture , ILectureModel } from '../models/Lecture' ; import { Unit , IUnitModel } from '../models/units/Unit' ; import { User } from '../models/User' ; import { ICourse } from '../../../shared/models/ICourse' ; import { ILecture } from '../../../shared/models/ILecture' ; import { IUnit } from '../../../shared/models/units/IUnit' ; import { IUser } from '../../../shared/models/IUser' ; import { SendMailOptions } from 'nodemailer' ; import emailService from '../services/EmailService' ; import { errorCodes } from '../config/errorCodes' ; @ JsonController ( '/notification' ) @ UseBefore ( passportJwtMiddleware ) export class NotificationController { static async resolveTarget ( targetId , targetType , currentUser ) { let course ; let lecture ; let unit ; switch ( targetType ) { case 'course' : course = await Course . findById ( targetId ) . orFail ( new NotFoundError ( ) ) ; break ; case 'lecture' : lecture = await Lecture . findById ( targetId ) . orFail ( new NotFoundError ( ) ) ; course = await Course . findOne ( { lectures : targetId } ) . orFail ( new InternalServerError ( errorCodes . notification . missingCourseOfLecture . text ) ) ; break ; case 'unit' : unit = await Unit . findById ( targetId ) . orFail ( new NotFoundError ( ) ) ; course = await Course . findById ( unit . _course ) . orFail ( new InternalServerError ( errorCodes . notification . missingCourseOfUnit . text ) ) ; break ; default : throw new BadRequestError ( errorCodes . notification . invalidTargetType . text ) ; } if ( ! course . checkPrivileges ( currentUser ) . userCanEditCourse ) { throw new ForbiddenError ( ) ; } return { course , lecture , unit } ; } api apiName apiGroup apiPermission apiPermission apiParam apiParam apiParam apiSuccess apiSuccessExample apiError apiError apiError apiError apiError @ Authorized ( [ 'teacher' , 'admin' ] ) @ Post ( '/' ) async createNotifications ( @ BodyParam ( 'targetId' , { required : true } ) targetId , @ BodyParam ( 'targetType' , { required : true } ) targetType , @ BodyParam ( 'text' , { required : true } ) text , @ CurrentUser ( ) currentUser ) { const { course , lecture , unit } = await NotificationController . resolveTarget ( targetId , targetType , currentUser ) ; await Promise . all ( course . students . map ( async ( student ) => { if ( await this . shouldCreateNotification ( student , course , unit ) ) { await this . createNotification ( student , text , course , lecture , unit ) ; } } ) ) ; return { } ; } api apiName apiGroup apiPermission apiPermission apiParam apiParam apiParam apiParam apiSuccess apiSuccessExample apiError apiError apiError apiError apiError @ Authorized ( [ 'teacher' , 'admin' ] ) @ Post ( '/user/:id' ) async createNotificationForStudent ( @ Param ( 'id' ) userId , @ BodyParam ( 'targetId' , { required : false } ) targetId , @ BodyParam ( 'targetType' , { required : true } ) targetType , @ BodyParam ( 'text' , { required : false } ) text , @ CurrentUser ( ) currentUser ) { if ( targetType === 'text' && ! text ) { throw new BadRequestError ( errorCodes . notification . textOnlyWithoutText . text ) ; } const { course , lecture , unit } = targetType === 'text' ? { course : undefined , lecture : undefined , unit : undefined } : await NotificationController . resolveTarget ( targetId , targetType , currentUser ) ; const user = await User . findById ( userId ) . orFail ( new NotFoundError ( errorCodes . notification . targetUserNotFound . text ) ) ; if ( await this . shouldCreateNotification ( user , course , unit ) ) { await this . createNotification ( user , text , course , lecture , unit ) ; } return { } ; } async shouldCreateNotification ( user , changedCourse , changedUnit ? ) { if ( ! changedCourse && ! changedUnit ) { return true ; } if ( ! changedUnit ) { return ! ( await Notification . findOne ( { user , changedCourse } ) ) ; } return ! ( await Notification . findOne ( { user , changedUnit } ) ) ; } async createNotification ( user , text , changedCourse ? , changedLecture ? , changedUnit ? ) { if ( changedCourse && ! changedCourse . active ) { return ; } if ( changedUnit && ! changedUnit . visible ) { return ; } const notification = new Notification ( ) ; notification . user = user ; notification . text = text ; notification . isOld = false ; if ( changedCourse ) { notification . changedCourse = changedCourse ; const settings = await this . getOrCreateSettings ( user , changedCourse ) ; if ( settings . notificationType === API_NOTIFICATION_TYPE_ALL_CHANGES ) { if ( changedLecture ) { notification . changedLecture = changedLecture ; } if ( changedUnit ) { notification . changedUnit = changedUnit ; } if ( settings . emailNotification ) { await this . sendNotificationMail ( user , 'you received new notifications for the course ' + changedCourse . name + '.' ) ; } } } return await notification . save ( ) ; } async getOrCreateSettings ( user , changedCourse ) { let settings = await NotificationSettings . findOne ( { 'user' : user , 'course' : changedCourse } ) ; if ( settings === undefined || settings === null ) { settings = await new NotificationSettings ( { user : user , course : changedCourse , notificationType : API_NOTIFICATION_TYPE_ALL_CHANGES , emailNotification : false } ) . save ( ) ; } return settings ; } async sendNotificationMail ( user , text ) { const message = { } ; user = await User . findById ( user ) ; message . to = user . profile . firstName + ' ' + user . profile . lastName + '<' + user . email + '>' ; message . subject = 'Geli informs: you have new notifications :)' ; message . text = 'Hello ' + user . profile . firstName + ', \n\n' + + text + '\n' + 'Please check your notifications in geli.\n' + 'Your GELI Team.' ; message . html = '<p>Hello ' + user . profile . firstName + ',</p><br>' + '<p>' + text + '<br>Please check your notifications in geli.</p><br>' + '<p>Your GELI Team.</p>' ; await emailService . sendFreeFormMail ( message ) ; } api apiName apiGroup apiPermission apiPermission apiPermission apiSuccess apiSuccessExample @ Authorized ( [ 'student' , 'teacher' , 'admin' ] ) @ Get ( '/' ) async getNotifications ( @ CurrentUser ( ) currentUser ) { const notifications = await Notification . find ( { user : currentUser } ) ; return notifications . map ( notification => notification . forView ( ) ) ; } api apiName apiGroup apiPermission apiPermission apiPermission apiParam apiSuccess apiSuccessExample apiError @ Authorized ( [ 'student' , 'teacher' , 'admin' ] ) @ Delete ( '/:id' ) async deleteNotification ( @ Param ( 'id' ) id , @ CurrentUser ( ) currentUser ) { const notification = await Notification . findOne ( { _id : id , user : currentUser } ) . orFail ( new NotFoundError ( ) ) ; await notification . remove ( ) ; return { } ; } }