Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 'use strict';
- var app = require('../../server/server');
- var constants = require('../../server/constants');
- var Enumerable = require('linq');
- var emailer = require('emailer');
- var templateManager = require('../../server/email-templates/template-manager');
- var watt = require('watt');
- var encryptor = require('encryptor');
- var key = require('../../server/constants').ENCRYPTION_KEY;
- var async = require('async');
- emailer.init(constants.DEFAULT_EMAIL_SENDER, constants.DEFAULT_EMAIL_SENDER_PASSWORD);
- module.exports = function (Meeting) {
- Meeting.on('editNextMeetings', function (data) {
- editNextMeetings(data.editThisAndFollowing, data.diffMeetings, data.currentMeeting, function (err) {
- if (err) console.log(err);
- console.log('editNextMeetings ' + (err ? 'failed' : 'succeeded') + '!!');
- });
- });
- Meeting.on('createNextMeetings', function (data) {
- createNextMeetings(data.currentMeeting, data.datesOfNextMeetings, data.invitees, data.agendaItems, function (err) {
- if (err) console.log(err);
- console.log('createNextMeetings ' + (err ? 'failed' : 'succeeded') + '!!');
- });
- });
- Meeting.on('notifyUser', function (data) {
- app.models.EnvironmentUser.findById(data.envUserId, {
- include: ['user', { environment: 'config' }]
- }, function (err, environmentUser) {
- if (err) {
- console.log('err:', err);
- return;
- }
- if (!environmentUser) {
- console.log('Cannot found EnvironmentUser with ID %d', data.envUserId);
- return;
- }
- const icalToolkit = require('ical-toolkit');
- //Create a builder
- const builder = icalToolkit.createIcsFileBuilder();
- builder.spacers = true; //Add space in ICS file, better human reading. Default: true
- builder.NEWLINE_CHAR = '\r\n'; //Newline char to use.
- builder.throwError = false; //If true throws errors, else returns error when you do .toString() to generate the file contents.
- builder.ignoreTZIDMismatch = true; //If TZID is invalid, ignore or not to ignore!
- builder.calname = 'Yo Cal';
- builder.method = 'CANCEL';
- //Add events
- builder.events.push({
- start: data.meeting.startDate,
- end: data.meeting.endDate,
- transp: 'OPAQUE',
- summary: data.meeting.name,
- uid: data.meeting.idEnvironment + '' + data.meeting.id + '@eboard.com',
- location: data.meeting.location,
- description: 'Meeting details/Détails de la réunion',
- organizer: {
- name: environmentUser.environment().config().allowEditOrganiserNameInCalender ? environmentUser.environment().config().edittedOrganiserName : data.meeting.organiser().user().firstName + ' ' + data.meeting.organiser().user().lastName,
- email: environmentUser.environment().config().mailFrom
- },
- attendees: [{
- name: environmentUser.user().firstName + ' ' + environmentUser.user().lastName,
- email: environmentUser.user().email,
- rsvp: true
- }],
- method: 'CANCEL',
- status: 'CANCELLED'
- });
- //Try to build
- let icsContent = builder.toString();
- if (icsContent instanceof Error)
- icsContent = '';
- const moment = require('moment');
- emailer.init(environmentUser.environment().config().smtpUsername, environmentUser.environment().config().smtpPassword, environmentUser.environment().config().smtpServerAddress);
- const emailContent = `<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">
- <p>Dear Sir/Madam,</p>
- <p><br></p>
- <p>Kindly note that the following meeting has been cancelled: <strong> `+ data.meeting.name + `</strong></p>
- <p><strong>Company: </strong>`+ data.meeting.company().name + `</p>
- <p><strong>Date: </strong>`+ moment(data.meeting.startDate).format('DD MMM YYYY') + `</p>
- <p><strong>Location: </strong>`+ data.meeting.location + `</p>
- <p><br></p>
- <p>We sincerely apologise for any inconvenience caused.</p>
- <p><br></p>
- <p><strong>Best Regards,</strong></p>
- <p>The Support Team</p>
- <p><br></p>
- </td>`;
- templateManager.injectContent(emailContent, function (injectError, response) {
- if (!injectError) {
- const subject = 'Cancel_' + data.meeting.company().name + '_' + data.meeting.name + '_' + moment(data.meeting.startDate).format('DD MMM YYYY');
- emailer.sendEmail({
- from: environmentUser.environment().config().mailFrom,
- to: environmentUser.user().email,
- cc: data.organiser.email,
- subject: subject,
- isHtml: true,
- body: response,
- alternatives: [{
- headers: { 'Content-Transfer-Encoding': '7bit' },
- contentType: 'text/calendar; charset="utf-8"; method=REPLY',
- content: new Buffer(icsContent ? icsContent : '')
- }]
- }, function (errr, mailInfo) {
- app.models.Email.create({
- from: environmentUser.environment().config().mailFrom,
- to: environmentUser.user().email,
- content: response,
- subject: subject,
- idEnvironment: data.meeting.idEnvironment,
- idMeeting: data.meeting.id,
- date: new Date(),
- type: 'MEETING_DELETE'
- }, function (ex, res) { });
- });
- }
- });
- });
- });
- /**
- *
- * @param {Meeting} meeting
- * @param {String} companyName
- * @param {EboardUser} organiser
- * @param {Boolean} showAttendance
- * @param {Number} destId environmentUser ID of the recipient
- * @returns {String}
- */
- function generateMeetingRequestHtml(meeting, companyName, organiser, showAttendance = false, destId = null) {
- const moment = require('moment');
- const content = `<p>Dear Sir/Madam,</p>
- <p><br></p>
- <p>You have been convened to the following meeting:</p>
- <p><strong>Name: </strong>` + meeting.name + `</p>
- <p><strong>Company: </strong>` + companyName + `</p>
- <p><strong>Date: </strong>` + moment(meeting.startDate).format('DD MMM YYYY') + `</p>
- <p><strong>Time: </strong>` + moment(meeting.startDate).format('HH:mm') + `</p>
- <p><strong>Location: </strong>` + meeting.location + `</p>
- <p><br></p>
- <p><strong>Best Regards,</strong></p>
- <p>` + (organiser.lastName + ' ' + organiser.firstName) + `</p>
- <p><br></p>`;
- const attendance = `<p>To book your calendar please accept/decline the invitation above.</p>
- <p><br></p>
- <p>For your attendance to be visible in PRO meeting, please select one of the following:</p>
- <a href="` + constants.HOSTNAME + `add_attendance.html?idMeeting=` + meeting.id + `&idUser=` + destId + `&attending=1" style="background-color:#EB7035;border:1px solid #EB7035;border-radius:3px;color:#ffffff;display:inline-block;font-family:sans-serif;font-size:16px;line-height:44px;text-align:center;text-decoration:none;width:150px;-webkit-text-size-adjust:none;mso-hide:all;">Yes</a>
- <a href="` + constants.HOSTNAME + `add_attendance.html?idMeeting=` + meeting.id + `&idUser=` + destId + `&attending=0" style="margin-left:30px;background-color:#EB7035;border:1px solid #EB7035;border-radius:3px;color:#ffffff;display:inline-block;font-family:sans-serif;font-size:16px;line-height:44px;text-align:center;text-decoration:none;width:150px;-webkit-text-size-adjust:none;mso-hide:all;">No</a>`;
- return showAttendance ? content + attendance : content;
- }
- /**
- *
- * @param {Meeting} meeting
- * @param {String} companyName
- * @param {EboardUser} organiser
- */
- function generateMeetingUpdateHtml(meeting, companyName, organiser) {
- const moment = require('moment');
- const content = `<p>Dear Sir/Madam,</p>
- <p><br></p>
- <p>Kindly note that the details of the meeting <strong>` + meeting.name + `</strong> scheduled for company <strong>` + companyName + `</strong> have been modified to the following:</p>
- <p><strong>Date: </strong>` + moment(meeting.startDate).format('DD MMM YYYY') + `</p>
- <p><strong>Time: </strong>` + moment(meeting.startDate).format('HH:mm') + `</p>
- <p><strong>Location: </strong>` + meeting.location + `</p>
- <p><br></p>
- <p>We sincerely apologise for any inconvenience caused.</p>
- <p><br></p>
- <p><strong>Best Regards,</strong></p>
- <p>` + (organiser.lastName + ' ' + organiser.firstName) + `</p>
- <p><br></p>`;
- return content;
- }
- /**
- *
- * @param {Meeting} meeting
- * @param {String} companyName
- */
- function generateMeetingCancellationHtml(meeting, companyName) {
- const moment = require('moment');
- const content = `<p>Dear Sir/Madam,</p>
- <p><br></p>
- <p>Kindly note that the following meeting has been cancelled: <strong> `+ meeting.name + `</strong></p>
- <p><strong>Company: </strong>` + companyName + `</p>
- <p><strong>Date: </strong>` + moment(meeting.startDate).format('DD MMM YYYY') + `</p>
- <p><strong>Location: </strong>` + meeting.location + `</p>
- <p><br></p>
- <p>We sincerely apologise for any inconvenience caused.</p>
- <p><br></p>
- <p><strong>Best Regards,</strong></p>
- <p>The Support Team</p>
- <p><br></p>`;
- return content;
- }
- /**
- *
- * @param {EnvironmentConfig} config
- * @param {Meeting} meeting
- * @param {EboardUser} organiser
- * @param {Array<EboardUser>} invitees
- * @param {Function(Error, String)} callback
- */
- function generateICSFileV2(config, meeting, organiser, invitees, callback) {
- const icalToolkit = require('ical-toolkit');
- //Create a builder
- const builder = icalToolkit.createIcsFileBuilder();
- /*
- * Settings (All Default values shown below. It is optional to specify)
- * */
- builder.spacers = true; //Add space in ICS file, better human reading. Default: true
- builder.NEWLINE_CHAR = '\r\n'; //Newline char to use.
- builder.throwError = false; //If true throws errors, else returns error when you do .toString() to generate the file contents.
- builder.ignoreTZIDMismatch = true; //If TZID is invalid, ignore or not to ignore!
- /**
- * Build ICS
- * */
- //Name of calander 'X-WR-CALNAME' tag.
- builder.calname = 'Yo Cal';
- //Method
- builder.method = 'REQUEST';
- //Add events
- builder.events.push({
- //Event start time, Required: type Date()
- start: meeting.startDate,
- //Event end time, Required: type Date()
- end: meeting.endDate,
- //transp. Will add TRANSP:OPAQUE to block calendar.
- transp: 'OPAQUE',
- //Event summary, Required: type String
- summary: meeting.name,
- //Event identifier, Optional, default auto generated
- uid: meeting.idEnvironment + '' + meeting.id + '@eboard.com',
- //Location of event, optional.
- location: meeting.location,
- //Optional description of event.
- description: 'Meeting details/Détails de la réunion',
- //Optional Organizer info
- organizer: {
- name: config.allowEditOrganiserNameInCalender ? config.edittedOrganiserName : organiser.firstName + ' ' + organiser.lastName,
- email: config.mailFrom
- },
- attendees: (invitees || []).map(invitee => { return { name: invitee.firstName + ' ' + invitee.lastName, email: invitee.email, rsvp: true }; }),
- //What to do on addition
- method: 'REQUEST'
- });
- //Try to build
- const icsFileContent = builder.toString();
- //Check if there was an error (Only required if yu configured to return error, else error will be thrown.)
- if (icsFileContent instanceof Error) {
- if (callback) callback(icsFileContent);
- return;
- }
- if (callback) callback(null, icsFileContent);
- }
- /**
- *
- * @param {EnvironmentConfig} config
- * @param {Meeting} meeting
- * @param {EboardUser} organiser
- * @param {Array<EboardUser>} invitees
- * @param {Function(Error, String)} callback
- */
- function deleteICSFileV2(config, meeting, organiser, invitees, callback) {
- const icalToolkit = require('ical-toolkit');
- //Create a builder
- const builder = icalToolkit.createIcsFileBuilder();
- /*
- * Settings (All Default values shown below. It is optional to specify)
- * */
- builder.spacers = true; //Add space in ICS file, better human reading. Default: true
- builder.NEWLINE_CHAR = '\r\n'; //Newline char to use.
- builder.throwError = false; //If true throws errors, else returns error when you do .toString() to generate the file contents.
- builder.ignoreTZIDMismatch = true; //If TZID is invalid, ignore or not to ignore!
- /**
- * Build ICS
- * */
- //Name of calander 'X-WR-CALNAME' tag.
- builder.calname = 'Yo Cal';
- //Method
- builder.method = 'CANCEL';
- //Add events
- builder.events.push({
- //Event start time, Required: type Date()
- start: meeting.startDate,
- //Event end time, Required: type Date()
- end: meeting.endDate,
- //transp. Will add TRANSP:OPAQUE to block calendar.
- transp: 'OPAQUE',
- //Event summary, Required: type String
- summary: meeting.name,
- //Event identifier, Optional, default auto generated
- uid: meeting.idEnvironment + '' + meeting.id + '@eboard.com',
- //Location of event, optional.
- location: meeting.location,
- //Optional description of event.
- description: 'Meeting details/Détails de la réunion',
- //Optional Organizer info
- organizer: {
- name: config.allowEditOrganiserNameInCalender ? config.edittedOrganiserName : organiser.firstName + ' ' + organiser.lastName,
- email: config.mailFrom
- },
- attendees: (invitees || []).map(invitee => { return { name: invitee.firstName + ' ' + invitee.lastName, email: invitee.email, rsvp: true }; }),
- //What to do on addition
- method: 'CANCEL',
- //Status of event
- status: 'CANCELLED'
- });
- //Try to build
- const icsFileContent = builder.toString();
- //Check if there was an error (Only required if yu configured to return error, else error will be thrown.)
- if (icsFileContent instanceof Error) {
- if (callback) callback(icsFileContent);
- return;
- }
- if (callback) callback(null, icsFileContent);
- }
- /**
- *
- * @param {EnvironmentConfig} config
- * @param {Meeting} meeting
- * @param {EboardUser} organiser
- * @param {Array<EboardUser>} invitees
- * @param {EboardUser} to
- * @param {String} subject
- * @param {String} emailMessage
- * @param {Function(Error)} callback
- */
- function sendEmailWithIcsFileV2(config, meeting, organiser, invitees, to, subject, emailMessage, callback) {
- const messageHtml = '<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">' + emailMessage + '</td>';
- templateManager.injectContent(messageHtml, function (injectErr, response) {
- if (injectErr) {
- if (callback) callback(injectErr);
- return;
- }
- generateICSFileV2(config, meeting, organiser, invitees, function (err, icsContent) {
- if (err) {
- if (callback) callback(err);
- return;
- }
- const headers = {};
- headers['Content-Transfer-Encoding'] = '7bit';
- let ccEmail = to.ccEmail;
- if (!ccEmail) {
- ccEmail = '';
- } else {
- ccEmail = '; ' + ccEmail;
- }
- // TODO: emailer.init()
- emailer.sendEmail({
- from: config.mailFrom,
- to: to.email + ccEmail,
- subject: subject,
- isHtml: true,
- body: response,
- alternatives: [{
- headers: headers,
- contentType: 'text/calendar; charset="utf-8"; method=REPLY',
- content: new Buffer(icsContent ? icsContent : '')
- }]
- }, function (err) {
- if (err) {
- if (callback) callback(err);
- return;
- }
- if (callback) callback();
- });
- });
- });
- }
- /**
- *
- * @param {EnvironmentConfig} config
- * @param {Meeting} meeting
- * @param {EboardUser} organiser
- * @param {Array<EboardUser>} invitees
- * @param {Array<EboardUser>} to default empty
- * @param {String} subject
- * @param {String} emailMessage
- * @param {Function(Error)} callback
- */
- function sendEmailInBatchWithIcsFileV2(config, meeting, organiser, invitees, to = null, subject, emailMessage, callback) {
- const messageHtml = '<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">' + emailMessage + '</td>';
- templateManager.injectContent(messageHtml, function (injectErr, response) {
- if (injectErr) {
- if (callback) callback(injectErr);
- return;
- }
- generateICSFileV2(config, meeting, organiser, invitees, function (err, icsContent) {
- if (err) {
- if (callback) callback(err);
- return;
- }
- const headers = {};
- headers['Content-Transfer-Encoding'] = '7bit';
- const invList = [];
- const orgList = [];
- orgList.push(organiser.email);
- if (organiser.ccEmail) {
- orgList.push(organiser.ccEmail);
- }
- const recipients = Array.isArray(to) && to.length ? to : invitees;
- for (var invitee of recipients) {
- invList.push(invitee.email);
- if (invitee.ccEmail)
- invList.push(invitee.ccEmail);
- }
- // if (config.allowSendMailToAllOrganiser) {
- // const meetingTypeOrgs = meeting.meetingType().organisers();
- // meetingTypeOrgs = Enumerable.from(meetingTypeOrgs).where(function (mo) {
- // return mo.isActive && mo.eboardUserId != meeting.organiser().eboardUserId;
- // }).toArray();
- // for (var org of meetingTypeOrgs) {
- // orgList.push(org.eboardUser().email);
- // if (org.eboardUser().ccEmail) {
- // orgList.push(org.eboardUser().ccEmail);
- // }
- // }
- // }
- // TODO: emailer.init()
- emailer.sendEmail({
- from: config.mailFrom,
- to: invList,
- subject: subject,
- isHtml: true,
- body: response,
- cc: orgList,
- alternatives: [{
- headers: headers,
- contentType: 'text/calendar; charset="utf-8"; method=REPLY',
- content: new Buffer(icsContent ? icsContent : '')
- }],
- }, function (err) {
- if (err) {
- if (callback) callback(err);
- return;
- }
- if (callback) callback();
- });
- });
- });
- }
- /**
- *
- * @param {EnvironmentConfig} config
- * @param {Meeting} meeting
- * @param {EboardUser} organiser
- * @param {Array<EboardUser>} invitees
- * @param {Array<EboardUser>} meetingTypeOrganisers
- * @param {Array<EboardUser>} to
- * @param {String} subject
- * @param {String} emailMessage
- * @param {Function(Error)} callback
- */
- function sendCancellationEmailWithIcs(config, meeting, organiser, invitees, meetingTypeOrganisers, to, subject, emailMessage, callback) {
- const messageHtml = '<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">' + emailMessage + '</td>';
- const recipients = Array.isArray(to) && to.length ? to : invitees;
- const cc = recipients.map(i => i.email);
- cc = cc.concat(recipients.map(i => i.ccEmail).filter(m => typeof m === 'string' && m.length));
- templateManager.injectContent(messageHtml, function (err, response) {
- if (err/* || !config.deleteMeetingWithNotif*/) {
- if (callback) callback(err);
- return;
- }
- deleteICSFileV2(config, meeting, organiser, invitees, function (err, icsContent) {
- if (err) {
- if (callback) callback(err);
- return;
- }
- if (config.allowSendMailToAllOrganiser)
- cc = cc.concat(meetingTypeOrganisers.filter(o => cc.indexOf(o.email) === -1).map(o => o.email));
- emailer.init(config.smtpUsername, config.smtpPassword, config.smtpServerAddress);
- const headers = {};
- headers['Content-Transfer-Encoding'] = '7bit';
- emailer.sendEmail({
- from: config.mailFrom,
- to: organiser.email,
- subject: subject,
- isHtml: true,
- body: response,
- cc: cc.filter((v, i, s) => s.indexOf(v) === i),
- alternatives: [{
- headers: headers,
- contentType: 'text/calendar; charset="utf-8"; method=REPLY',
- content: new Buffer(icsContent ? icsContent : '')
- }]
- }, function (err) {
- if (callback) callback(err);
- });
- });
- });
- }
- Meeting.on('notifyNewUserV2', function (data) {
- Meeting.findById(data.meeting.id, {
- include: [
- { environment: 'config' },
- { organiser: 'user' },
- { invitees: { environmentUser: 'user' } },
- { meetingType: { organisers: 'user' } },
- 'company'
- ]
- }, function (err, meeting) {
- if (err || !meeting) return;
- app.models.EnvironmentUser.find({
- where: {
- and: [
- { id: { inq: data.ids } },
- { isActive: true },
- { isDeleted: false }
- ]
- },
- include: 'user'
- }, function (err, environmentUsers) {
- if (err || !environmentUsers) return;
- const moment = require('moment');
- const subject = 'New_' + meeting.company().name + '_' + meeting.name + '_' + moment(meeting.startDate).format('DD MMM YYYY');
- if (meeting.environment().config().showAttendance) {
- async.each(environmentUsers, function (environmentUser, callback) {
- app.models.MeetingAttendance.findOrCreate({
- idMeeting: meeting.id,
- idEnvironmentUser: environmentUser.id
- }, function (err) {
- if (err) return callback(err);
- const emailMessage = generateMeetingRequestHtml(meeting, meeting.company().name, meeting.organiser().user(), true, environmentUser.id);
- sendEmailWithIcsFileV2(
- meeting.environment().config(), meeting, meeting.organiser().user(),
- meeting.invitees().map(invitee => invitee.environmentUser().user()),
- environmentUser.user(), subject, emailMessage, callback
- );
- });
- }, function (err) {
- if (err) console.log('sendEmailWithIcsFileV2:', err);
- });
- } else { // Batch
- const emailMessage = generateMeetingRequestHtml(meeting, meeting.company().name, meeting.organiser().user());
- sendEmailInBatchWithIcsFileV2(
- meeting.environment().config(), meeting, meeting.organiser().user(),
- meeting.invitees().map(invitee => invitee.environmentUser().user()),
- environmentUsers.map(environmentUser => environmentUser.user()), subject,
- emailMessage, function (err) { if (err) console.log('sendEmailInBatchWithIcsFileV2:', err); }
- );
- }
- // if (updateState) {
- // TODO: Update state if new meeting (MEETING_CREATED)
- // }
- });
- });
- });
- function generateICSFile(aMeeting, cb) {
- var icalToolkit = require('ical-toolkit');
- app.models.Environment.findById(aMeeting.idEnvironment, {
- include: ['config']
- }, function (errorEnv, currentEnv) {
- if (errorEnv) {
- if (cb) {
- cb(errorEnv);
- }
- } else {
- //Create a builder
- var builder = icalToolkit.createIcsFileBuilder();
- /*
- * Settings (All Default values shown below. It is optional to specify)
- * */
- builder.spacers = true; //Add space in ICS file, better human reading. Default: true
- builder.NEWLINE_CHAR = '\r\n'; //Newline char to use.
- builder.throwError = false; //If true throws errors, else returns error when you do .toString() to generate the file contents.
- builder.ignoreTZIDMismatch = true; //If TZID is invalid, ignore or not to ignore!
- /**
- * Build ICS
- * */
- //Name of calander 'X-WR-CALNAME' tag.
- builder.calname = 'Yo Cal';
- //Cal timezone 'X-WR-TIMEZONE' tag. Optional. We recommend it to be same as tzid.
- //builder.timezone = 'america/new_york';
- //Time Zone ID. This will automatically add VTIMEZONE info.
- //builder.tzid = 'america/new_york';
- //Method
- builder.method = 'REQUEST';
- // var sequenceNumber = aMeeting.startDate.getDate() + '' + aMeeting.startDate.getHours() + '' + aMeeting.startDate.getSeconds();
- //var sequenceNumber = 150;
- var allInvitees = aMeeting.invitees() || [];
- var attendees = [];
- for (var invitee of allInvitees) {
- attendees.push({
- name: invitee.environmentUser().eboardUser().firstName + " " + invitee.environmentUser().eboardUser().lastName,
- email: invitee.environmentUser().eboardUser().email,
- rsvp: true
- });
- }
- //Add events
- builder.events.push({
- //Event start time, Required: type Date()
- start: aMeeting.startDate,
- //Event end time, Required: type Date()
- end: aMeeting.endDate,
- //transp. Will add TRANSP:OPAQUE to block calendar.
- transp: 'OPAQUE',
- //Event summary, Required: type String
- summary: aMeeting.name,
- //All Optionals Below
- //sequence: sequenceNumber,
- //Alarms, array in minutes
- //alarms: [15, 10, 5],
- //Event identifier, Optional, default auto generated
- uid: aMeeting.idEnvironment + "" + aMeeting.id + "@eboard.com",
- //Location of event, optional.
- location: aMeeting.location,
- //Optional description of event.
- description: 'Meeting details/Détails de la réunion',
- //Optional Organizer info
- organizer: {
- name: currentEnv.config().allowEditOrganiserNameInCalender ? currentEnv.config().edittedOrganiserName : aMeeting.organiser().eboardUser().firstName + " " + aMeeting.organiser().eboardUser().lastName,
- //if the sender and receiver have same email like oragniser, add to calendar will not be displayed
- //use a hardcoded unique email as a work around
- email: currentEnv.config().mailFrom // 'promeeting@agileum.com' //'someone@agileum.com' //aMeeting.organiser().eboardUser().email
- // sentBy: 'person_acting_on_behalf_of_organizer@email.com' //OPTIONAL email address of the person who is acting on behalf of organizer.
- },
- attendees: attendees,
- //What to do on addition
- method: 'REQUEST',
- //Status of event
- // status: 'CONFIRMED',
- //Url for event on core application, Optional.
- // url: 'http://yahoo.com'
- });
- //Try to build
- var icsFileContent = builder.toString();
- //Check if there was an error (Only required if yu configured to return error, else error will be thrown.)
- if (icsFileContent instanceof Error) {
- console.log('Returned Error, you can also configure to throw errors!');
- //handle error
- cb(null);
- }
- /*
- //Here is the ics file content.
- // console.log(icsFileContent);
- icsFileContent = `BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Schedule a meeting
- METHOD:REQUEST
- BEGIN:VEVENT
- DTSTART:20160429T060000Z
- DTSTAMP:20160427T125420Z
- DTEND:20160429T073000Z
- LOCATION:1st floor, The factory building, Vivea Business Park, Moka, St Pierre
- DESCRIPTION:Meeting details/Détails de la réunion
- SUMMARY:Ford Committee meeting
- ORGANIZER;CN=Kavida Pillai:mailto:kavida.pillai@agileum.com
- ATTENDEE;CN=Kav Collins;RSVP=TRUE:mailto:kavida15@hotmail.com
- CLASS:PUBLIC
- UID:12
- SEQUENCE:1
- PRIORITY:5
- END:VEVENT
- END:VCALENDAR`;
- icsFileContent = `BEGIN:VCALENDAR
- VERSION:2.0
- PRODID:-//Schedule a meeting
- METHOD:REQUEST
- BEGIN:VEVENT
- DTSTART:20160429T060000Z
- DTSTAMP:20160427T125420Z
- DTEND:20160429T073000Z
- LOCATION:1st floor, The factory building, Vivea Business Park, Moka, St Pierre
- DESCRIPTION:Meeting details/Détails de la réunion
- SUMMARY:Ford Committee (without chairman) 1
- ORGANIZER;CN=Kavida Pillai:mailto:kavida.pillai@agileum.com
- ATTENDEE;CN=Kav Collins;RSVP=TRUE:mailto:kavida15@hotmail.com
- CLASS:PUBLIC
- UID:29
- SEQUENCE:229
- PRIORITY:5
- END:VEVENT
- END:VCALENDAR
- `;
- */
- return cb(icsFileContent);
- /*
- var fs = require('fs');
- var path = require('path');
- var dest = path.resolve(__dirname, '../../server/storage/tmp/');
- //remove special characters
- var removeDiacritics = require('diacritics').remove;
- var meetingName = removeDiacritics(aMeeting.name);
- meetingName = meetingName.replace(/\s+/g, '_').toLowerCase();
- meetingName = meetingName.replace('%20', '_');
- var filePath = path.join(dest, meetingName.trim() + ".ics");
- fs.writeFileSync(filePath, icsFileContent);
- cb(filePath);
- */
- }
- });
- }
- function sendEmailWithIcsFile(envUser, subject, emailMessage, meeting, shouldInjectAttendance, cb) {
- var receiverUserId = envUser.id;
- var os = require("os");
- var portNumber = app.get('port');
- /*---------*/
- var baseUrl = app.get('url').replace(/\/$/, '');
- // console.log(baseUrl + ':' + portNumber + "/");
- var networkInterfaces = os.networkInterfaces();
- // console.log(networkInterfaces);
- /*---------*/
- //change ip when on test
- //"http://" + os.hostname() + ":" + portNumber + "/";
- var hostName = "https://www.promeeting-agileum.com:8443/";
- // To book your calendar please accept/decline the invitation above.
- // For your attendance to be visible in PRO meeting, please select one of the following:
- var attendanceDiv = '<p>To book your calendar please accept/decline the invitation above.</p>' +
- '<p><br></p>' +
- '<p>For your attendance to be visible in PRO meeting, please select one of the following:</p>' +
- '<a href="' + hostName + 'add_attendance.html?idMeeting=' + meeting.id + '&idUser=' + receiverUserId + '&attending=1" style="background-color:#EB7035;border:1px solid #EB7035;border-radius:3px;color:#ffffff;display:inline-block;font-family:sans-serif;font-size:16px;line-height:44px;text-align:center;text-decoration:none;width:150px;-webkit-text-size-adjust:none;mso-hide:all;">Yes</a>' + ' ' +
- '<a href="' + hostName + 'add_attendance.html?idMeeting=' + meeting.id + '&idUser=' + receiverUserId + '&attending=0" style="margin-left:30px;background-color:#EB7035;border:1px solid #EB7035;border-radius:3px;color:#ffffff;display:inline-block;font-family:sans-serif;font-size:16px;line-height:44px;text-align:center;text-decoration:none;width:150px;-webkit-text-size-adjust:none;mso-hide:all;">No</a>';
- var emailMessageHtml = '<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">' + emailMessage + (shouldInjectAttendance ? attendanceDiv : '') + '</td>';
- templateManager.injectContent(emailMessageHtml, function (injectErr, response) {
- if (injectErr) {
- console.log(injectErr);
- if (cb) {
- cb(injectErr);
- }
- return;
- }
- generateICSFile(meeting, function (icsContent) {
- // console.log(icsContent);
- app.models.Environment.findById(meeting.idEnvironment, {
- include: ['config']
- }, function (errorEnv, currentEnv) {
- if (errorEnv) {
- if (cb) {
- cb(errorEnv);
- }
- } else {
- //emailer.init(currentEnv.config().smtpUsername, currentEnv.config().smtpPassword, currentEnv.config().smtpServerAddress);
- var headers = {};
- headers['Content-Transfer-Encoding'] = '7bit';
- var ccEmail = envUser.eboardUser().ccEmail;
- if (ccEmail === null) {
- ccEmail = '';
- } else {
- ccEmail = '; ' + ccEmail;
- }
- console.log('From: ' + currentEnv.config().mailFrom);
- emailer.sendEmail({
- from: currentEnv.config().mailFrom,
- to: envUser.eboardUser().email + ccEmail,
- subject: subject,
- isHtml: true,
- body: response,
- //cc: ccEmail,
- alternatives: [{
- headers: headers,
- contentType: 'text/calendar; charset="utf-8"; method=REPLY',
- content: new Buffer(icsContent ? icsContent : '')
- }],
- //attachments: [icsPath]
- }, function (err, mailInfo) {
- /*app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: envUser.eboardUser().email,
- content: response,
- idEnvironment: currentEnv.id,
- idMeeting: meeting.id,
- subject: subject,
- date: new Date(),
- type: 'MEETING_PUBLISH'
- }, function (ex, res) {});*/
- if (err) {
- console.log(err);
- if (cb)
- return cb(err);
- }
- // console.log(mailInfo);
- if (cb)
- cb();
- });
- }
- });
- });
- });
- }
- Meeting.getAllMeetings = function (data, cb) {
- Meeting.find({
- order: 'name ASC',
- include: ['meetingType', {
- attendance: 'environmentUser'
- }, {
- organiser: ['eboardUser']
- }, {
- agendaItems: [{
- documents: ['file', {
- votes: [{
- environmentUser: ['eboardUser']
- }]
- }]
- }]
- }, {
- company: ['users', 'companyLogo', {
- meetingTypes: ['company', {
- users: ['permission', {
- role: 'permission'
- }, {
- environmentUser: 'eboardUser'
- }]
- }, {
- organisers: ['eboardUser']
- }]
- }]
- }, {
- invitees: ['permission', {
- role: 'permission'
- }, {
- environmentUser: ['eboardUser', 'profilePicture', 'role']
- }]
- }],
- where: {
- and: [{
- isDeleted: false
- }, {
- idEnvironment: data.idEnvironment
- }]
- }
- }, function (error, meetings) {
- if (error) {
- return cb(error);
- } else {
- app.models.EnvironmentUser.findOne({
- include: 'role',
- where: {
- and: [{
- eboardUserId: data.idUser
- }, {
- environmentId: data.idEnvironment
- }, {
- isDeleted: false
- }]
- }
- }, function (err, myself) {
- if (err) {
- return cb(err, null);
- }
- var currentUserId = myself.id;
- var amIMeetingOrganiser = myself.role().name.toLowerCase() == constants.MEETING_ORGANISER;
- if (amIMeetingOrganiser) {
- //if MO manages any of the meeting company
- var meetingsInCompaniesIManage = Enumerable.from(meetings)
- .where(function (m) {
- return Enumerable.from(m.company().users())
- .where(function (u) {
- return u.id == currentUserId;
- })
- .firstOrDefault(null) !== null;
- })
- .toArray();
- //find all the meeting types MO manages
- var mTypeIds = Enumerable.from(meetingsInCompaniesIManage)
- .select(function (m) {
- return m.idMeetingType;
- })
- .toArray();
- var whereFilter = {
- include: [
- 'organisers'
- ],
- where: {
- or: []
- }
- };
- for (var i = 0; i < mTypeIds.length; i++) {
- whereFilter.where.or.push({
- id: mTypeIds[i]
- });
- }
- app.models.MeetingType.find(whereFilter, function (anError, meetingTypes) {
- var meetingTypesIdsIManage = Enumerable.from(meetingTypes)
- .where(function (mt) {
- return Enumerable.from(mt.organisers())
- .where(function (o) {
- return o.id == currentUserId;
- })
- .firstOrDefault(null) !== null;
- }).select(function (m) {
- return m.id;
- })
- .toArray();
- var myMeetings = [];
- for (var aMeet of meetingsInCompaniesIManage) {
- var isMyMeeting = Enumerable.from(meetingTypesIdsIManage)
- .where(function (mTId) {
- return aMeet.idMeetingType == mTId;
- })
- .firstOrDefault(null) !== null;
- if (isMyMeeting) {
- myMeetings.push(aMeet);
- }
- }
- var resultsForOrganiser = data.showMeetingOver ? (Enumerable.from(myMeetings).where(function (m) {
- return m.state == "MEETING_OVER";
- }).toArray()) : (Enumerable.from(myMeetings).where(function (m) {
- return m.state != "MEETING_OVER";
- }).toArray());
- for (var meet of resultsForOrganiser) {
- meet.information = encryptor.decryptText(meet.information, key);
- meet.decisionTaken = encryptor.decryptText(meet.decisionTaken, key);
- }
- return cb(null, resultsForOrganiser);
- });
- } else {
- //if user is invited in meeting
- var amIDirector = myself.role().name.toLowerCase() == constants.USER;
- app.models.Environment.findById(data.idEnvironment, {
- include: ['config']
- }, function (errorEnv, currentEnv) {
- if (errorEnv) {
- if (cb) {
- cb(errorEnv);
- }
- } else {
- if (amIDirector) {
- var meetingsImInvitedTo = Enumerable.from(meetings)
- .where(function (m) {
- return Enumerable.from(m.invitees())
- .where(function (i) {
- return i.idEnvironmentUser == currentUserId;
- })
- .firstOrDefault(null) !== null;
- })
- .toArray();
- var showUnpublishedMeetings = !currentEnv.config().viewPublishedMeeting || false;
- var meetingState = (showUnpublishedMeetings ? ("MEETING_CREATED" || "MEETING_PUBLISHED") : ("MEETING_PUBLISHED"));
- var results = data.showMeetingOver ? (Enumerable.from(meetingsImInvitedTo).where(function (m) {
- return m.state == "MEETING_OVER";
- }).toArray()) : (Enumerable.from(meetingsImInvitedTo).where(function (m) {
- return (m.state == meetingState || m.state == "MEETING_UPDATED" || m.state == "MEETING_PUBLISHED");
- }).toArray());
- /*var showUnpublishedMeetings = !currentEnv.config().viewPublishedMeeting || false;
- var filteredResults = Enumerable.from(results).where(function(m) {
- return m.state == (showUnpublishedMeetings ? ("MEETING_CREATED" || "MEETING_PUBLISHED") : "MEETING_PUBLISHED");
- }).toArray();*/
- for (var meet of results) {
- meet.information = encryptor.decryptText(meet.information, key);
- meet.decisionTaken = encryptor.decryptText(meet.decisionTaken, key);
- }
- return cb(null, results);
- } else {
- //SU OR Admin
- var resultsForAdmin = data.showMeetingOver ? (Enumerable.from(meetings).where(function (m) {
- return m.state == "MEETING_OVER";
- }).toArray()) : (Enumerable.from(meetings).where(function (m) {
- return m.state != "MEETING_OVER";
- }).toArray());
- for (var meetig of resultsForAdmin) {
- meetig.information = encryptor.decryptText(meetig.information, key);
- meetig.decisionTaken = encryptor.decryptText(meetig.decisionTaken, key);
- }
- return cb(null, resultsForAdmin);
- }
- }
- });
- }
- });
- }
- });
- };
- Meeting.remoteMethod('getAllMeetings', {
- accepts: {
- arg: 'data',
- type: 'object',
- http: {
- source: 'body'
- }
- },
- returns: {
- root: true,
- arg: '',
- type: 'Meeting'
- },
- http: {
- path: '/getAllMeetings',
- verb: 'post'
- }
- });
- Meeting.beforeRemote('getAllMeetingsV2', function (ctx, unused, cb) {
- if (!ctx.args.data['idEnvironment'])
- return cb(new Error('idEnvironment is missing'));
- if (!ctx.args.data['idUser'])
- return cb(new Error('idUser is missing'));
- app.models.EnvironmentUser.findOne({
- include: 'role',
- where: {
- and: [{
- eboardUserId: ctx.args.data['idUser']
- },
- {
- environmentId: ctx.args.data['idEnvironment']
- },
- {
- isDeleted: false
- },
- {
- isActive: true
- }
- ]
- }
- }, function (err, user) {
- if (err)
- return cb(err);
- if (!user)
- return cb('user not found');
- ctx.args.data['userId'] = user.id;
- ctx.args.data['userRole'] = user.role().name.toLowerCase();
- cb();
- });
- });
- Meeting.getAllMeetingsV2 = function (data, cb) {
- const filter = {
- skip: 0,
- limit: 50,
- order: 'startDate ASC',
- include: [
- 'meetingType',
- {
- attendance: 'environmentUser'
- },
- {
- organiser: ['eboardUser']
- },
- {
- agendaItems: [{
- documents: [
- 'file',
- {
- votes: [{
- environmentUser: ['eboardUser']
- }]
- }
- ]
- }]
- },
- {
- company: [
- 'users',
- 'companyLogo',
- {
- meetingTypes: [
- 'company',
- {
- users: [
- 'permission',
- {
- role: 'permission'
- },
- {
- environmentUser: 'eboardUser'
- }
- ]
- },
- {
- organisers: ['eboardUser']
- }
- ]
- }
- ]
- },
- {
- invitees: [
- 'permission',
- {
- role: 'permission'
- },
- {
- environmentUser: [
- 'eboardUser',
- 'profilePicture',
- 'role'
- ]
- }
- ]
- }
- ]
- };
- if (data.perPage > 0)
- filter.limit = data.perPage;
- if (data.page > 0)
- filter.skip = (data.page - 1) * filter.limit;
- if (data.orderBy)
- filter.order = data.orderBy;
- switch (data.userRole) {
- case constants.MEETING_ORGANISER: // Meeting Organizer
- let query = `SELECT DISTINCT meeting.id FROM meeting
- INNER JOIN companyuser ON meeting.idcompany = companyuser.companyid
- INNER JOIN meetingtype ON meeting.idmeetingtype = meetingtype.id
- INNER JOIN meetingtypeorganiser ON meetingtype.id = meetingtypeorganiser.meetingtypeid
- WHERE meeting.idenvironment = ` + data.idEnvironment + `
- AND companyuser.environmentuserid = ` + data.userId + `
- AND meetingtypeorganiser.environmentuserid = ` + data.userId + `
- AND meeting.isdeleted = FALSE
- AND companyuser.isdeleted = FALSE
- AND meetingtype.isdeleted = FALSE
- AND meetingtypeorganiser.isdeleted = FALSE`;
- if (data.showMeetingOver)
- query += " AND meeting.state = 'MEETING_OVER'";
- else
- query += " AND meeting.state != 'MEETING_OVER'";
- if (data.startDate) {
- if (isValidDate(new Date(data.startDate)))
- query += " AND meeting.startdate >= timestamp '" + data.startDate.substring(0, 10) + " " + data.startDate.substring(11) + "'";
- }
- if (data.endDate) {
- if (isValidDate(new Date(data.endDate)))
- query += " AND meeting.startdate <= timestamp '" + data.endDate.substring(0, 10) + " " + data.endDate.substring(11) + "'";
- }
- app.datasources.eboardDatasource.connector.execute(query, function (err, arr) {
- if (err)
- return cb(err);
- const meetingIds = arr.map(function (v) {
- return v.id;
- });
- filter.where = {
- id: {
- inq: meetingIds
- }
- };
- const count = meetingIds.length;
- Meeting.find(filter, function (error, meetings) {
- if (error)
- return cb(error);
- const result = {
- pagination: {
- page: (filter.skip / filter.limit) + 1,
- pageSize: filter.limit,
- totalPages: Math.ceil(count / filter.limit),
- totalItems: count
- },
- items: meetings
- };
- for (var meeting of result.items) {
- meeting.information = encryptor.decryptText(meeting.information, key)
- meeting.decisionTaken = encryptor.decryptText(meeting.decisionTaken, key)
- }
- cb(null, result);
- });
- });
- break;
- case constants.USER: // Director
- app.models.Environment.findById(data.idEnvironment, {
- // fields
- include: ['config']
- }, function (errorEnv, currentEnv) {
- if (errorEnv)
- return cb(errorEnv);
- let query = `SELECT DISTINCT meeting.id FROM meeting
- INNER JOIN meetinginvitee ON meetinginvitee.idmeeting = meeting.id
- WHERE meeting.idenvironment = ` + data.idEnvironment + `
- AND meetinginvitee.idenvironmentuser = ` + data.userId + `
- AND meeting.isdeleted = FALSE
- AND meetinginvitee.isdeleted = FALSE`;
- if (data.showMeetingOver)
- query += " AND meeting.state = 'MEETING_OVER'";
- else {
- if (currentEnv.config().viewPublishedMeeting)
- query += " AND meeting.state IN ('MEETING_PUBLISHED', 'MEETING_UPDATED')";
- else
- query += " AND meeting.state IN ('MEETING_CREATED', 'MEETING_PUBLISHED', 'MEETING_UPDATED')";
- }
- if (data.startDate) {
- if (isValidDate(new Date(data.startDate)))
- query += " AND meeting.startdate >= timestamp '" + data.startDate.substring(0, 10) + " " + data.startDate.substring(11) + "'";
- }
- if (data.endDate) {
- if (isValidDate(new Date(data.endDate)))
- query += " AND meeting.startdate <= timestamp '" + data.endDate.substring(0, 10) + " " + data.endDate.substring(11) + "'";
- }
- app.datasources.eboardDatasource.connector.execute(query, function (err, arr) {
- if (err)
- return cb(err);
- const meetingIds = arr.map(function (v) {
- return v.id;
- });
- filter.where = {
- id: {
- inq: meetingIds
- }
- };
- const count = meetingIds.length;
- Meeting.find(filter, function (error, meetings) {
- if (error)
- return cb(error);
- const result = {
- pagination: {
- page: (filter.skip / filter.limit) + 1,
- pageSize: filter.limit,
- totalPages: Math.ceil(count / filter.limit),
- totalItems: count
- },
- items: meetings
- };
- for (var meeting of result.items) {
- meeting.information = encryptor.decryptText(meeting.information, key)
- meeting.decisionTaken = encryptor.decryptText(meeting.decisionTaken, key)
- }
- cb(null, result);
- });
- });
- });
- break;
- default: // SU OR Admin
- filter.where = {
- and: [{
- idEnvironment: data.idEnvironment
- },
- {
- isDeleted: false
- }
- ]
- };
- filter.where.and.push(data.showMeetingOver ? {
- state: 'MEETING_OVER'
- } : {
- state: {
- neq: 'MEETING_OVER'
- }
- });
- if (data.startDate) {
- const startDate = new Date(data.startDate);
- if (isValidDate(startDate))
- filter.where.and.push({
- startDate: {
- gte: startDate
- }
- });
- }
- if (data.endDate) {
- const endDate = new Date(data.endDate);
- if (isValidDate(endDate))
- filter.where.and.push({
- startDate: {
- lte: endDate
- }
- });
- }
- Meeting.count(filter.where, function (err, count) {
- if (err)
- return cb(err);
- Meeting.find(filter, function (error, meetings) {
- if (error)
- return cb(error);
- const result = {
- pagination: {
- page: (filter.skip / filter.limit) + 1,
- pageSize: filter.limit,
- totalPages: Math.ceil(count / filter.limit),
- totalItems: count
- },
- items: meetings
- };
- for (var meeting of result.items) {
- meeting.information = encryptor.decryptText(meeting.information, key)
- meeting.decisionTaken = encryptor.decryptText(meeting.decisionTaken, key)
- }
- cb(null, result);
- });
- });
- }
- }
- Meeting.remoteMethod('getAllMeetingsV2', {
- accepts: {
- arg: 'data',
- type: 'object',
- http: {
- source: 'body'
- }
- },
- returns: {
- root: true,
- arg: '',
- type: 'object'
- },
- http: {
- path: '/getAllMeetingsV2',
- verb: 'post'
- }
- });
- function isValidDate(d) {
- if (Object.prototype.toString.call(d) === "[object Date]") {
- if (isNaN(d.getTime())) // d.valueOf() could also work
- return false;
- return true;
- }
- return false;
- }
- /**
- *
- * @param {String} rule
- * @returns {Object}
- */
- function parseRecurringPattern(rule) {
- const pattern = {};
- rule.split(';').forEach(v => {
- const parts = v.split('=');
- pattern[parts[0]] = parts[1];
- });
- return pattern;
- }
- /**
- *
- * @param {Number} nth 1-4 for 1st, 2nd, 3rd or 4th weekday of the month
- * @param {Number} day 0-6 for Sunday to Saturday
- * @param {Date} date
- * @returns {Date|Boolean} false if there isn't an nth weekday
- */
- function getMonthlyWeekday(nth, day, date) {
- const moment = require('moment');
- let a = moment(date).date(1); // 1st day of month
- const b = moment(a).add(1, 'months').subtract(1, 'days'); // last day of month
- let count = 0;
- while (a.toDate().getTime() <= b.toDate().getTime()) {
- if (a.day() === day && ++count === nth)
- return a.toDate();
- a.add(1, 'days');
- }
- return false;
- }
- /**
- *
- * @param {Date} start
- * @param {Date} until
- * @returns {Array<Date>}
- */
- function daily(start, until) {
- const moment = require('moment');
- const next = [];
- let a = moment(start).add(1, 'days');
- while (a.toDate().getTime() <= until.getTime()) {
- next.push(a.toDate());
- a.add(1, 'days');
- }
- return next;
- }
- /**
- *
- * @param {Date} start
- * @param {Array<Number>} weekdays 0-6 for Sunday to Saturday
- * @param {Date} until
- * @param {Number} interval default 1
- * @returns {Array<Date>}
- */
- function weekly(start, weekdays = [], until, interval = 1) {
- const moment = require('moment');
- const next = [];
- let a = moment(start);
- for (var i = 0; i < weekdays.length; i++) {
- if (weekdays[i] > a.day() && a.day(weekdays[i]).toDate().getTime() <= until.getTime())
- next.push(a.toDate());
- }
- a.add(interval, 'weeks');
- while (a.toDate().getTime() <= until.getTime()) {
- for (var i = 0; i < weekdays.length; i++) {
- if (a.day(weekdays[i]).toDate().getTime() <= until.getTime())
- next.push(a.toDate());
- }
- a.add(interval, 'weeks');
- }
- return next;
- }
- /**
- *
- * @param {Date} start
- * @param {Number} nth 1-4 for 1st, 2nd, 3rd or 4th weekday of the month
- * @param {Array<Number>} weekdays 0-6 for Sunday to Saturday
- * @param {Number} monthday 1-31
- * @param {Date} until
- * @returns {Array<Date>}
- */
- function monthly(start, nth = null, weekdays = null, monthday = null, until) {
- const moment = require('moment');
- const next = [];
- let a = moment(start);
- if (nth && Array.isArray(weekdays)) {
- for (var i = 0; i < weekdays.length; i++) {
- const mwd = moment(getMonthlyWeekday(nth, weekdays[i], start));
- if (mwd.date() > a.date() && mwd.toDate().getTime() <= until.getTime())
- next.push(mwd.toDate());
- }
- }
- a.add(1, 'months');
- while (a.toDate().getTime() <= until.getTime()) {
- if (monthday) {
- if (a.daysInMonth() >= monthday && a.date(monthday).toDate().getTime() <= until.getTime())
- next.push(a.toDate());
- } else if (Array.isArray(weekdays)) {
- for (var i = 0; i < weekdays.length; i++) {
- const mwd = moment(getMonthlyWeekday(nth, weekdays[i], a.toDate()));
- if (mwd.toDate().getTime() <= until.getTime())
- next.push(mwd.toDate());
- }
- }
- a.add(1, 'months');
- }
- return next;
- }
- /**
- *
- * @param {Date} start
- * @param {Date} until
- * @returns {Array<Date>}
- */
- function yearly(start, until) {
- const moment = require('moment');
- const next = [];
- let a = moment(start).add(1, 'years');
- while (a.toDate().getTime() <= until.getTime()) {
- next.push(a.toDate());
- a.add(1, 'years');
- }
- return next;
- }
- /**
- *
- * @param {String} byday
- * @returns {Array<Number>}
- */
- function parseWeekDays(byday) {
- return byday.split(',').map(d => {
- switch (d) {
- case 'SUN': return 0;
- case 'MON': return 1;
- case 'TUE': return 2;
- case 'WED': return 3;
- case 'THU': return 4;
- case 'FRI': return 5;
- case 'SAT': return 6;
- }
- }).sort((a, b) => a - b);
- }
- /**
- *
- * @param {Meeting} meeting
- * @returns {Array<Date>}
- */
- function generateNextOccurrences(meeting) {
- const moment = require('moment');
- let occurrences = [];
- if (meeting.isRecurring) {
- const pattern = parseRecurringPattern(meeting.recurringPattern);
- switch (pattern['FREQ']) {
- case 'DAILY':
- occurrences = daily(moment(meeting.startDate).toDate(), new Date(pattern['UNTIL']));
- break;
- case 'WEEKLY':
- occurrences = weekly(moment(meeting.startDate).toDate(), parseWeekDays(pattern['BYDAY']), new Date(pattern['UNTIL']), Number(pattern['INTERVAL']));
- break;
- case 'MONTHLY':
- occurrences = monthly(
- moment(meeting.startDate).toDate(),
- pattern['BYSETPOS'] ? Number(pattern['BYSETPOS']) : null,
- pattern['BYDAY'] ? parseWeekDays(pattern['BYDAY']) : null,
- pattern['BYMONTHDAY'] ? Number(pattern['BYMONTHDAY']) : null,
- new Date(pattern['UNTIL'])
- );
- break;
- case 'YEARLY':
- occurrences = yearly(moment(meeting.startDate).toDate(), new Date(pattern['UNTIL']));
- break;
- }
- occurrences.sort((a, b) => a.getTime() - b.getTime());
- }
- return occurrences;
- }
- /**
- *
- * @param {Array<Object>} oldOccurrences
- * @param {Array<Date>} newOccurrences
- * @param {Boolean} dirty default false
- * @returns {Object|Boolean} false if there have been no changes
- */
- function diffOccurrences(oldOccurrences, newOccurrences, dirty = false) {
- const oldOccurrencesISOString = oldOccurrences.map(o => o.startdate.toISOString().substr(0, 10));
- const newOccurrencesISOString = newOccurrences.map(d => d.toISOString().substr(0, 10));
- const toRemove = oldOccurrences.filter(o => newOccurrencesISOString.indexOf(o.startdate.toISOString().substr(0, 10)) === -1); // Some occurrences have been removed
- const toAdd = newOccurrences.filter(d => oldOccurrencesISOString.indexOf(d.toISOString().substr(0, 10)) === -1); // Occurrences have been added
- const toUpdate = dirty ? oldOccurrences.filter(o => toRemove.map(r => r.id).indexOf(o.id) === -1) : []; // Occurrences have been modified
- let diff = false;
- if (toRemove.length || toAdd.length || toUpdate.length) {
- diff = {};
- if (toRemove.length) diff['remove'] = toRemove; // Array<OldOccurrence>
- if (toAdd.length) diff['add'] = toAdd; // Array<Date>
- if (toUpdate.length) diff['update'] = toUpdate; // Array<OldOccurrence>
- }
- return diff;
- }
- /**
- *
- * @param {Meeting} oldMeeting
- * @param {Meeting} newMeeting
- * @returns {Object|Boolean} false if there have been no changes
- */
- function diffMeetings(oldMeeting, newMeeting) {
- const moment = require('moment');
- let diff = false;
- if (!oldMeeting || !newMeeting)
- return diff;
- if (oldMeeting.name !== newMeeting.name)
- diff = { name: newMeeting.name };
- const oldStartDate = moment(oldMeeting.startDate).toDate();
- const newStartDate = moment(newMeeting.startDate).toDate();
- const oldEndDate = moment(oldMeeting.endDate).toDate();
- const newEndDate = moment(newMeeting.endDate).toDate();
- if (oldStartDate.getTime() !== newStartDate.getTime() || oldEndDate.getTime() !== newEndDate.getTime()) {
- if (!diff) diff = {};
- diff['startDate'] = newStartDate;
- diff['endDate'] = newEndDate;
- }
- if (oldMeeting.location !== newMeeting.location) {
- if (!diff) diff = {};
- diff['location'] = newMeeting.location;
- }
- const oldIdOrganiser = oldMeeting.organiser ? (typeof oldMeeting.organiser === 'function' && oldMeeting.organiser().id) || oldMeeting.organiser.id : oldMeeting.idOrganiser;
- const newIdOrganiser = newMeeting.organiser ? (typeof newMeeting.organiser === 'function' && newMeeting.organiser().id) || newMeeting.organiser.id : newMeeting.idOrganiser;
- if (oldIdOrganiser !== newIdOrganiser) {
- if (!diff) diff = {};
- diff['idOrganiser'] = newIdOrganiser;
- }
- const oldAgendaItems = (typeof oldMeeting.agendaItems === 'function' && oldMeeting.agendaItems()) || oldMeeting.agendaItems || [];
- const newAgendaItems = (typeof newMeeting.agendaItems === 'function' && newMeeting.agendaItems()) || newMeeting.agendaItems || [];
- const toRemoveAgendaItems = oldAgendaItems.filter(a => newAgendaItems.map(n => n.id).indexOf(a.id) === -1);
- const toAddAgendaItems = newAgendaItems.filter(a => oldAgendaItems.map(o => o.id).indexOf(a.id) === -1);
- const toUpdateAgendaItems = oldAgendaItems.filter(o => {
- if (toRemoveAgendaItems.map(r => r.id).indexOf(o.id) !== -1)
- return false;
- for (var i = 0; i < newAgendaItems.length; i++) {
- if (newAgendaItems[i].id === o.id && newAgendaItems[i].title !== o.title)
- return true;
- }
- return false;
- }).map(o => {
- const obj = { oldValue: o.title };
- for (var i = 0; i < newAgendaItems.length; i++) {
- if (newAgendaItems[i].id === o.id) {
- obj.newValue = newAgendaItems[i].title;
- break;
- }
- }
- return obj;
- });
- if (toRemoveAgendaItems.length || toAddAgendaItems.length || toUpdateAgendaItems.length) {
- if (!diff) diff = {};
- diff['agendaItems'] = {};
- if (toRemoveAgendaItems.length) diff['agendaItems']['remove'] = toRemoveAgendaItems; // Object | AgendaItem
- if (toAddAgendaItems.length) diff['agendaItems']['add'] = toAddAgendaItems; // Object | AgendaItem
- if (toUpdateAgendaItems.length) diff['agendaItems']['update'] = toUpdateAgendaItems; // Object | AgendaItem
- }
- const oldInvitees = ((typeof oldMeeting.invitees === 'function' && oldMeeting.invitees()) || oldMeeting.invitees || [])
- .concat(oldMeeting.otherInvitees || [])
- .map(o => o.environmentUser ? (typeof o.environmentUser === 'function' && o.environmentUser().id) || o.environmentUser.id : o.idEnvironmentUser)
- .filter(id => !isNaN(Number(id)));
- const newInvitees = ((typeof newMeeting.invitees === 'function' && newMeeting.invitees()) || newMeeting.invitees || [])
- .concat(newMeeting.otherInvitees || [])
- .map(n => n.environmentUser ? (typeof n.environmentUser === 'function' && n.environmentUser().id) || n.environmentUser.id : n.idEnvironmentUser)
- .filter(id => !isNaN(Number(id)));
- const toRemoveInvitees = oldInvitees.filter(o => newInvitees.indexOf(o) === -1);
- const toAddInvitees = newInvitees.filter(n => oldInvitees.indexOf(n) === -1);
- if (toRemoveInvitees.length || toAddInvitees.length) {
- if (!diff) diff = {};
- diff['invitees'] = {};
- if (toRemoveInvitees.length) diff['invitees']['remove'] = toRemoveInvitees; /* environnementUser IDs */
- if (toAddInvitees.length) diff['invitees']['add'] = toAddInvitees; /* environnementUser IDs */
- }
- if (newMeeting.isRecurring !== oldMeeting.isRecurring) {
- if (!diff) diff = {};
- diff['isRecurring'] = { oldValue: oldMeeting.isRecurring, newValue: newMeeting.isRecurring };
- }
- if (newMeeting.recurringPattern !== oldMeeting.recurringPattern) {
- if (!diff) diff = {};
- diff['recurringPattern'] = { oldValue: oldMeeting.recurringPattern, newValue: newMeeting.recurringPattern };
- }
- return diff;
- }
- /**
- *
- * @param {Number} parentId
- * @param {Boolean} inclusive
- * @param {Function} callback
- */
- function nextMeetings(parentId, inclusive = true, callback) {
- const query = `
- WITH RECURSIVE nextmeetings AS (
- SELECT id, parentId, startDate FROM meeting WHERE id = `+ parentId + `
- UNION
- SELECT m.id, m.parentId, m.startDate FROM meeting m INNER JOIN nextmeetings n ON n.id = m.parentId WHERE isDeleted = FALSE
- ) SELECT * FROM nextmeetings`;
- if (!inclusive)
- query += ' WHERE id != ' + parentId;
- app.datasources.eboardDatasource.connector.execute(query, function (err, next) {
- if (err || !next) {
- if (callback) callback(err);
- return;
- }
- next.sort((a, b) => a.startdate.getTime() - b.startdate.getTime());
- if (callback) callback(null, next);
- });
- }
- /**
- *
- * @param {Array<Number>} meetingIds
- * @param {Function} callback
- */
- function buildMeetingTree(meetingIds, callback) {
- if (!Array.isArray(meetingIds) || !meetingIds.length) {
- if (callback) callback(null, false);
- return;
- }
- const query = `
- WITH occurrences AS (
- SELECT id, ROW_NUMBER () OVER (ORDER BY startdate) AS rowno FROM meeting WHERE id IN (`+ meetingIds.filter(id => !!id).join() + `)
- ) UPDATE meeting SET parentid = CASE WHEN o.rowno = 1 THEN NULL ELSE (SELECT id FROM occurrences WHERE rowno = o.rowno - 1) END
- FROM occurrences o WHERE o.id = meeting.id`;
- app.datasources.eboardDatasource.connector.execute(query, function (err) {
- if (callback) callback(err, !!!err);
- });
- }
- /**
- *
- * @param {Meeting} meeting
- * @param {Function} callback
- */
- function cancelMeeting(meeting, callback) {
- const icalToolkit = require('ical-toolkit');
- const moment = require('moment');
- async.each(meeting.invitees(), function (invitee, cb) {
- const builder = icalToolkit.createIcsFileBuilder();
- builder.spacers = true; //Add space in ICS file, better human reading. Default: true
- builder.NEWLINE_CHAR = '\r\n'; //Newline char to use.
- builder.throwError = false; //If true throws errors, else returns error when you do .toString() to generate the file contents.
- builder.ignoreTZIDMismatch = true; //If TZID is invalid, ignore or not to ignore!
- builder.calname = 'Yo Cal';
- builder.method = 'CANCEL';
- builder.events.push({
- start: meeting.startDate,
- end: meeting.endDate,
- transp: 'OPAQUE',
- summary: meeting.name,
- uid: meeting.idEnvironment + '' + meeting.id + '@eboard.com',
- location: meeting.location,
- description: 'Meeting details/Détails de la réunion',
- organizer: {
- name: meeting.environment().config().allowEditOrganiserNameInCalender ? meeting.environment().config().edittedOrganiserName : meeting.organiser().user().firstName + ' ' + meeting.organiser().user().lastName,
- email: meeting.environment().config().mailFrom
- },
- attendees: [{
- name: invitee.environmentUser().user().firstName + ' ' + invitee.environmentUser().user().lastName,
- email: invitee.environmentUser().user().email,
- rsvp: true
- }],
- method: 'CANCEL',
- status: 'CANCELLED'
- });
- let icsContent = builder.toString();
- if (icsContent instanceof Error)
- return cb(icsContent);
- emailer.init(meeting.environment().config().smtpUsername, meeting.environment().config().smtpPassword, meeting.environment().config().smtpServerAddress);
- const emailContent = `<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">
- <p>Dear Sir/Madam,</p>
- <p><br></p>
- <p>Note that the following meeting has been cancelled:</p>
- <p><strong>Name: </strong>`+ meeting.name + `</p>
- <p><strong>Company: </strong>`+ meeting.company().name + `</p>
- <p><strong>Date: </strong>`+ moment(meeting.startDate).format('DD MMM YYYY') + `</p>
- <p><strong>Location: </strong>`+ meeting.location + `</p>
- <p><br></p>
- <p>We sincerely apologise for any inconvenience caused.</p>
- <p><br></p>
- <p><strong>Best Regards,</strong></p>
- <p>The Support Team</p>
- <p><br></p>
- </td>`;
- templateManager.injectContent(emailContent, function (injectError, response) {
- if (injectError) return cb(injectError);
- const subject = 'Cancel_' + meeting.company().name + '_' + meeting.name + '_' + moment(meeting.startDate).format('DD MMM YYYY');
- emailer.sendEmail({
- from: meeting.environment().config().mailFrom,
- to: invitee.environmentUser().user().email,
- subject: subject,
- isHtml: true,
- body: response,
- alternatives: [{
- headers: { 'Content-Transfer-Encoding': '7bit' },
- contentType: 'text/calendar; charset="utf-8"; method=REPLY',
- content: new Buffer(icsContent ? icsContent : '')
- }]
- }, function (errr/*, mailInfo*/) {
- if (errr) return cb(errr);
- app.models.Email.create({
- from: meeting.environment().config().mailFrom,
- to: invitee.environmentUser().user().email,
- content: response,
- subject: subject,
- idEnvironment: meeting.idEnvironment,
- idMeeting: meeting.id,
- date: new Date(),
- type: 'MEETING_DELETE'
- }, cb);
- });
- });
- }, callback);
- }
- /**
- *
- * @param {Array<Number>} ids IDs of meetings
- * @param {Function} callback
- */
- function cancelMeetings(ids, callback) {
- if (!Array.isArray(ids) || !ids.length) {
- if (callback) callback();
- return;
- }
- Meeting.find({
- where: {
- and: [
- { id: { inq: ids } },
- { isDeleted: false }
- ]
- },
- include: [
- { environment: 'config' },
- { organiser: 'user' },
- { invitees: { environmentUser: 'user' } },
- 'company'
- ]
- }, function (err, meetings) {
- if (err || !meetings || !meetings.length) {
- if (callback) callback(err);
- return;
- }
- async.each(meetings, function (meeting, next) {
- meeting.updateAttributes({
- modified: new Date(),
- isDeleted: true
- }, function (err, updatedMeeting) {
- if (err || updatedMeeting.state === constants.MEETING_CREATED || updatedMeeting.state === constants.MEETING_OVER)
- return next(err);
- cancelMeeting(meeting, next);
- });
- }, function (err) {
- if (err) {
- if (callback) callback(err);
- return;
- }
- if (callback) callback(null, meetings.map(m => m.id));
- });
- });
- }
- /**
- *
- * @param {EnvironmentConfig} config
- * @param {EnvironmentUser} environmentUser
- * @param {String} subject
- * @param {String} message
- * @param {Meeting} meeting
- * @param {Boolean} showAttendance
- * @param {Function} callback
- */
- // function sendMeetingUpdateWithIcs(config, environmentUser, subject, message, meeting, showAttendance, callback) {
- // sendEmailWithIcsFile(environmentUser, subject, message, meeting, showAttendance, function (sendErr) {
- // app.models.Email.create({
- // from: config.mailFrom,
- // to: environmentUser.eboardUser().email,
- // content: message,
- // idEnvironment: meeting.idEnvironment,
- // idMeeting: meeting.id,
- // date: new Date(),
- // subject: subject,
- // type: 'MEETING_NOTIFY'
- // }, function (ex) {
- // if (sendErr) {
- // if (callback) callback(sendErr);
- // return;
- // }
- // if (ex) {
- // if (callback) callback(ex);
- // return;
- // }
- // if (callback) callback();
- // });
- // });
- // }
- /**
- *
- * @param {String} subject
- * @param {String} message
- * @param {Meeting} meeting
- * @param {Function} callback
- */
- // function sendBatchMeetingUpdateWithIcs(subject, message, meeting, callback) {
- // sendEmailInBatchWithIcsFile(subject, message, meeting, function (sendErr) {
- // app.models.Email.create({
- // from: meeting.environment().config().mailFrom,
- // to: meeting.organiser().user().email,
- // content: message,
- // idEnvironment: meeting.idEnvironment,
- // idMeeting: meeting.id,
- // subject: subject,
- // date: new Date(),
- // type: 'MEETING_NOTIFY'
- // }, function (ex) {
- // if (sendErr) {
- // if (callback) callback(sendErr);
- // return;
- // }
- // if (ex) {
- // if (callback) callback(ex);
- // return;
- // }
- // if (callback) callback();
- // });
- // });
- // }
- /**
- *
- * @param {Meeting} meeting
- * @param {Function} callback
- */
- // function meetingUpdate(meeting, callback) {
- // const moment = require('moment');
- // const subject = 'Update_' + meeting.company().name + '_' + meeting.name + '_' + moment(meeting.startDate).format('DD MMM YYYY');
- // const sender = meeting.environment().config().allowSendMailToAllOrganiser ?
- // meeting.organiser().user().lastName + ' ' + meeting.organiser().user().firstName :
- // 'The Support Team';
- // const message = `<p>Dear Sir/Madam,</p>
- // <p><br></p>
- // <p>Note that the details of the meeting `+ meeting.name + ` scheduled for company ` + meeting.company().name + ` have been modified to the following:</p>
- // <p><strong>Date: </strong>`+ moment(meeting.startDate).format('DD MMM YYYY') + `</p>
- // <p><strong>Time: </strong>`+ moment(meeting.startDate).format('HH:mm') + `</p>
- // <p><strong>Location: </strong>`+ meeting.location + `</p>
- // <p><br></p>
- // <p>We sincerely apologise for any inconvenience caused.</p>
- // <p><br></p>
- // <p><strong>Best Regards,</strong></p>
- // <p>`+ sender + `</p>
- // <p><br></p>`;
- // emailer.init(meeting.environment().config().smtpUsername, meeting.environment().config().smtpPassword, meeting.environment().config().smtpServerAddress);
- // if (meeting.environment().config().showAttendance) {
- // async.parallel([
- // function (next) { // Notify the organiser
- // sendMeetingUpdateWithIcs(meeting.environment().config(), meeting.organiser(), subject, message, meeting, false, next);
- // },
- // function (next) { // Notify other organisers
- // if (!meeting.environment().config().allowSendMailToAllOrganiser)
- // return next();
- // async.each(meeting.meetingType().organisers().filter(mo => mo.isActive && mo.eboardUserId != meeting.organiser().eboardUserId), function (org, nxt) {
- // sendMeetingUpdateWithIcs(meeting.environment().config(), org, subject, message, meeting, false, nxt);
- // }, next);
- // },
- // function (next) { // Notify each invitee
- // async.each(meeting.invitees(), function (invitee, nxt) {
- // sendMeetingUpdateWithIcs(meeting.environment().config(), invitee.environmentUser(), subject, message, meeting, meeting.environment().config().showAttendance, nxt);
- // }, next);
- // }
- // ], callback);
- // } else {
- // sendBatchMeetingUpdateWithIcs(subject, message, meeting, callback);
- // }
- // }
- /**
- *
- * @param {Meeting} cMeeting current meeting to update containing diff
- * @param {Object} diff
- * @param {Array<Number>} ids ID of meetings to update
- * @param {Function} callback
- */
- function updateMeetings(cMeeting, diff, ids, callback) {
- if (!diff) {
- if (callback) callback();
- return;
- }
- Meeting.find({
- where: {
- and: [
- { id: { inq: ids.filter(id => id !== cMeeting.id) } },
- { isDeleted: false }
- ]
- },
- include: [
- { invitees: 'environmentUser' },
- 'agendaItems'
- ]
- }, function (err, meetings) {
- if (err || !meetings) {
- if (callback) callback(err);
- return;
- }
- async.each(meetings, function (meeting, next) {
- const diffObj = {};
- if (diff.isRecurring)
- diffObj.isRecurring = diff.isRecurring.newValue;
- if (diff.recurringPattern)
- diffObj.recurringPattern = diff.recurringPattern.newValue;
- if (diff.startDate || diff.endDate) {
- diffObj.startDate = new Date(meeting.startDate.toISOString().substr(0, 10) + cMeeting.startDate.toISOString().substr(10));
- diffObj.endDate = new Date(meeting.endDate.toISOString().substr(0, 10) + cMeeting.endDate.toISOString().substr(10));
- }
- if (diff.location)
- diffObj.location = diff.location;
- if (diff.idOrganiser)
- diffObj.idOrganiser = diff.idOrganiser;
- diffObj.state = meeting.state === constants.MEETING_PUBLISHED ? constants.MEETING_UPDATED : meeting.state;
- async.parallel([
- function (cbk) {
- meeting.updateAttributes(diffObj, cbk);
- },
- function (cbk) { // agendaItems
- if (!diff.agendaItems) return cbk();
- async.parallel([
- function (cb) { // remove
- if (!diff.agendaItems.remove || !diff.agendaItems.remove.length)
- return cb();
- const removedAgendaItemIds = meeting.agendaItems().filter(a => diff.agendaItems.remove.map(r => r.title).indexOf(a.title) !== -1).map(a => a.id);
- if (!removedAgendaItemIds.length)
- return cb();
- app.models.AgendaItem.updateAll({
- and: [
- { id: { inq: removedAgendaItemIds } },
- { isDeleted: false }
- ]
- }, { isDeleted: true }, cb);
- },
- function (cb) { // update
- if (!diff.agendaItems.update || !diff.agendaItems.update.length)
- return cb();
- const updatedAgendaItems = meeting.agendaItems().filter(
- a => diff.agendaItems.update.map(u => u.oldValue).indexOf(a.title) !== -1
- ).map(a => {
- const idx = diff.agendaItems.update.map(u => u.oldValue).indexOf(a.title);
- return { id: a.id, title: diff.agendaItems.update[idx].newValue };
- });
- if (!updatedAgendaItems.length)
- return cb();
- async.each(updatedAgendaItems, function (item, nxt) {
- app.models.AgendaItem.replaceById(item.id, { /*idMeeting: meeting.id,*/ title: item.title }, nxt);
- }, cb);
- },
- function (cb) { // add
- if (!diff.agendaItems.add || !diff.agendaItems.add.length)
- return cb();
- const addedAgendaItems = diff.agendaItems.add.map(a => a.title).filter(
- title => meeting.agendaItems().map(a => a.title).indexOf(title) === -1
- && (diff.agendaItems.remove || []).map(r => r.title).indexOf(title) === -1
- && (diff.agendaItems.update || []).map(u => u.newValue).indexOf(title) === -1
- );
- if (!addedAgendaItems.length)
- return cb();
- async.each(addedAgendaItems, function (title, nxt) {
- app.models.AgendaItem.create({ idMeeting: meeting.id, title: title }, nxt);
- }, cb);
- }
- ], cbk);
- },
- function (cbk) { // invitees
- if (!diff.invitees) return cbk();
- async.parallel([
- function (cb) { // remove
- if (!diff.invitees.remove || !diff.invitees.remove.length)
- return cb();
- async.parallel([
- function (nxt) {
- if (meeting.state === constants.MEETING_CREATED || meeting.state === constants.MEETING_OVER)
- return nxt();
- // TODO: Send meeting cancellation
- callback(null, 'one');
- },
- function (nxt) {
- app.models.MeetingInvitee.destroyAll({
- and: [
- { idMeeting: meeting.id },
- { idEnvironmentUser: { inq: diff.invitees.remove } }
- ]
- }, nxt);
- }
- ], cb);
- },
- function (cb) { // add
- if (!diff.invitees.add || !diff.invitees.add.length)
- return cb();
- const existingInvitees = meeting.invitees().map(i => i.environmentUser().id);
- const inviteesToAdd = diff.invitees.add.filter(id => existingInvitees.indexOf(id) === -1);
- if (!inviteesToAdd || !inviteesToAdd.length)
- return cb();
- app.models.EnvironmentUser.find({ // Consider only active users
- fields: { id: true },
- where: {
- and: [
- { id: { inq: inviteesToAdd } },
- { isActive: true },
- { isDeleted: false }
- ]
- }
- }, function (err, activeUsers) {
- if (err || !activeUsers) return cb(err);
- async.each(inviteesToAdd.filter(id => activeUsers.map(u => u.id).indexOf(id) !== -1), function (uid, nxt) {
- const idx = cMeeting.invitees.map(i => i.idEnvironmentUser).indexOf(uid);
- if (idx === -1) return nxt();
- const invitee = cMeeting.invitees[idx];
- if (!invitee.permission) return nxt(); // should be considered as an error
- const permission = invitee.permission;
- delete permission.id;
- app.models.Permission.create(permission, function (err, newPermission) {
- if (err || !newPermission) return nxt(err);
- app.models.MeetingInvitee.create({
- idMeeting: meeting.id,
- idPermission: newPermission.id,
- idMeetingRole: invitee.idMeetingRole,
- idEnvironmentUser: uid
- }, nxt);
- });
- }, cb);
- // TODO: Send meeting request
- });
- }
- ], cbk);
- }
- ], next);
- }, function (err) {
- if (callback)
- callback(err, meetings.map(m => m.id));
- });
- });
- }
- /**
- *
- * @param {Meeting} cMeeting
- * @param {Array<Date>} datesOfNextMeetings
- * @param {Array<MeetingInvitee>} invitees
- * @param {Array<AgendaItem>} agendaItems
- * @param {Function} callback
- */
- function createNextMeetings(cMeeting, datesOfNextMeetings, invitees, agendaItems, callback) {
- if (!Array.isArray(datesOfNextMeetings) || !datesOfNextMeetings.length) {
- if (callback) callback();
- return;
- }
- const moment = require('moment');
- const ids = [];
- const diff = moment(cMeeting.endDate).toDate().getTime() - moment(cMeeting.startDate).toDate().getTime();
- async.eachOfSeries(datesOfNextMeetings, function (startDate, i, next) {
- const meeting = JSON.parse(JSON.stringify(cMeeting));
- delete meeting.id;
- delete meeting.information
- delete meeting.decisionTaken
- meeting.startDate = startDate;
- meeting.endDate = new Date(startDate.getTime() + diff);
- meeting.parentId = i > 0 ? ids[i - 1] : cMeeting.id;
- Meeting.create(meeting, function (err, newMeeting) {
- if (err || !newMeeting) return next(err);
- ids.push(newMeeting.id);
- async.parallel([
- function (nxt) { // save the invitees
- async.each(invitees, function (aNewInvitee, cb) {
- if (!aNewInvitee.permission) return cb(); // should be considered as an error
- var inviteePermission = aNewInvitee.permission;
- delete inviteePermission.id;
- app.models.Permission.create(inviteePermission, function (err, newInviteePermission) {
- if (err || !newInviteePermission) return cb(err);
- app.models.MeetingInvitee.create({
- idMeeting: newMeeting.id,
- idPermission: newInviteePermission.id,
- idMeetingRole: aNewInvitee.idMeetingRole,
- idEnvironmentUser: aNewInvitee.idEnvironmentUser
- }, cb);
- });
- }, nxt);
- },
- function (nxt) { // save the agenda items
- if (!Array.isArray(agendaItems) || !agendaItems.length)
- return nxt();
- async.each(agendaItems, function (item, cb) {
- delete item.id;
- item.idMeeting = newMeeting.id;
- app.models.AgendaItem.create(item, cb);
- }, nxt);
- }
- ], next);
- });
- }, function (err) {
- if (callback) callback(err, ids);
- });
- }
- /**
- *
- * @param {Boolean} editThisAndFollowing default false
- * @param {Object} diffMeetings
- * @param {Meeting} cMeeting current meeting
- * @param {Function} callback
- */
- function editNextMeetings(editThisAndFollowing = false, diffMeetings, cMeeting, callback) {
- const moment = require('moment');
- if (editThisAndFollowing) {
- nextMeetings(cMeeting.id, true, function (err, nextmeetings) {
- if (err) {
- if (callback) callback(err);
- return;
- }
- const newOccurrences = generateNextOccurrences(cMeeting);
- newOccurrences.unshift(moment(cMeeting.startDate).toDate());
- const diffoccurrences = diffOccurrences(nextmeetings, newOccurrences, !!diffMeetings);
- if (!diffoccurrences) {
- if (callback) callback();
- return;
- }
- async.parallel([
- function (next) { // Cancel meetings
- if (!diffoccurrences.remove || !diffoccurrences.remove.length)
- return next();
- cancelMeetings(diffoccurrences.remove.map(o => o.id).filter(id => id !== cMeeting.id), next);
- },
- function (next) { // Update meetings
- if (!diffoccurrences.update || !diffoccurrences.update.length)
- return next();
- updateMeetings(cMeeting, diffMeetings, diffoccurrences.update.map(o => o.id), next);
- },
- function (next) { // Create meetings
- if (!diffoccurrences.add || !diffoccurrences.add.length)
- return next();
- createNextMeetings(cMeeting, diffoccurrences.add, cMeeting.invitees, cMeeting.agendaItems, next);
- }
- ], function (err, results) {
- if (err) {
- if (callback) callback(err);
- return;
- }
- buildMeetingTree([cMeeting.id].concat(results[1]).concat(results[2]), callback);
- });
- });
- } else if (diffMeetings && diffMeetings.isRecurring) {
- if (!diffMeetings.isRecurring.oldValue && diffMeetings.isRecurring.newValue) { // Create next meetings
- createNextMeetings(cMeeting, generateNextOccurrences(cMeeting), cMeeting.invitees, cMeeting.agendaItems, callback);
- } else if (diffMeetings.isRecurring.oldValue && !diffMeetings.isRecurring.newValue) { // Cancel next meetings
- nextMeetings(cMeeting.id, false, function (err, nextmeetings) {
- if (err) {
- if (callback) callback(err);
- return;
- }
- cancelMeetings(nextmeetings.map(m => m.id), callback);
- });
- } else if (callback) {
- callback();
- }
- } else if (callback) {
- callback();
- }
- }
- function publishNextMeetings(cMeeting, callback) {
- nextMeetings(cMeeting.id, false, function (err, nextmeetings) {
- if (err || !nextmeetings || !nextmeetings.length) {
- if (callback) callback(err);
- return;
- }
- async.each(nextmeetings, function (m, next) {
- Meeting.findOne({
- // include
- where: {
- and: [
- { state: constants.MEETING_CREATED },
- { isDeleted: false }
- ]
- }
- }, function (err, meeting) {
- if (err || !meeting || meeting.state !== constants.MEETING_CREATED)
- return next(err);
- // TODO: Send meeting request
- meeting.updateAttributes({ state: constants.MEETING_PUBLISHED, modified: new Date() }, next);
- });
- }, function (err) {
- if (callback) callback(err);
- });
- });
- }
- function deleteNextMeetings(cMeeting, callback) {
- nextMeetings(cMeeting.id, false, function (err, nextmeetings) {
- if (err || !nextmeetings || !nextmeetings.length) {
- if (callback) callback(err);
- return;
- }
- async.each(nextmeetings, function (m, next) {
- Meeting.findById(m.id/*, { include: [] }*/, function (err, meeting) {
- if (err || !meeting)
- return next(err);
- meeting.updateAttributes({ isDeleted: true, modified: new Date() }, function (err) {
- if (err || meeting.state === constants.MEETING_CREATED || meeting.state === constants.MEETING_OVER)
- return next(err);
- // TODO: Send meeting cancellation
- next();
- });
- });
- }, function (err) {
- if (callback) callback(err);
- });
- });
- }
- Meeting.saveMeeting = function (meeting, cb) {
- if (meeting.recurrence && meeting.recurrence.dirty) {
- meeting.isRecurring = meeting.recurrence.isRecurring;
- meeting.recurringPattern = meeting.recurrence.pattern;
- }
- if (meeting.id) { // updating meeting
- Meeting.findById(meeting.id, {
- include: [
- { environment: 'config' },
- { organiser: 'user' },
- { invitees: 'environmentUser' },
- 'company',
- 'agendaItems'
- ]
- }, function (err, meetingToUpdate) {
- if (err) return cb(err);
- if (!meetingToUpdate) {
- var notFound = new Error();
- notFound.status = 404;
- notFound.message = 'Meeting not found!';
- notFound.name = 'MEETING_NOT_FOUND';
- return cb(notFound);
- }
- const diffmeetings = diffMeetings(meetingToUpdate, meeting);
- meeting.state = diffmeetings && meetingToUpdate.state === constants.MEETING_PUBLISHED ? constants.MEETING_UPDATED : meetingToUpdate.state;
- if ((diffmeetings && diffmeetings.isRecurring && diffmeetings.isRecurring.oldValue && !diffmeetings.isRecurring.newValue)
- || meeting.editThisAndFollowing)
- meeting.parentId = null;
- let removedEnvironmentUsersId = [];
- let addedEnvironmentUsersId = [];
- if (meetingToUpdate.state !== constants.MEETING_CREATED) {
- const oldEnvironmentUsersId = (meetingToUpdate.invitees() || []).map(mi => mi.idEnvironmentUser);
- const newEnvironmentUsersId = (meeting.invitees || []).map(mi => {
- if (mi.environmentUser)
- return mi.environmentUser.id;
- return mi.idEnvironmentUser;
- }).concat((meeting.otherInvitees || []).map(moi => {
- if (moi.environmentUser)
- return moi.environmentUser.id;
- return moi.idEnvironmentUser;
- }));
- if (newEnvironmentUsersId.length < oldEnvironmentUsersId.length && meetingToUpdate.environment().config().notifyUserIfRemoved) // some users were removed from the meeting
- removedEnvironmentUsersId = oldEnvironmentUsersId.filter(id => newEnvironmentUsersId.indexOf(id) === -1);
- addedEnvironmentUsersId = newEnvironmentUsersId.filter(i => oldEnvironmentUsersId.indexOf(i) === -1); // some users were added to the meeting
- }
- meeting.modified = new Date();
- meeting.information = encryptor.encryptText(meeting.information, key);
- meeting.decisionTaken = encryptor.encryptText(meeting.decisionTaken, key);
- meetingToUpdate.patchAttributes(meeting, function (err, updatedMeeting) {
- if (err || !updatedMeeting) return cb(err);
- async.parallel([
- function (callback) { // invitees
- if (!diffmeetings || !diffmeetings.invitees)
- return callback();
- meetingToUpdate.invitees.destroyAll(function (err) {
- if (err) return callback(err);
- async.each(meeting.invitees, function (invitee, next) { // update the invitees
- if (!invitee.permission) return next(); // should be considered as an error
- var invPermission = invitee.permission;
- delete invPermission.id;
- app.models.Permission.create(invPermission, function (err, newPermission) {
- if (err || !newPermission) return next(err);
- app.models.MeetingInvitee.create({
- idMeeting: meeting.id,
- idPermission: newPermission.id,
- idMeetingRole: invitee.idMeetingRole,
- idEnvironmentUser: invitee.idEnvironmentUser
- }, next);
- });
- }, callback);
- });
- },
- function (callback) { // agenda items
- if (!diffmeetings || !diffmeetings.agendaItems || !Array.isArray(meeting.agendaItems) || !meeting.agendaItems.length)
- return callback();
- async.each(meeting.agendaItems, function (item, next) { // update the agenda items
- item.idMeeting = meeting.id;
- app.models.AgendaItem.findById(item.id, function (err, agendaItem) {
- if (err || !agendaItem) return next(err);
- agendaItem.patchAttributes(item, function (err) {
- if (err) return next(err);
- async.each(item.documents, function (doc, nxt) { // update the agenda documents
- app.models.AgendaDocument.findById(doc.id, function (err, agendaDocument) {
- if (err || !agendaDocument) return nxt(err);
- agendaDocument.patchAttributes(doc, nxt);
- });
- }, next);
- });
- });
- }, callback);
- }
- ], function (err) {
- if (err) return cb(err);
- cb(null, updatedMeeting);
- Meeting.emit('editNextMeetings', {
- editThisAndFollowing: !!meeting.editThisAndFollowing,
- diffMeetings: diffmeetings,
- currentMeeting: meeting
- });
- (removedEnvironmentUsersId.filter((v, i, s) => s.indexOf(v) === i)).forEach(function (id) {
- Meeting.emit('notifyUser', {
- meeting: meetingToUpdate,
- envUserId: id,
- organiser: meetingToUpdate.organiser().user()
- });
- });
- const batchNewIds = addedEnvironmentUsersId.filter((v, i, s) => s.indexOf(v) === i);
- if (batchNewIds.length) {
- Meeting.emit('notifyNewUserV2', {
- meeting: meetingToUpdate,
- ids: batchNewIds
- });
- }
- });
- });
- });
- } else { // create meeting
- delete meeting.id;
- meeting.information = encryptor.encryptText(meeting.information, key);
- meeting.decisionTaken = encryptor.encryptText(meeting.decisionTaken, key);
- Meeting.create(meeting, function (err, newMeeting) {
- if (err || !newMeeting) return cb(err);
- const datesOfNextMeetings = generateNextOccurrences(newMeeting);
- async.parallel([
- function (callback) { // invitees
- async.each(meeting.invitees, function (invitee, next) { // save the invitees
- if (!invitee.permission) return next(); // should be considered as an error
- var invPermission = invitee.permission;
- delete invPermission.id;
- app.models.Permission.create(invPermission, function (err, newPermission) {
- if (err || !newPermission) return next(err);
- app.models.MeetingInvitee.create({
- idMeeting: newMeeting.id,
- idPermission: newPermission.id,
- idMeetingRole: invitee.idMeetingRole,
- idEnvironmentUser: invitee.idEnvironmentUser
- }, next);
- });
- }, callback);
- },
- function (callback) { // agenda items
- if (!Array.isArray(meeting.agendaItems) || !meeting.agendaItems.length)
- return callback();
- async.each(meeting.agendaItems, function (item, next) { // save the agenda items
- item.idMeeting = newMeeting.id;
- app.models.AgendaItem.findById(item.id, function (err, agendaItem) {
- if (err || !agendaItem) return next(err);
- agendaItem.patchAttributes(item, function (err) {
- if (err) return next(err);
- async.each(item.documents, function (doc, nxt) { // save the agenda documents
- app.models.AgendaDocument.findById(doc.id, function (err, agendaDocument) {
- if (err || !agendaDocument) return nxt(err);
- agendaDocument.patchAttributes(doc, nxt);
- });
- }, next);
- });
- });
- }, callback);
- }
- ], function (err) {
- if (err) return cb(err);
- cb(null, newMeeting);
- if (datesOfNextMeetings.length) {
- Meeting.emit('createNextMeetings', {
- datesOfNextMeetings: datesOfNextMeetings,
- currentMeeting: newMeeting,
- invitees: meeting.invitees,
- agendaItems: meeting.agendaItems
- });
- }
- });
- });
- }
- };
- Meeting.remoteMethod('saveMeeting', {
- accepts: {
- arg: 'data',
- type: 'object',
- http: {
- source: 'body'
- }
- },
- returns: {
- root: true,
- arg: '',
- type: 'Meeting'
- },
- http: {
- path: '/saveMeeting',
- verb: 'post'
- }
- });
- Meeting.setMeetingOver = function (data, cb) {
- app.models.Meeting.findById(data.idMeeting, {
- include: ['company', {
- organiser: ['eboardUser']
- }]
- }, function (error, currentMeeting) {
- currentMeeting.state = "MEETING_OVER";
- app.models.Meeting.upsert(currentMeeting, function (err, meetingUpdated) {
- cb(err, meetingUpdated);
- });
- app.models.Environment.findById(data.idEnvironment, {
- include: ['config']
- }, function (error, currentEnv) {
- emailer.init(currentEnv.config().smtpUsername, currentEnv.config().smtpPassword, currentEnv.config().smtpServerAddress);
- var templateContent = currentEnv.config().meetingOverTemplate; //'<p>' + currentMeeting.name + '</p>' + '<p>Information</p>' + encryptor.decryptText(currentMeeting.information) + '<p>Decision Taken</p>' + encryptor.decryptText(currentMeeting.decisionTaken);
- templateContent = templateContent.replace('[MEETING_NAME]', currentMeeting.name);
- templateContent = templateContent.replace('[INFORMATION]', encryptor.decryptText(currentMeeting.information, key));
- templateContent = templateContent.replace('[DECISION]', encryptor.decryptText(currentMeeting.decisionTaken, key));
- var emailContent = '<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">' + templateContent + '</td>';
- templateManager.injectContent(emailContent, function (injectError, response) {
- if (!injectError) {
- var subject = 'Archived Meeting';
- var mailInfo = emailer.sendEmail({
- from: currentEnv.config().mailFrom,
- to: currentMeeting.organiser().eboardUser().email,
- subject: subject,
- isHtml: true,
- body: response
- }, function (err) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: currentMeeting.organiser().eboardUser().email,
- content: response,
- idEnvironment: currentEnv.id,
- idMeeting: currentMeeting.id,
- date: new Date(),
- subject: subject,
- type: 'Meeting Over',
- }, function (ex, res) { });
- });
- //return cb(null,currentMeeting);
- }
- });
- });
- });
- };
- Meeting.remoteMethod(
- 'setMeetingOver', {
- accepts: {
- arg: 'data',
- type: 'object',
- http: {
- source: 'body'
- }
- },
- returns: {
- root: true,
- arg: '',
- type: 'Meeting'
- },
- http: {
- path: '/setMeetingOver',
- verb: 'post'
- }
- });
- Meeting.sendAnnotatedDocument = function (data, cb) {
- var runAsync = watt(function* (next) {
- var annotatedDoc = yield app.models.RemoteFile.findById(data.documentId, next);
- var currentMeeting = yield app.models.Meeting.findById(data.idMeeting, {
- include: ['company']
- }, next);
- var currentEnv = yield app.models.Environment.findById(currentMeeting.idEnvironment, {
- include: ['config']
- }, next);
- var currentEnvUser = yield app.models.EnvironmentUser.findById(data.idUser, {
- include: ['eboardUser']
- }, next);
- for (var recipientId of data.recipients) {
- var currentRecipient = yield app.models.EnvironmentUser.findById(recipientId, {
- include: ['eboardUser']
- }, next);
- if (currentRecipient) {
- var moment = require('moment');
- var templateContent = currentEnv.config().annotatedDocumentTemplate;
- templateContent = templateContent.replace('[DOC_NAME]', annotatedDoc.name);
- templateContent = templateContent.replace('[SENDER_NAME]', currentEnvUser.eboardUser().firstName + " " + currentEnvUser.eboardUser().lastName);
- templateContent = templateContent.replace('[MEETING_NAME]', currentMeeting.name);
- templateContent = templateContent.replace('[COMPANY_NAME]', currentMeeting.company().name);
- templateContent = templateContent.replace('[DATE]', moment(currentMeeting.startDate).format('DD MMM YYYY'));
- // templateContent = templateContent.replace('[TIME]', moment(currentMeeting.startDate).zone("+04:00").format('HH:mm'));
- templateContent = templateContent.replace('[LOCATION_NAME]', currentMeeting.location);
- var emailContent = '<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">' + templateContent + '</td>';
- var response = yield templateManager.injectContent(emailContent, next);
- var appRoot = require('app-root-path');
- var fileNameOnDisk = Enumerable.from(annotatedDoc.url.split("/")).last();
- var filePath = require('path').resolve(appRoot.path + '/server/storage/' + currentEnv.id + '/' + fileNameOnDisk);
- var tmpFolder = require('path').resolve(appRoot.path + '/server/storage/tmp/');
- var decryptedPath = require('path').join(tmpFolder, annotatedDoc.name);
- yield encryptor.decryptFile(filePath, decryptedPath, key, next);
- emailer.init(currentEnv.config().smtpUsername, currentEnv.config().smtpPassword, currentEnv.config().smtpServerAddress);
- var subject = 'Meeting Annotation Document';
- var mailInfo = yield emailer.sendEmail({
- from: currentEnv.config().smtpUsername,
- to: currentRecipient.eboardUser().email,
- subject: subject,
- isHtml: true,
- body: response,
- attachments: [{ // file on disk as an attachment
- filename: annotatedDoc.name,
- path: decryptedPath // stream this file
- }]
- }, next);
- app.models.Email.create({
- from: currentEnv.config().smtpUsername,
- to: currentRecipient.eboardUser().email,
- content: response,
- idEnvironment: currentMeeting.idEnvironment,
- idMeeting: data.idMeeting,
- subject: subject,
- date: new Date(),
- hasDocument: true,
- type: 'SEND_ANNOTATED_DOC'
- }, function (ex, res) { });
- }
- }
- return currentMeeting;
- });
- runAsync(function (err, response) {
- if (err) {
- console.error(err);
- }
- cb(err, response);
- });
- };
- Meeting.remoteMethod(
- 'sendAnnotatedDocument', {
- accepts: {
- arg: 'data',
- type: 'object',
- http: {
- source: 'body'
- }
- },
- returns: {
- root: true,
- arg: '',
- type: 'Meeting'
- },
- http: {
- path: '/sendAnnotatedDocument',
- verb: 'post'
- }
- });
- Meeting.addAttendance = function (idMeeting, idUser, attending, cb) {
- idMeeting = parseInt(idMeeting, 10);
- idUser = parseInt(idUser, 10);
- attending = parseInt(attending, 10);
- var isAttending = attending == 1;
- app.models.MeetingAttendance.findOne({
- include: 'environmentUser',
- where: {
- and: [
- { idMeeting: idMeeting },
- { idEnvironmentUser: idUser },
- { isDeleted: false }
- ]
- }
- }, function (error, theUser) {
- if (error) {
- return cb(error, {
- success: false
- });
- }
- if (theUser) {
- theUser.patchAttributes({
- isAttending: isAttending
- }, function (err, theUser) {
- if (err) {
- return cb(error, {
- success: false
- });
- } else {
- cb(null, {
- success: true
- });
- }
- });
- }
- });
- };
- Meeting.remoteMethod(
- 'addAttendance', {
- accepts: [{
- arg: 'idMeeting',
- type: 'string'
- }, {
- arg: 'idUser',
- type: 'string'
- }, {
- arg: 'attending',
- type: 'string'
- }],
- http: {
- path: '/addAttendance',
- verb: 'get'
- }
- });
- Meeting.publishMeeting = function (data, cb) {
- Meeting.findOne({
- order: 'name ASC',
- include: ['attendance', {
- meetingType: {
- organisers: ['eboardUser']
- }
- }, {
- organiser: ['eboardUser']
- }, {
- agendaItems: [{
- documents: ["file", {
- votes: [{
- environmentUser: ['eboardUser']
- }]
- }]
- }]
- }, {
- company: ['users', 'companyLogo']
- }, {
- invitees: ['permission', {
- role: 'permission'
- }, {
- environmentUser: 'eboardUser'
- }]
- }],
- where: {
- and: [{
- isDeleted: false
- }, {
- id: data.idMeeting
- }]
- }
- }, function (error, meeting) {
- if (error)
- return cb(error);
- if (!meeting) {
- const notFound = new Error();
- notFound.status = 404;
- notFound.message = 'Meeting not found';
- notFound.name = 'NO_MEETING';
- return cb(notFound);
- }
- if (meeting.isRecurring) {
- // TODO: publish next meetings if not published
- // publishNextMeetings(meeting, callback);
- }
- app.models.Environment.findById(meeting.idEnvironment, {
- include: ['config']
- }, function (errorEnv, currentEnv) {
- if (errorEnv)
- return cb(errorEnv);
- emailer.init(currentEnv.config().smtpUsername, currentEnv.config().smtpPassword, currentEnv.config().smtpServerAddress);
- if (currentEnv.config().publishMeetingWithNotif) {
- var moment = require('moment');
- var subject = 'New_' + meeting.company().name + '_' + meeting.name + '_' + moment(meeting.startDate).format('DD MMM YYYY');
- if (currentEnv.config().showAttendance) {
- //invite the organiser
- sendEmailWithIcsFile(meeting.organiser(), subject, data.message, meeting, false, function (sendErr) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: meeting.organiser().eboardUser().email,
- content: data.message,
- idEnvironment: currentEnv.id,
- idMeeting: meeting.id,
- subject: subject,
- date: new Date(),
- type: 'MEETING_PUBLISH'
- }, function (ex, res) { });
- });
- var allInvitees = meeting.invitees();
- if (currentEnv.config().allowSendMailToAllOrganiser) {
- var meetingTypeOrg = meeting.meetingType().organisers();
- meetingTypeOrg = Enumerable.from(meetingTypeOrg).where(function (mo) {
- return mo.isActive && mo.eboardUserId != meeting.organiser().eboardUserId;
- }).toArray();
- for (var org of meetingTypeOrg) {
- sendEmailWithIcsFile(org, subject, data.message, meeting, false, function (sendErr) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: org.eboardUser().email,
- content: data.message,
- idEnvironment: currentEnv.id,
- idMeeting: meeting.id,
- subject: subject,
- date: new Date(),
- type: 'MEETING_PUBLISH'
- }, function (ex, res) { });
- });
- }
- }
- for (var invitee of allInvitees) {
- //add attendance
- app.models.MeetingAttendance.findOrCreate({
- idMeeting: meeting.id,
- idEnvironmentUser: invitee.environmentUser().id
- }, function (attendError, theUser) {
- if (attendError) {
- console.log(attendError);
- }
- });
- sendEmailWithIcsFile(invitee.environmentUser(), subject, data.message, meeting, currentEnv.config().showAttendance, function (sendErr) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: invitee.environmentUser().eboardUser().email,
- content: data.message,
- idEnvironment: currentEnv.id,
- idMeeting: meeting.id,
- subject: subject,
- date: new Date(),
- type: 'MEETING_PUBLISH'
- }, function (ex, res) { });
- });
- }
- } else {
- sendEmailInBatchWithIcsFile(subject, data.message, meeting, function (sendErr) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: meeting.organiser().eboardUser().email,
- content: data.message,
- idEnvironment: currentEnv.id,
- idMeeting: meeting.id,
- subject: subject,
- date: new Date(),
- type: 'MEETING_PUBLISH'
- }, function (ex, res) { });
- });
- }
- }
- });
- meeting.state = constants.MEETING_PUBLISHED;
- Meeting.upsert(meeting, function (err, meetingUpdated) {
- cb(err, meetingUpdated);
- });
- });
- };
- Meeting.remoteMethod(
- 'publishMeeting', {
- accepts: {
- arg: 'data',
- type: 'object',
- http: {
- source: 'body'
- }
- },
- returns: {
- root: true,
- arg: '',
- type: 'Meeting'
- },
- http: {
- path: '/publishMeeting',
- verb: 'post'
- }
- });
- function deleteICSFile(aMeeting, cb) {
- var icalToolkit = require('ical-toolkit');
- app.models.Environment.findById(aMeeting.idEnvironment, {
- include: ['config']
- }, function (errorEnv, currentEnv) {
- if (errorEnv) {
- if (cb) {
- cb(errorEnv);
- }
- } else {
- //Create a builder
- var builder = icalToolkit.createIcsFileBuilder();
- /*
- * Settings (All Default values shown below. It is optional to specify)
- * */
- builder.spacers = true; //Add space in ICS file, better human reading. Default: true
- builder.NEWLINE_CHAR = '\r\n'; //Newline char to use.
- builder.throwError = false; //If true throws errors, else returns error when you do .toString() to generate the file contents.
- builder.ignoreTZIDMismatch = true; //If TZID is invalid, ignore or not to ignore!
- /**
- * Build ICS
- * */
- //Name of calander 'X-WR-CALNAME' tag.
- builder.calname = 'Yo Cal';
- //Cal timezone 'X-WR-TIMEZONE' tag. Optional. We recommend it to be same as tzid.
- //builder.timezone = 'america/new_york';
- //Time Zone ID. This will automatically add VTIMEZONE info.
- //builder.tzid = 'america/new_york';
- //Method
- builder.method = 'CANCEL';
- //var sequenceNumber = aMeeting.startDate.getDate() + '' + aMeeting.startDate.getHours() + '' + aMeeting.startDate.getSeconds();
- //var sequenceNumber = 150;
- var allInvitees = aMeeting.invitees() || [];
- var attendees = [];
- for (var invitee of allInvitees) {
- attendees.push({
- name: invitee.environmentUser().eboardUser().firstName + " " + invitee.environmentUser().eboardUser().lastName,
- email: invitee.environmentUser().eboardUser().email,
- rsvp: true
- });
- }
- //Add events
- builder.events.push({
- //Event start time, Required: type Date()
- start: aMeeting.startDate,
- //Event end time, Required: type Date()
- end: aMeeting.endDate,
- //transp. Will add TRANSP:OPAQUE to block calendar.
- transp: 'OPAQUE',
- //Event summary, Required: type String
- summary: aMeeting.name,
- //All Optionals Below
- //sequence: sequenceNumber,
- //Alarms, array in minutes
- //alarms: [15, 10, 5],
- //Event identifier, Optional, default auto generated
- uid: aMeeting.idEnvironment + "" + aMeeting.id + "@eboard.com",
- //Location of event, optional.
- location: aMeeting.location,
- //Optional description of event.
- description: 'Meeting details/Détails de la réunion',
- //Optional Organizer info
- organizer: {
- name: currentEnv.config().allowEditOrganiserNameInCalender ? currentEnv.config().edittedOrganiserName : aMeeting.organiser().eboardUser().firstName + " " + aMeeting.organiser().eboardUser().lastName,
- //if the sender and receiver have same email like oragniser, add to calendar will not be displayed
- //use a hardcoded unique email as a work around
- email: currentEnv.config().mailFrom //'promeeting@agileum.com' //'someone@agileum.com' //aMeeting.organiser().eboardUser().email
- // sentBy: 'person_acting_on_behalf_of_organizer@email.com' //OPTIONAL email address of the person who is acting on behalf of organizer.
- },
- attendees: attendees,
- //What to do on addition
- method: 'CANCEL',
- //Status of event
- status: 'CANCELLED',
- //Url for event on core application, Optional.
- // url: 'http://yahoo.com'
- });
- //Try to build
- var icsFileContent = builder.toString();
- //Check if there was an error (Only required if yu configured to return error, else error will be thrown.)
- if (icsFileContent instanceof Error) {
- console.log('Returned Error, you can also configure to throw errors!');
- //handle error
- cb(null);
- }
- console.log(icsFileContent);
- return cb(icsFileContent);
- }
- });
- }
- Meeting.deletePublishedMeeting = function (data, cb) {
- Meeting.findOne({
- order: 'name ASC',
- include: [
- { meetingType: { organisers: ['eboardUser'] } },
- { organiser: ['eboardUser'] },
- {
- agendaItems: [
- {
- documents: [
- 'file',
- {
- votes: [
- { environmentUser: ['eboardUser'] }
- ]
- }
- ]
- }
- ]
- },
- { company: ['users', 'companyLogo'] },
- {
- invitees: [
- 'permission',
- { role: 'permission' },
- { environmentUser: 'eboardUser' }
- ]
- }
- ],
- where: {
- and: [
- { isDeleted: false },
- { id: data.idMeeting }
- ]
- }
- }, function (error, meeting) {
- if (error)
- return cb(error);
- if (!meeting) {
- var notFound = new Error();
- notFound.status = 404;
- notFound.message = 'Meeting not found';
- notFound.name = 'NO_MEETING';
- return cb(notFound);
- }
- if (data.deleteThisAndFollowing && meeting.isRecurring) {
- // TODO: Delete next meetings
- // deleteNextMeetings(meeting, callback);
- }
- var moment = require('moment');
- var emailMessage = '<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">' + data.template + '</td>';
- var meetingInvitees = Enumerable.from(meeting.invitees()).select(function (m) { return m.environmentUser().eboardUser().email; }).toArray();
- meetingInvitees.push(Enumerable.from(meeting.invitees()).select(function (m) { return m.environmentUser().eboardUser().ccEmail; }).firstOrDefault(null));
- templateManager.injectContent(emailMessage, function (err, response) {
- if (err)
- console.log(err);
- app.models.Environment.findById(meeting.idEnvironment, {
- include: ['config']
- }, function (errorEnv, currentEnv) {
- if (errorEnv)
- return cb(errorEnv);
- if (currentEnv.config().deleteMeetingWithNotif) {
- deleteICSFile(meeting, function (icsContent) {
- if (currentEnv.config().allowSendMailToAllOrganiser) {
- var meetingTypeOrg = meeting.meetingType().organisers();
- meetingTypeOrg = Enumerable.from(meetingTypeOrg).where(function (mo) { return mo.isActive && mo.eboardUserId != meeting.organiser().eboardUserId; }).toArray();
- for (var org of meetingTypeOrg)
- meetingInvitees.push(org.eboardUser().email);
- }
- emailer.init(currentEnv.config().smtpUsername, currentEnv.config().smtpPassword, currentEnv.config().smtpServerAddress);
- var headers = {};
- headers['Content-Transfer-Encoding'] = '7bit';
- var subject = 'Cancel_' + meeting.company().name + '_' + meeting.name + '_' + moment(meeting.startDate).format('DD MMM YYYY');
- emailer.sendEmail({
- from: currentEnv.config().mailFrom,
- to: meeting.organiser().eboardUser().email,
- subject: subject,
- isHtml: true,
- body: response,
- cc: meetingInvitees,
- alternatives: [{
- headers: headers,
- contentType: 'text/calendar; charset="utf-8"; method=REPLY',
- content: new Buffer(icsContent ? icsContent : '')
- }]
- }, function (errr, mailInfo) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: meeting.organiser().eboardUser().email,
- content: response,
- subject: subject,
- idEnvironment: meeting.idEnvironment,
- idMeeting: meeting.id,
- date: new Date(),
- type: 'MEETING_DELETE'
- }, function (ex, res) { });
- for (var anEmail of meetingInvitees) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: anEmail,
- content: response,
- subject: subject,
- idEnvironment: meeting.idEnvironment,
- idMeeting: meeting.id,
- date: new Date(),
- type: 'MEETING_DELETE'
- }, function (ex, res) { });
- }
- if (errr)
- console.log(err);
- console.log(mailInfo);
- });
- });
- }
- });
- meeting.isDeleted = true;
- Meeting.upsert(meeting, function (err, meetingUpdated) {
- cb(err, meetingUpdated);
- });
- });
- });
- };
- Meeting.remoteMethod('deletePublishedMeeting', {
- accepts: {
- arg: 'data',
- type: 'object',
- http: {
- source: 'body'
- }
- },
- returns: {
- root: true,
- arg: '',
- type: 'Meeting'
- },
- http: {
- path: '/deletePublishedMeeting',
- verb: 'post'
- }
- });
- Meeting.notifyMeeting = function (data, cb) {
- var notifyUpdate = data.notifyUpdate;
- Meeting.findOne({
- order: 'name ASC',
- include: [
- { meetingType: { organisers: ['eboardUser'] } },
- { organiser: ['eboardUser'] },
- {
- agendaItems: [
- {
- documents: [
- 'file',
- { votes: [{ environmentUser: ['eboardUser'] }] }
- ]
- }
- ]
- },
- { company: ['users', 'companyLogo'] },
- {
- invitees: [
- 'permission',
- { role: 'permission' },
- { environmentUser: 'eboardUser' }
- ]
- }
- ],
- where: {
- and: [
- { isDeleted: false },
- { id: data.idMeeting }
- ]
- }
- }, function (error, meeting) {
- if (error)
- return cb(error);
- var moment = require('moment');
- var subject = 'Update_' + meeting.company().name + '_' + meeting.name + '_' + moment(meeting.startDate).format('DD MMM YYYY');
- var allInvitees = meeting.invitees();
- app.models.Environment.findById(meeting.idEnvironment, {
- include: ['config']
- }, function (errorEnv, currentEnv) {
- if (errorEnv)
- return cb(errorEnv);
- emailer.init(currentEnv.config().smtpUsername, currentEnv.config().smtpPassword, currentEnv.config().smtpServerAddress);
- if (notifyUpdate) {
- var emailHtml = '<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">' + data.message + '</td>';
- templateManager.injectContent(emailHtml, function (injectErr, response) {
- if (injectErr)
- return cb(injectErr);
- var invEmailList = [];
- var orgEmailList = [];
- orgEmailList.push(meeting.organiser().eboardUser().email);
- for (var invitee of allInvitees) {
- invEmailList.push(invitee.environmentUser().eboardUser().email);
- if (invitee.environmentUser().eboardUser().ccEmail !== null)
- invEmailList.push(invitee.environmentUser().eboardUser().ccEmail);
- }
- if (currentEnv.config().allowSendMailToAllOrganiser) {
- var meetingTypeOrg = meeting.meetingType().organisers();
- meetingTypeOrg = Enumerable.from(meetingTypeOrg).where(function (mo) {
- return mo.isActive && mo.eboardUserId != meeting.organiser().eboardUserId;
- }).toArray();
- for (var org of meetingTypeOrg) {
- orgEmailList.push(org.eboardUser().email);
- if (org.eboardUser().ccEmail !== null)
- orgEmailList.push(org.eboardUser().ccEmail);
- }
- }
- emailer.sendEmail({
- from: currentEnv.config().mailFrom,
- to: invEmailList,
- subject: subject,
- isHtml: true,
- body: response,
- cc: orgEmailList,
- }, function (err, mailInfo) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: orgEmailList + invEmailList,
- content: response,
- idEnvironment: currentEnv.id,
- idMeeting: meeting.id,
- subject: subject,
- date: new Date(),
- type: 'MEETING_NOTIFY'
- }, function (ex, res) { });
- if (err) {
- console.log(err);
- // if (cb)
- // return cb(err);
- }
- console.log(mailInfo);
- // if (cb)
- // cb();
- });
- });
- } else {
- if (currentEnv.config().showAttendance) {
- //update the organiser
- sendEmailWithIcsFile(meeting.organiser(), subject, data.message, meeting, false, function (sendErr) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: meeting.organiser().eboardUser().email,
- content: data.message,
- idEnvironment: currentEnv.id,
- idMeeting: meeting.id,
- subject: subject,
- date: new Date(),
- type: 'MEETING_NOTIFY'
- }, function (ex, res) { });
- });
- if (currentEnv.config().allowSendMailToAllOrganiser) {
- var meetingTypeOrg = meeting.meetingType().organisers();
- meetingTypeOrg = Enumerable.from(meetingTypeOrg).where(function (mo) {
- return mo.isActive && mo.eboardUserId != meeting.organiser().eboardUserId;
- }).toArray();
- for (var org of meetingTypeOrg) {
- sendEmailWithIcsFile(org, subject, data.message, meeting, false, function (sendErr) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: org.eboardUser().email,
- content: data.message,
- idEnvironment: currentEnv.id,
- idMeeting: meeting.id,
- subject: subject,
- date: new Date(),
- type: 'MEETING_NOTIFY'
- }, function (ex, res) { });
- });
- }
- }
- for (var invitee of allInvitees) {
- app.models.MeetingAttendance.findOrCreate({
- idMeeting: meeting.id,
- idEnvironmentUser: invitee.environmentUser().id
- }, function (attendErrorr, theInv) {
- if (attendErrorr)
- console.log(attendErrorr);
- });
- sendEmailWithIcsFile(invitee.environmentUser(), subject, data.message, meeting, currentEnv.config().showAttendance, function (sendErr) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: invitee.environmentUser().eboardUser().email,
- content: data.message,
- idEnvironment: meeting.idEnvironment,
- idMeeting: data.idMeeting,
- date: new Date(),
- subject: subject,
- type: 'MEETING_NOTIFY'
- }, function (ex, res) { });
- });
- }
- } else {
- sendEmailInBatchWithIcsFile(subject, data.message, meeting, function (sendErr) {
- app.models.Email.create({
- from: currentEnv.config().mailFrom,
- to: meeting.organiser().eboardUser().email,
- content: data.message,
- idEnvironment: currentEnv.id,
- idMeeting: meeting.id,
- subject: subject,
- date: new Date(),
- type: 'MEETING_NOTIFY'
- }, function (ex, res) { });
- });
- }
- }
- });
- meeting.state = constants.MEETING_PUBLISHED;
- Meeting.upsert(meeting, function (err, meetingUpdated) {
- cb(err, meetingUpdated);
- });
- });
- };
- Meeting.remoteMethod('notifyMeeting', {
- accepts: {
- arg: 'data',
- type: 'object',
- http: {
- source: 'body'
- }
- },
- returns: {
- root: true,
- arg: '',
- type: 'Meeting'
- },
- http: {
- path: '/notifyMeeting',
- verb: 'post'
- }
- });
- Meeting.searchMeetings = function (data, cb) {
- this.getAllMeetings({
- idUser: data.idUser,
- idEnvironment: data.idEnvironment
- }, function (err, meetings) {
- if (err) {
- cb(err, null);
- } else {
- //filter now
- var filteredMeetings = Enumerable.from(meetings)
- .where(function (m) {
- var shouldSearchByDocument = data.documentName || data.documentName !== "";
- var hasDocument;
- if (shouldSearchByDocument) {
- var allAgendas = Enumerable.from(m.agendaItems()).where(function (a) {
- return a.isDeleted === false;
- }).toArray() || [];
- var allDocuments = [];
- for (var ag of allAgendas) {
- for (var doc of ag.documents()) {
- if (doc.isDeleted === false) {
- allDocuments.push(doc);
- }
- }
- }
- hasDocument = Enumerable.from(allDocuments).where(function (agendaDoc) {
- return agendaDoc.file().name.toLowerCase().indexOf(data.documentName.toLowerCase()) !== -1;
- }).firstOrDefault(null) !== null;
- }
- var hasMeetingName = data.name || data.name !== "";
- return (data.idCompany ? m.idCompany == data.idCompany : true) &&
- (hasMeetingName ? (m.name.toLowerCase().indexOf(data.name.toLowerCase()) !== -1) : true) &&
- (data.idMeetingType ? m.idMeetingType == data.idMeetingType : true) &&
- (shouldSearchByDocument ? hasDocument : true);
- }).toArray();
- cb(null, filteredMeetings);
- //end
- }
- });
- };
- Meeting.remoteMethod(
- 'searchMeetings', {
- accepts: {
- arg: 'data',
- type: 'object',
- http: {
- source: 'body'
- }
- },
- returns: {
- root: true,
- arg: '',
- type: 'Meeting'
- },
- http: {
- path: '/searchMeetings',
- verb: 'post'
- }
- });
- function sendEmailInBatchWithIcsFile(subject, emailMessage, meeting, cb) {
- var emailTempHtml = '<td bgcolor="#ffffff" align="left" height="100%" valign="top" width="100%" style="padding-bottom: 40px;padding:30px;">' + emailMessage + '</td>';
- templateManager.injectContent(emailTempHtml, function (injectErr, response) {
- if (injectErr) {
- console.log(injectErr);
- if (cb) {
- cb(injectErr);
- }
- return;
- }
- generateICSFile(meeting, function (icsContent) {
- console.log(icsContent);
- app.models.Environment.findById(meeting.idEnvironment, {
- include: ['config']
- }, function (errorEnv, currentEnv) {
- if (errorEnv) {
- if (cb) {
- cb(errorEnv);
- }
- } else {
- var headers = {};
- headers['Content-Transfer-Encoding'] = '7bit';
- console.log('From: ' + currentEnv.config().mailFrom);
- var invList = [];
- var orgList = [];
- orgList.push(meeting.organiser().eboardUser().email);
- if (meeting.organiser().eboardUser().ccEmail !== null) {
- orgList.push(meeting.organiser().eboardUser().ccEmail);
- }
- for (var invitee of meeting.invitees()) {
- invList.push(invitee.environmentUser().eboardUser().email);
- if (invitee.environmentUser().eboardUser().ccEmail !== null) {
- invList.push(invitee.environmentUser().eboardUser().ccEmail);
- }
- }
- if (currentEnv.config().allowSendMailToAllOrganiser) {
- var meetingTypeOrgs = meeting.meetingType().organisers();
- meetingTypeOrgs = Enumerable.from(meetingTypeOrgs).where(function (mo) {
- return mo.isActive && mo.eboardUserId != meeting.organiser().eboardUserId;
- }).toArray();
- for (var org of meetingTypeOrgs) {
- orgList.push(org.eboardUser().email);
- if (org.eboardUser().ccEmail !== null) {
- orgList.push(org.eboardUser().ccEmail);
- }
- }
- }
- emailer.sendEmail({
- from: currentEnv.config().mailFrom,
- to: invList,
- subject: subject,
- isHtml: true,
- body: response,
- cc: orgList,
- alternatives: [{
- headers: headers,
- contentType: 'text/calendar; charset="utf-8"; method=REPLY',
- content: new Buffer(icsContent ? icsContent : '')
- }],
- }, function (err, mailInfo) {
- if (err) {
- console.log(err);
- if (cb)
- return cb(err);
- }
- console.log(mailInfo);
- if (cb)
- cb();
- });
- }
- });
- });
- });
- }
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement