packages/oae-activity/emailTemplates/mail.shared.js
/*!
* Copyright 2014 Apereo Foundation (AF) Licensed under the
* Educational Community License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS"
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
import _ from 'underscore';
import * as AuthzUtil from 'oae-authz/lib/util.js';
import { ActivityConstants } from 'oae-activity/lib/constants.js';
/**
* Determine if the given string is an email
*
* @param {String} email The string to check
* @return {Boolean} Whether or not the string is an email address
*/
const { isEmail } = AuthzUtil;
/**
* Get an appropriate message to put in the email subject header.
*
* For an email invitation, the subject always contains the names of people who are trying to
* invite them so it better legitimizes the email:
*
* e.g., "Nicolaas Matthijs, Branden Visser and 2 others have invited you to collaborate"
*
* For an existing user account, we make simpler subjects dependent on their email preference:
*
* - When an immediate email is sent with a single activity: `<activitySummary>`
* - When an immediate email is sent with multiple actors: `New activity is waiting for you`
* - When a daily email is sent: `Today's activity summary`
* - When a weekly email is sent: `Last week's activity summary`
*
* @param {Object} util The template utility that can be used to encode HTML, translate keys, etc...
* @param {Resource} recipient The email preference for which to generate an email summary
* @param {Activity[]} activitities The activities for which to generate a summary
* @return {String} An appropriate summary given the recipient information and activities
*/
const getEmailSubject = (util, recipient, activities) => {
if (isEmail(recipient.id)) {
// If this is an invitation to a user who doesn't have an account yet, we speak to them
// a little bit differently because we have to legitimize our email quicker (i.e., in the
// subject)
if (_.size(activities) === 1) {
return util.i18n.translate(activities[0].summary.i18nKey, activities[0].summary.i18nArguments);
}
const actors = _getAllEntities(activities, 'actor');
if (_.size(actors) === 1) {
return util.i18n.translate('__MSG__ACTIVITY_EMAIL_SUBJECT_INVITE_ACTOR_1__', {
actor1DisplayName: actors[0].displayName
});
}
if (_.size(actors) === 2) {
return util.i18n.translate('__MSG__ACTIVITY_EMAIL_SUBJECT_INVITE_ACTOR_2__', {
actor1DisplayName: actors[0].displayName,
actor2DisplayName: actors[1].displayName
});
}
return util.i18n.translate('__MSG__ACTIVITY_EMAIL_SUBJECT_INVITE_ACTOR_3+__', {
actor1DisplayName: actors[0].displayName,
numActorsMinus1: actors.length - 1
});
}
// If the user already has an account, we can generalize a bit on what has happened based
// on their email preference and number of activities
const { emailPreference } = recipient;
let message = util.i18n.translate('__MSG__RECENT_ACTIVITY__');
switch (emailPreference) {
case 'immediate': {
message =
activities.length === 1
? util.i18n.translate(activities[0].summary.i18nKey, activities[0].summary.i18nArguments)
: util.i18n.translate('__MSG__ACTIVITY_EMAIL_SUBJECT_MULTIPLE__');
break;
}
case 'daily': {
message = util.i18n.translate('__MSG__ACTIVITY_EMAIL_SUBJECT_DAILY__');
break;
}
case 'weekly': {
message = util.i18n.translate('__MSG__ACTIVITY_EMAIL_SUBJECT_WEEKLY__');
break;
}
// No default
}
return message;
};
/**
* Get an appropariate summary given a user's email preference and a set of activities
*
* The options are dependent on their email preference:
* - When an immediate email is sent with a single actor and a single activity: `<displayName> has been active recently`
* - When an immediate email is sent with a single actor and multiple activities: `<displayName> has been very active recently`
* - When an immediate email is sent with multiple actors: `New activity is waiting for you`
* - When a daily email is sent: `Here's your summary of today's activity`
* - When a weekly email is sent: `Here's your summary of last week's activity`
*
* @param {Object} util The template utility that can be used to encode HTML, translate keys, etc
* @param {Resource} recipient The email preference for which to generate an email summary
* @param {Activity[]} activitities The activities for which to generate a summary
* @param {String} baseUrl The base url that each link should have as a prefix
* @return {String} An appropriate summary given the user's email preference and given activities
*/
const getEmailSummary = function (util, recipient, activities, baseUrl) {
if (isEmail(recipient.id)) {
// For an email invitation, we always use the subject invitation language, even for the
// summary
const actors = _getAllEntities(activities, 'actor');
if (_.size(actors) === 1) {
return util.i18n.translate('__MSG__ACTIVITY_EMAIL_SUBJECT_INVITE_ACTOR_1__', {
actor1DisplayName: actors[0].displayName
});
}
if (_.size(actors) === 2) {
return util.i18n.translate('__MSG__ACTIVITY_EMAIL_SUBJECT_INVITE_ACTOR_2__', {
actor1DisplayName: actors[0].displayName,
actor2DisplayName: actors[1].displayName
});
}
return util.i18n.translate('__MSG__ACTIVITY_EMAIL_SUBJECT_INVITE_ACTOR_3+__', {
actor1DisplayName: actors[0].displayName,
numActorsMinus1: actors.length - 1
});
}
const { emailPreference } = recipient;
if (emailPreference === 'immediate') {
// Determine if there was a single or multiple actors
let isSingleActor = true;
let actor = null;
_.each(activities, (activity) => {
if (actor !== null && actor['oae:id'] !== activity.originalActivity.actor['oae:id']) {
isSingleActor = false;
}
actor = activity.originalActivity.actor;
});
if (isSingleActor && actor.objectType !== 'collection') {
let key = '__MSG__ACTIVITY_EMAIL_SUMMARY_IMMEDIATE_SINGLE_ACTOR_SINGLE_ACTIVITY__';
if (activities.length > 1) {
key = '__MSG__ACTIVITY_EMAIL_SUMMARY_IMMEDIATE_SINGLE_ACTOR_MULTIPLE_ACTIVITIES__';
}
// If the profile path was set, it indicates that we have access to view the user, therefore
// we should display a link. If not specified, we should show plain-text
const url = util.url.ensureAbsoluteLink(actor['oae:profilePath'], baseUrl);
let actorLink = '<span>' + util.html.encodeForHTML(actor.displayName) + '</span>';
if (url) {
actorLink = '<a href="' + url + '">' + util.html.encodeForHTML(actor.displayName) + '</a>';
}
const summary = util.i18n.translate(key, { actorLink });
return util.url.ensureAbsoluteLinks(summary, baseUrl);
}
return '__MSG__ACTIVITY_EMAIL_SUMMARY_IMMEDIATE_MULTIPLE_ACTORS__';
}
if (emailPreference === 'daily') {
return '__MSG__ACTIVITY_EMAIL_SUMMARY_DAILY__';
}
if (emailPreference === 'weekly') {
return '__MSG__ACTIVITY_EMAIL_SUMMARY_WEEKLY__';
}
};
/*!
* Get all entities of the entity type associated to all given activities
*
* @param {Activity[]} activities The activities from which to get the entities
* @param {String} entityType The entity type (actor, object or target)
* @return {ActivityEntity[]} All entities of the specified type for all activities
*/
const _getAllEntities = function (activities, entityType) {
const seenIds = {};
const entities = [];
_.each(activities, (activity) => {
const entity = activity.originalActivity[entityType];
// If the entity is a collection, collect all of them
if (entity.objectType === 'collection') {
_.each(entity[ActivityConstants.properties.OAE_COLLECTION], (entity) => {
const entityId = entity[ActivityConstants.properties.OAE_ID];
if (!seenIds[entityId]) {
seenIds[entityId] = true;
entities.push(entity);
}
});
} else {
const entityId = entity[ActivityConstants.properties.OAE_ID];
if (!seenIds[entityId]) {
seenIds[entityId] = true;
entities.push(entity);
}
}
});
return entities;
};
export { isEmail, getEmailSubject, getEmailSummary };