### Eclipse Workspace Patch 1.0
#P Ametys - 07 CMS
Index: main/plugin-cms/i18n/messages_en.xml
===================================================================
--- main/plugin-cms/i18n/messages_en.xml (revision 42093)
+++ main/plugin-cms/i18n/messages_en.xml (working copy)
@@ -2184,4 +2184,15 @@
The name of one or several columns does not correspond to the chosen content type
One or several facets do not correspont to the chosen content type
+
+
+ Sending instant alert on content {0}
+ Sending instant alert on content "{0}" ({1})
+ Sending differed alert on content {0}
+ Sending differed alert on content "{0}" ({1})
+ Send alerts on contents
+ This task goes through the contents and determines if alerts must be sent
+ Daily sending potential alerts on contents
+ Daily sending potential alerts on contents
+
Index: main/plugin-cms/i18n/messages_fr.xml
===================================================================
--- main/plugin-cms/i18n/messages_fr.xml (revision 42093)
+++ main/plugin-cms/i18n/messages_fr.xml (working copy)
@@ -2180,4 +2180,14 @@
Le nom d'une ou plusieurs colonnes ne correspond pas au type de contenu choisi.
Une ou plusieurs facettes ne correspondent pas au type de contenu choisi.
+
+ Envoi d'une alerte instantanée sur le contenu {0}
+ Envoi d'une alerte instantanée sur le contenu "{0}" ({1})
+ Envoi d'une alerte différée sur le contenu {0}
+ Envoi d'une alerte différée sur le contenu "{0}" ({1})
+ Envoyer des alertes sur les contenus
+ Cette tâche parcourt les contenus et détermine si des alertes doivent être envoyées
+ Envoi quotidien d'éventuelles alertes sur les contenus
+ Envoi quotidien d'éventuelles alertes sur les contenus
+
Index: main/plugin-cms/resources/js/Ametys/plugins/cms/content/actions/AlertsActions.js
===================================================================
--- main/plugin-cms/resources/js/Ametys/plugins/cms/content/actions/AlertsActions.js (revision 42093)
+++ main/plugin-cms/resources/js/Ametys/plugins/cms/content/actions/AlertsActions.js (working copy)
@@ -358,7 +358,8 @@
'tristatechange': Ext.bind (this._onCheckReminder, this)
}
},{
- xtype: 'edition.date',
+ xtype: 'edition.datetime',
+ submitFormat: 'Y-m-d H:i',
name: 'reminderDate',
hideLabel: true,
disabled: true,
Index: main/plugin-cms/src/org/ametys/cms/alerts/AlertEngine.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/AlertEngine.java (revision 42093)
+++ main/plugin-cms/src/org/ametys/cms/alerts/AlertEngine.java (working copy)
@@ -1,901 +0,0 @@
-/*
- * Copyright 2010 Anyware Services
- *
- * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
- */
-package org.ametys.cms.alerts;
-
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.mail.MessagingException;
-
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-import org.apache.avalon.framework.context.Context;
-import org.apache.avalon.framework.context.ContextException;
-import org.apache.avalon.framework.service.ServiceException;
-import org.apache.avalon.framework.service.ServiceManager;
-import org.apache.cocoon.Constants;
-import org.apache.cocoon.util.log.SLF4JLoggerAdapter;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.ametys.cms.content.archive.ArchiveConstants;
-import org.ametys.cms.repository.Content;
-import org.ametys.cms.repository.ContentQueryHelper;
-import org.ametys.cms.repository.ModifiableContent;
-import org.ametys.cms.repository.WorkflowStepExpression;
-import org.ametys.cms.repository.WorkflowStepExpression.LogicalOperator;
-import org.ametys.core.engine.BackgroundEngineHelper;
-import org.ametys.core.right.RightsManager;
-import org.ametys.core.user.User;
-import org.ametys.core.user.UserIdentity;
-import org.ametys.core.user.UserManager;
-import org.ametys.core.util.I18nUtils;
-import org.ametys.core.util.mail.SendMailHelper;
-import org.ametys.plugins.repository.AmetysObjectIterable;
-import org.ametys.plugins.repository.AmetysObjectResolver;
-import org.ametys.plugins.repository.AmetysRepositoryException;
-import org.ametys.plugins.repository.metadata.CompositeMetadata;
-import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
-import org.ametys.plugins.repository.query.expression.AndExpression;
-import org.ametys.plugins.repository.query.expression.BooleanExpression;
-import org.ametys.plugins.repository.query.expression.DateExpression;
-import org.ametys.plugins.repository.query.expression.Expression;
-import org.ametys.plugins.repository.query.expression.Expression.Operator;
-import org.ametys.plugins.repository.query.expression.MetadataExpression;
-import org.ametys.plugins.repository.query.expression.NotExpression;
-import org.ametys.plugins.repository.query.expression.OrExpression;
-import org.ametys.plugins.repository.version.MetadataAndVersionAwareAmetysObject;
-import org.ametys.plugins.repository.version.ModifiableMetadataAwareVersionableAmetysObject;
-import org.ametys.runtime.config.Config;
-import org.ametys.runtime.i18n.I18nizableText;
-
-/**
- * Alerts engine: sends alerts mail.
- */
-public class AlertEngine implements Runnable
-{
-
- /** The logger. */
- protected static final Logger _LOGGER = LoggerFactory.getLogger(AlertEngine.class);
-
- /** The avalon context. */
- protected Context _context;
-
- /** The service manager. */
- protected ServiceManager _manager;
-
- /** The server base URL. */
- protected String _baseUrl;
-
- /** Is the engine initialized ? */
- protected boolean _initialized;
-
- /** The cocoon environment context. */
- protected org.apache.cocoon.environment.Context _environmentContext;
-
- /** The ametys object resolver. */
- protected AmetysObjectResolver _ametysResolver;
-
- /** The rights manager. */
- protected RightsManager _rightsManager;
-
- /** The users manager. */
- protected UserManager _userManager;
-
- /** The i18n utils. */
- protected I18nUtils _i18nUtils;
-
- /** The content of "from" field in emails. */
- protected String _mailFrom;
-
- /** The "waiting for validation" e-mail will be sent to users that have at least one of this rights. */
- protected Set _awaitingValidationRights;
-
- /** The "waiting for validation" e-mail subject i18n key. */
- protected String _awaitingValidationSubject;
-
- /** The "waiting for validation" e-mail body i18n key. */
- protected String _awaitingValidationBody;
-
- /** Only contents in this steps will be taken into account for the "unmodified content" alert. */
- protected int[] _unmodifiedContentStepIds;
-
- /** The "unmodified content" e-mail will be sent to users that have at least one of this rights. */
- protected Set _unmodifiedContentRights;
-
- /** The "unmodified content" e-mail subject i18n key. */
- protected String _unmodifiedContentSubject;
-
- /** The "unmodified content" e-mail body i18n key. */
- protected String _unmodifiedContentBody;
-
- /** The reminder e-mail will be sent to users that have this at least one of this rights. */
- protected Set _reminderRights;
-
- /** The reminder e-mail subject i18n key. */
- protected String _reminderSubject;
-
- /** The reminder e-mail body i18n key. */
- protected String _reminderBody;
-
- /** The scheduled archiving reminder e-mail will be sent to users that have this at least one of this rights. */
- protected Set _scheduledArchivingReminderRights;
-
- /** The scheduled archiving reminder e-mail subject i18n key. */
- protected String _scheduledArchivingReminderSubject;
-
- /** The scheduled archiving reminder e-mail body i18n key. */
- protected String _scheduledArchivingReminderBody;
-
- /** The instant alert e-mail will be sent to users that have this at least one of this rights. */
- protected Set _instantAlertRights;
- /** The instant alert e-mail subject i18n key. */
- protected String _instantAlertSubject;
- /** The instant alert e-mail body i18n key. */
- protected String _instantAlertBody;
-
- /** True if the engine was been run in instant mode (for instant alerts only) **/
- protected boolean _instantMode;
- /** The list of contents' id (for instant alerts only) **/
- private List _instantAlertContentIds;
- /** The email message (for instant alerts only) **/
- private String _instantAlertMessage;
-
- /**
- * Default constructor
- */
- public AlertEngine ()
- {
- _instantMode = false;
- }
-
- /**
- * Constructor used to send instant alerts
- * @param contentIds The content's id
- * @param message the message
- */
- public AlertEngine (List contentIds, String message)
- {
- _instantMode = true;
- _instantAlertContentIds = contentIds;
- _instantAlertMessage = message;
- }
-
- /**
- * Initialize the alert engine.
- * @param manager the avalon service manager.
- * @param context the avalon context.
- * @throws ContextException if the CONTEXT_ENVIRONMENT_CONTEXT cannot be found
- * @throws ServiceException if some components cannot be resolved
- */
- public void initialize(ServiceManager manager, Context context) throws ContextException, ServiceException
- {
- _manager = manager;
- _context = context;
- _environmentContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
-
- // Lookup the needed components.
- _ametysResolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
-
- _rightsManager = (RightsManager) manager.lookup(RightsManager.ROLE);
- _userManager = (UserManager) manager.lookup(UserManager.ROLE);
- _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
-
- _baseUrl = StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValueAsString("cms.url"), "index.html"), "/");
- _mailFrom = Config.getInstance().getValueAsString("smtp.mail.from");
-
- _initialized = true;
- }
-
- /**
- * Configure the engine (called by the scheduler).
- * @param configuration the component configuration.
- * @throws ConfigurationException if the configuration is not valid
- */
- public void configure(Configuration configuration) throws ConfigurationException
- {
- Configuration instantConf = configuration.getChild("instantAlert");
- Configuration validationConf = configuration.getChild("awaitingValidation");
- Configuration unmodifiedConf = configuration.getChild("unmodifiedContent");
- Configuration reminderConf = configuration.getChild("reminder");
- Configuration scheduledArchivingReminderConf = configuration.getChild("scheduledArchiving");
-
- // Configure the rights.
- _instantAlertRights = _getRightsFromConf(instantConf);
- _awaitingValidationRights = _getRightsFromConf(validationConf);
- _unmodifiedContentRights = _getRightsFromConf(unmodifiedConf);
- _reminderRights = _getRightsFromConf(reminderConf);
- _scheduledArchivingReminderRights = _getRightsFromConf(scheduledArchivingReminderConf);
- Configuration[] stepIds = unmodifiedConf.getChildren("stepId");
- _unmodifiedContentStepIds = new int[stepIds.length];
- int i = 0;
- for (Configuration stepId : stepIds)
- {
- try
- {
- _unmodifiedContentStepIds[i] = Integer.parseInt(stepId.getValue(""));
- i++;
- }
- catch (NumberFormatException e)
- {
- // Ignore
- }
- }
-
- // Configure the i18n texts.
- _awaitingValidationSubject = validationConf.getChild("subjectKey").getValue();
- _awaitingValidationBody = validationConf.getChild("bodyKey").getValue();
- _unmodifiedContentSubject = unmodifiedConf.getChild("subjectKey").getValue();
- _unmodifiedContentBody = unmodifiedConf.getChild("bodyKey").getValue();
- _reminderSubject = reminderConf.getChild("subjectKey").getValue();
- _reminderBody = reminderConf.getChild("bodyKey").getValue();
- _scheduledArchivingReminderSubject = scheduledArchivingReminderConf.getChild("subjectKey").getValue();
- _scheduledArchivingReminderBody = scheduledArchivingReminderConf.getChild("bodyKey").getValue();
- _instantAlertSubject = instantConf.getChild("subjectKey").getValue();
- _instantAlertBody = instantConf.getChild("bodyKey").getValue();
- }
-
- /**
- * Check the initialization and throw an exception if not initialized.
- */
- protected void _checkInitialization()
- {
- if (!_initialized)
- {
- String message = "Le composant de synchronisation doit être initialisé avant d'être lancé.";
- _LOGGER.error(message);
- throw new IllegalStateException(message);
- }
- }
-
- @Override
- public void run()
- {
- Map environmentInformation = null;
- try
- {
- _LOGGER.info("Preparing to send the alerts...");
-
- _checkInitialization();
-
- // Create the environment.
- environmentInformation = BackgroundEngineHelper.createAndEnterEngineEnvironment(_manager, _environmentContext, new SLF4JLoggerAdapter(_LOGGER));
-
- // Prepare and send all the alerts.
- _sendAlerts();
- }
- catch (Exception e)
- {
- _LOGGER.error("An error occurred sending the alerts.", e);
- }
- finally
- {
- // Leave the environment.
- if (environmentInformation != null)
- {
- BackgroundEngineHelper.leaveEngineEnvironment(environmentInformation);
- }
- // Dispose of the resources.
- _dispose();
- _LOGGER.info("Alerts sent.");
- }
- }
-
- /**
- * Dispose of the resources and looked-up components.
- */
- protected void _dispose()
- {
- // Release the components.
- if (_manager != null)
- {
- _manager.release(_ametysResolver);
- _manager.release(_rightsManager);
- _manager.release(_userManager);
- }
-
- _ametysResolver = null;
- _rightsManager = null;
- _userManager = null;
-
- _environmentContext = null;
- _context = null;
- _manager = null;
-
- _initialized = false;
- }
-
- /**
- * Send all the alerts. Can be overridden to add alerts.
- * @throws AmetysRepositoryException if an error occurs.
- */
- protected void _sendAlerts() throws AmetysRepositoryException
- {
- if (_instantMode)
- {
- _sendInstantAlerts();
- }
- else
- {
- _sendAwaitingValidationAlerts();
- _sendUnmodifiedAlerts();
- _sendReminders();
- _sendScheduledArchivingReminders();
- }
- }
-
- /**
- * Send instant alerts on contents
- * @throws AmetysRepositoryException if an error occurred
- */
- protected void _sendInstantAlerts () throws AmetysRepositoryException
- {
- if (_instantAlertContentIds != null && !_instantAlertContentIds.isEmpty())
- {
- for (String contentId : _instantAlertContentIds)
- {
- Content content = _ametysResolver.resolveById(contentId);
- _sendInstantAlertEmail (content, _instantAlertMessage);
- }
- }
- }
-
- /**
- * Send a instant e-mail alert to all the users who have the right to edit the content.
- * @param content the content about which to send the alert.
- * @param message the message
- * @throws AmetysRepositoryException if an error occurred
- */
- protected void _sendInstantAlertEmail(Content content, String message) throws AmetysRepositoryException
- {
- String context = _getContentContext(content);
-
- Set users = new HashSet<>();
- for (String right : _instantAlertRights)
- {
- users.addAll(_rightsManager.getGrantedUsers(right, context));
- }
-
- List params = _getInstantAlertParams(content, message);
-
- I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_instantAlertSubject, content), params);
- I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_instantAlertBody, content), params);
-
- String subject = _i18nUtils.translate(i18nSubject);
- String body = _i18nUtils.translate(i18nBody);
-
- _sendMails(subject, body, users, _mailFrom);
- }
-
- /**
- * Send the "awaiting validation" alerts.
- * @throws AmetysRepositoryException if an error occurs.
- */
- protected void _sendAwaitingValidationAlerts() throws AmetysRepositoryException
- {
- Long delay = Config.getInstance().getValueAsLong("remind.content.validation.delay");
- if (delay != null && delay > 0)
- {
- Calendar calendar = new GregorianCalendar();
- _removeTimeParts(calendar);
- calendar.add(Calendar.DAY_OF_MONTH, 1 - delay.intValue());
-
- // No last date and X days after the proposal date.
- Expression noLastDateExpr = new NotExpression(new MetadataExpression(AlertsConstants.AWAITING_VALIDATION_ALERT_LAST_DATE, true));
- Expression waitingExpression = new DateExpression("proposalDate", Operator.LT, calendar.getTime(), true);
- // Or proposal date before the last "awaiting validation" date and the and X days after the last "awaiting validation" date.
- Expression proposalBeforeLastDateExpr = new BinaryExpression("proposalDate", true, Operator.LT, AlertsConstants.AWAITING_VALIDATION_ALERT_LAST_DATE, true);
- Expression lastDateExpr = new DateExpression(AlertsConstants.AWAITING_VALIDATION_ALERT_LAST_DATE, Operator.LT, calendar.getTime(), true);
- Expression expression = new OrExpression(new AndExpression(noLastDateExpr, waitingExpression),
- new AndExpression(proposalBeforeLastDateExpr, lastDateExpr));
-
- String query = ContentQueryHelper.getContentXPathQuery(expression);
-
-
-
- try (AmetysObjectIterable contents = _ametysResolver.query(query))
- {
- if (_LOGGER.isInfoEnabled())
- {
- _LOGGER.info("Contents waiting for validation: " + contents.getSize());
- }
-
- for (ModifiableContent content : contents)
- {
- // Send the alert e-mails.
- _sendAwaitingValidationEmail(content);
-
- // Set the last validation alert date to now.
- ModifiableCompositeMetadata meta = ((ModifiableMetadataAwareVersionableAmetysObject) content).getUnversionedMetadataHolder();
- meta.setMetadata(AlertsConstants.AWAITING_VALIDATION_ALERT_LAST_DATE, new Date());
-
- content.saveChanges();
- }
- }
- }
- }
-
- /**
- * Send the unmodified content alerts.
- * @throws AmetysRepositoryException if an error occurs.
- */
- protected void _sendUnmodifiedAlerts() throws AmetysRepositoryException
- {
- Long delay = Config.getInstance().getValueAsLong("remind.unmodified.content.delay");
- if (delay != null && delay > 0)
- {
- Calendar calendar = new GregorianCalendar();
- _removeTimeParts(calendar);
- calendar.add(Calendar.DAY_OF_MONTH, 1 - delay.intValue());
-
- // If no step is configured, stepExpr will return the empty string.
- Expression stepExpr = new WorkflowStepExpression(Operator.EQ, _unmodifiedContentStepIds, LogicalOperator.OR);
- // Get only the contents on which the alert is enabled.
- Expression unmodifiedExpr = new BooleanExpression(AlertsConstants.UNMODIFIED_ALERT_ENABLED, true, true);
- // No last date and X days after the proposal date, or X days after the last date.
- Expression noLastDateExpr = new NotExpression(new MetadataExpression(AlertsConstants.UNMODIFIED_ALERT_LAST_DATE, true));
- Expression lastModifiedExpression = new DateExpression("lastModified", Operator.LT, calendar.getTime());
- Expression lastDateExpr = new DateExpression(AlertsConstants.UNMODIFIED_ALERT_LAST_DATE, Operator.LT, calendar.getTime(), true);
- Expression dateExpr = new OrExpression(new AndExpression(noLastDateExpr, lastModifiedExpression), lastDateExpr);
- // Full AND expression.
- Expression expression = new AndExpression(unmodifiedExpr, dateExpr, stepExpr);
-
- String query = ContentQueryHelper.getContentXPathQuery(expression);
-
- try (AmetysObjectIterable contents = _ametysResolver.query(query))
- {
- if (_LOGGER.isInfoEnabled())
- {
- _LOGGER.info("Contents not modified for " + delay + " days: " + contents.getSize());
- }
-
- for (ModifiableContent content : contents)
- {
- // Send the alert e-mail.
- _sendUnmodifiedContentEmail(content);
-
- // Set the last unmodified alert date to now.
- ModifiableCompositeMetadata meta = ((ModifiableMetadataAwareVersionableAmetysObject) content).getUnversionedMetadataHolder();
- meta.setMetadata(AlertsConstants.UNMODIFIED_ALERT_LAST_DATE, new Date());
-
- content.saveChanges();
- }
- }
- }
- }
-
- /**
- * Send the content reminders.
- * @throws AmetysRepositoryException if an error occurs.
- */
- protected void _sendReminders() throws AmetysRepositoryException
- {
- Calendar now = new GregorianCalendar();
- _removeTimeParts(now);
-
- Expression reminderExpr = new BooleanExpression(AlertsConstants.REMINDER_ENABLED, Operator.EQ, true, true);
- Expression dateExpr = new DateExpression(AlertsConstants.REMINDER_DATE, Operator.EQ, now.getTime(), true);
- Expression expression = new AndExpression(reminderExpr, dateExpr);
-
- String query = ContentQueryHelper.getContentXPathQuery(expression);
-
- try (AmetysObjectIterable contents = _ametysResolver.query(query))
- {
- if (_LOGGER.isInfoEnabled())
- {
- _LOGGER.info("Contents with reminder today: " + contents.getSize());
- }
-
- for (Content content : contents)
- {
- _sendReminderEmail(content);
- }
- }
- }
-
- /**
- * Send the scheduled archiving reminders on contents.
- * @throws AmetysRepositoryException if an error occurs.
- */
- protected void _sendScheduledArchivingReminders() throws AmetysRepositoryException
- {
- Long delay = Config.getInstance().getValueAsLong("archive.scheduler.reminder.delay");
- if (delay != null && delay > 0)
- {
- Calendar calendar = new GregorianCalendar();
- _removeTimeParts(calendar);
- calendar.add(Calendar.DAY_OF_MONTH, delay.intValue());
-
- // No last date and X days before the scheduled date.
- Expression noLastDateExpr = new NotExpression(new MetadataExpression(AlertsConstants.SCHEDULED_ARCHIVING_REMINDER_LAST_DATE, true));
- Expression scheduledDelayExpression = new DateExpression(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE, Operator.LE, calendar.getTime(), true);
- Expression expression = new AndExpression(noLastDateExpr, scheduledDelayExpression);
-
- String query = ContentQueryHelper.getContentXPathQuery(expression);
-
- try (AmetysObjectIterable contents = _ametysResolver.query(query))
- {
- if (_LOGGER.isInfoEnabled())
- {
- _LOGGER.info("Contents with scheduled archiving reminder today: " + contents.getSize());
- }
-
- for (ModifiableContent content : contents)
- {
- _sendScheduledArchivingReminderEmail(content);
-
- // Set the last scheduled archiving reminder date to now.
- ModifiableCompositeMetadata meta = ((ModifiableMetadataAwareVersionableAmetysObject) content).getUnversionedMetadataHolder();
- meta.setMetadata(AlertsConstants.SCHEDULED_ARCHIVING_REMINDER_LAST_DATE, new Date());
-
- content.saveChanges();
- }
- }
- }
- }
-
- /**
- * Send a "waiting for validation" e-mail alert to all the users who have the right to validate.
- * @param content the content about which to send the alert.
- * @throws AmetysRepositoryException if an error occured on the repository
- */
- protected void _sendAwaitingValidationEmail(Content content) throws AmetysRepositoryException
- {
- String context = _getContentContext(content);
-
- Set users = new HashSet<>();
- for (String right : _awaitingValidationRights)
- {
- users.addAll(_rightsManager.getGrantedUsers(right, context));
- }
-
- List params = _getAwaitingValidationParams(content);
-
- I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_awaitingValidationSubject, content), params);
- I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_awaitingValidationBody, content), params);
-
- String subject = _i18nUtils.translate(i18nSubject);
- String body = _i18nUtils.translate(i18nBody);
-
- _sendMails(subject, body, users, _mailFrom);
- }
-
- /**
- * Send a "unmodified content" e-mail alert to all the users who have the right to edit.
- * @param content the content about which to send the alert.
- * @throws AmetysRepositoryException if an error occured on the repository
- */
- protected void _sendUnmodifiedContentEmail(Content content) throws AmetysRepositoryException
- {
- String context = _getContentContext(content);
-
- Set users = new HashSet<>();
- for (String right : _unmodifiedContentRights)
- {
- users.addAll(_rightsManager.getGrantedUsers(right, context));
- }
-
- List params = _getUnmodifiedContentParams(content);
-
- I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_unmodifiedContentSubject, content), params);
- I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_unmodifiedContentBody, content), params);
-
- String subject = _i18nUtils.translate(i18nSubject);
- String body = _i18nUtils.translate(i18nBody);
-
- _sendMails(subject, body, users, _mailFrom);
- }
-
- /**
- * Send a reminder e-mail to all the users who have the right to edit.
- * @param content the content about which to send the reminder.
- * @throws AmetysRepositoryException if an error occured on the repository
- */
- protected void _sendReminderEmail(Content content) throws AmetysRepositoryException
- {
- String context = _getContentContext(content);
-
- Set users = new HashSet<>();
- for (String right : _reminderRights)
- {
- users.addAll(_rightsManager.getGrantedUsers(right, context));
- }
-
- List params = _getReminderParams(content);
-
- I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_reminderSubject, content), params);
- I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_reminderBody, content), params);
-
- String subject = _i18nUtils.translate(i18nSubject);
- String body = _i18nUtils.translate(i18nBody);
-
- _sendMails(subject, body, users, _mailFrom);
- }
-
- /**
- * Send a "scheduled archiving reminder" e-mail to all the users who have the right to archive.
- * @param content the content about which to send the alert.
- * @throws AmetysRepositoryException if an error occured on the repository
- */
- protected void _sendScheduledArchivingReminderEmail(ModifiableContent content) throws AmetysRepositoryException
- {
- String context = _getContentContext(content);
-
- Set users = new HashSet<>();
- for (String right : _scheduledArchivingReminderRights)
- {
- users.addAll(_rightsManager.getGrantedUsers(right, context));
- }
-
- List params = _getScheduledArchivingReminderParams(content);
-
- I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_scheduledArchivingReminderSubject, content), params);
- I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_scheduledArchivingReminderBody, content), params);
-
- String subject = _i18nUtils.translate(i18nSubject);
- String body = _i18nUtils.translate(i18nBody);
-
- _sendMails(subject, body, users, _mailFrom);
- }
-
- /**
- * Get the transform i18n body key for specific content
- * @param bodyI18nKey the original body key
- * @param content the content
- * @return the transform i18n body key
- */
- protected String getI18nKeyBody(String bodyI18nKey, Content content)
- {
- return bodyI18nKey;
- }
-
- /**
- * Get the mail parameters for instant alert.
- * @param content the content.
- * @param message the message
- * @return the parameters.
- */
- protected List _getInstantAlertParams(Content content, String message)
- {
- List params = new ArrayList<>();
-
- params.add(content.getTitle()); // {0}
- params.add(_getContentUrl(content)); // {1}
- params.add(message); // {2}
-
- return params;
- }
-
- /**
- * Get the mail parameters.
- * @param content the content.
- * @return the parameters.
- */
- protected List _getAwaitingValidationParams(Content content)
- {
- List params = new ArrayList<>();
-
- String delay = Config.getInstance().getValueAsString("remind.content.validation.delay");
-
- params.add(content.getTitle()); // {0}
- params.add(_getContentUrl(content)); // {1}
- params.add(delay); // {2}
-
- return params;
- }
-
- /**
- * Get the mail parameters.
- * @param content the content.
- * @return the parameters.
- */
- protected List _getUnmodifiedContentParams(Content content)
- {
- List params = new ArrayList<>();
-
- String delay = Config.getInstance().getValueAsString("remind.unmodified.content.delay");
-
- params.add(content.getTitle()); // {0}
- params.add(_getContentUrl(content)); // {1}
- params.add(delay); // {2}
-
- CompositeMetadata meta = ((MetadataAndVersionAwareAmetysObject) content).getUnversionedMetadataHolder();
- String alertText = meta.getString(AlertsConstants.UNMODIFIED_ALERT_TEXT, "");
- params.add(alertText); // {3}
-
- return params;
- }
-
- /**
- * Get the mail parameters.
- * @param content the content.
- * @return the parameters.
- */
- protected List _getReminderParams(Content content)
- {
- List params = new ArrayList<>();
-
- // Should never trigger a ClassCastException, as we query on an unversioned metadata.
- CompositeMetadata meta = ((MetadataAndVersionAwareAmetysObject) content).getUnversionedMetadataHolder();
- String reminderText = meta.getString(AlertsConstants.REMINDER_TEXT, "");
-
- params.add(content.getTitle()); // {0}
- params.add(_getContentUrl(content)); // {1}
- params.add(reminderText); // {2}
-
- return params;
- }
-
- /**
- * Get the mail parameters.
- * @param content the content.
- * @return the parameters.
- */
- protected List _getScheduledArchivingReminderParams(ModifiableContent content)
- {
- List params = new ArrayList<>();
-
- String delay = Config.getInstance().getValueAsString("archive.scheduler.reminder.delay");
-
- params.add(content.getTitle()); // {0}
- params.add(_getContentUrl(content)); // {1}
- params.add(delay); // {2}
-
- return params;
- }
-
- /**
- * Send the alert emails.
- * @param subject the e-mail subject.
- * @param body the e-mail body.
- * @param users users to send the mail to.
- * @param from the address sending the e-mail.
- */
- protected void _sendMails(String subject, String body, Set users, String from)
- {
- for (UserIdentity identity : users)
- {
- User user = _userManager.getUser(identity.getPopulationId(), identity.getLogin());
-
- if (user != null && StringUtils.isNotBlank(user.getEmail()))
- {
- String mail = user.getEmail();
-
- try
- {
- SendMailHelper.sendMail(subject, null, body, mail, from);
- }
- catch (MessagingException e)
- {
- if (_LOGGER.isWarnEnabled())
- {
- _LOGGER.warn("Could not send an alert e-mail to " + mail, e);
- }
- }
- }
- }
- }
-
- /**
- * Get the rights context on the given content.
- * @param content the content.
- * @return the rights context.
- * @throws AmetysRepositoryException if an error occured on the repository
- */
- protected String _getContentContext(Content content) throws AmetysRepositoryException
- {
- return "/contents/" + content.getName();
- }
-
- /**
- * Get the URL to the given content tool.
- * @param content the content.
- * @return the content URL.
- */
- protected String _getContentUrl(Content content)
- {
- StringBuilder url = new StringBuilder(_baseUrl);
- url.append("/index.html?uitool=uitool-content,id:%27").append(content.getId()).append("%27");
-
- return url.toString();
- }
-
- /**
- * Remove the time parts from a calendar, leaving only date parts.
- * @param calendar the calendar.
- */
- protected void _removeTimeParts(Calendar calendar)
- {
- calendar.set(Calendar.HOUR_OF_DAY, 0);
- calendar.set(Calendar.MINUTE, 0);
- calendar.set(Calendar.SECOND, 0);
- calendar.set(Calendar.MILLISECOND, 0);
- }
-
- /**
- * Get a set of rights from a configuration.
- * @param configuration the configuration.
- * @return the set of rights.
- * @throws ConfigurationException if the configuration is not valid.
- */
- protected Set _getRightsFromConf(Configuration configuration) throws ConfigurationException
- {
- Set rights = new HashSet<>();
-
- for (Configuration rightConf : configuration.getChildren("right"))
- {
- String right = rightConf.getValue("");
- if (StringUtils.isNotBlank(right))
- {
- rights.add(right);
- }
- }
-
- return rights;
- }
-
- /**
- * Binary date expression: test on two metadatas.
- */
- protected class BinaryExpression implements Expression
- {
- private MetadataExpression _metadata1;
- private MetadataExpression _metadata2;
- private Operator _operator;
-
- /**
- * Creates the comparison Expression.
- * @param metadata1 the first metadata name.
- * @param operator the operator to make the comparison
- * @param metadata2 the second metadata name.
- */
- public BinaryExpression(String metadata1, Operator operator, String metadata2)
- {
- _metadata1 = new MetadataExpression(metadata1);
- _operator = operator;
- _metadata2 = new MetadataExpression(metadata2);
- }
-
- /**
- * Creates the comparison Expression.
- * @param metadata1 the first metadata name.
- * @param unversioned1 true if the first metadata is unversioned.
- * @param operator the operator to make the comparison.
- * @param metadata2 the second metadata name.
- * @param unversioned2 true if the second metadata is unversioned.
- */
- public BinaryExpression(String metadata1, boolean unversioned1, Operator operator, String metadata2, boolean unversioned2)
- {
- _metadata1 = new MetadataExpression(metadata1, unversioned1);
- _operator = operator;
- _metadata2 = new MetadataExpression(metadata2, unversioned2);
- }
-
- @Override
- public String build()
- {
- return _metadata1.build() + " " + _operator + " " + _metadata2.build();
- }
- }
-
-}
Index: main/plugin-cms/src/org/ametys/cms/alerts/AlertEngineRunnable.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/AlertEngineRunnable.java (revision 0)
+++ main/plugin-cms/src/org/ametys/cms/alerts/AlertEngineRunnable.java (revision 0)
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 Anyware Services
+ *
+ * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
+ */
+package org.ametys.cms.alerts;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.commons.lang3.StringUtils;
+
+import org.ametys.core.schedule.Runnable;
+import org.ametys.plugins.core.impl.schedule.StaticRunnable;
+import org.ametys.runtime.config.Config;
+
+/**
+ * {@link Runnable} for scheduling an {@link AlertEngineSchedulable} to run once a day depending on a configuration parameter.
+ */
+public class AlertEngineRunnable extends StaticRunnable
+{
+ @Override
+ public void configure(Configuration configuration) throws ConfigurationException
+ {
+ _fireProcess = FireProcess.CRON;
+ super.configure(configuration);
+ String hourStr = Config.getInstance().getValueAsString("alerts.scheduler.hour");
+ if (StringUtils.isNotEmpty(hourStr) && hourStr.indexOf(':') > 0)
+ {
+ int hour = 0;
+ int minute = 0;
+ String[] hourArray = StringUtils.split(hourStr, ':');
+ hour = Integer.parseInt(hourArray[0]);
+ minute = Integer.parseInt(hourArray[1]);
+ _cronExpression = "0 " + minute + " " + hour + " * * ? *";
+ }
+ }
+}
Index: main/plugin-cms/src/org/ametys/cms/alerts/AlertEngineSchedulable.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/AlertEngineSchedulable.java (revision 0)
+++ main/plugin-cms/src/org/ametys/cms/alerts/AlertEngineSchedulable.java (revision 0)
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Anyware Services
+ *
+ * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
+ */
+package org.ametys.cms.alerts;
+
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.quartz.JobExecutionContext;
+
+import org.ametys.core.schedule.Schedulable;
+import org.ametys.plugins.core.impl.schedule.AbstractStaticSchedulable;
+import org.ametys.runtime.config.Config;
+
+/**
+ * A {@link Schedulable} job that looks at the contents and computes if they need to have some email alerts sent.
+ */
+public class AlertEngineSchedulable extends AbstractStaticSchedulable
+{
+ /** The service manager */
+ protected ServiceManager _manager;
+ /** The helper for the alerts on contents */
+ protected ContentAlertHelper _contentAlertHelper;
+
+ @Override
+ public void service(ServiceManager manager) throws ServiceException
+ {
+ super.service(manager);
+ _manager = manager;
+ }
+
+ @Override
+ public void execute(JobExecutionContext context) throws Exception
+ {
+ if (_contentAlertHelper == null)
+ {
+ // Delayed initialize because of circular dependency
+ _delayedInitializeAlertHelper();
+ }
+
+ if (Config.getInstance().getValueAsBoolean("remind.content.enabled"))
+ {
+ _contentAlertHelper.sendAlerts();
+ }
+ }
+
+ private void _delayedInitializeAlertHelper() throws ServiceException
+ {
+ _contentAlertHelper = (ContentAlertHelper) _manager.lookup(ContentAlertHelper.ROLE);
+ }
+}
Index: main/plugin-cms/src/org/ametys/cms/alerts/AlertScheduler.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/AlertScheduler.java (revision 42093)
+++ main/plugin-cms/src/org/ametys/cms/alerts/AlertScheduler.java (working copy)
@@ -1,239 +0,0 @@
-/*
- * Copyright 2014 Anyware Services
- *
- * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
- */
-package org.ametys.cms.alerts;
-
-import java.util.Calendar;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.apache.avalon.framework.activity.Disposable;
-import org.apache.avalon.framework.activity.Initializable;
-import org.apache.avalon.framework.component.Component;
-import org.apache.avalon.framework.configuration.Configurable;
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-import org.apache.avalon.framework.context.Context;
-import org.apache.avalon.framework.context.ContextException;
-import org.apache.avalon.framework.context.Contextualizable;
-import org.apache.avalon.framework.logger.LogEnabled;
-import org.apache.avalon.framework.logger.Logger;
-import org.apache.avalon.framework.service.ServiceException;
-import org.apache.avalon.framework.service.ServiceManager;
-import org.apache.avalon.framework.service.Serviceable;
-import org.apache.cocoon.environment.Request;
-import org.apache.commons.lang.StringUtils;
-
-import org.ametys.runtime.config.Config;
-
-/**
- * Alerts scheduler: launches a cron which sends the alerts each night.
- */
-public class AlertScheduler extends TimerTask implements Initializable, LogEnabled, Serviceable, Disposable, Contextualizable, Configurable, Component
-{
- /** The Avalon role */
- public static final String ROLE = AlertScheduler.class.getName();
-
- /** The service manager. */
- protected ServiceManager _manager;
-
- /** The component configuration. */
- protected Configuration _configuration;
-
- /** The avalon context. */
- protected Context _context;
-
- /** The logger. */
- protected Logger _logger;
-
- /** The timer. */
- protected Timer _timer;
-
- @Override
- public void service(ServiceManager manager) throws ServiceException
- {
- _manager = manager;
- }
-
- @Override
- public void contextualize(Context context) throws ContextException
- {
- _context = context;
- }
-
- @Override
- public void configure(Configuration configuration) throws ConfigurationException
- {
- _configuration = configuration;
- }
-
- @Override
- public void enableLogging(Logger logger)
- {
- _logger = logger;
- }
-
- @Override
- public void initialize() throws Exception
- {
- if (!Config.getInstance().getValueAsBoolean("remind.content.enabled"))
- {
- return;
- }
-
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Initializing the alert scheduler...");
- }
-
- // Schedule a timer to run each night.
- String hourStr = Config.getInstance().getValueAsString("alerts.scheduler.hour");
- int hour = 0;
- int minute = 0;
- if (StringUtils.isNotEmpty(hourStr) && hourStr.indexOf(':') > 0)
- {
- String[] hourArray = StringUtils.split(hourStr, ':');
- hour = Integer.parseInt(hourArray[0]);
- minute = Integer.parseInt(hourArray[1]);
- }
-
- GregorianCalendar calendar = new GregorianCalendar();
- calendar.set(Calendar.AM_PM, hour < 12 ? Calendar.AM : Calendar.PM);
- calendar.set(Calendar.HOUR, hour % 12);
- calendar.set(Calendar.MINUTE, minute);
- calendar.set(Calendar.SECOND, 0);
- calendar.set(Calendar.MILLISECOND, 0);
-
- // Each day.
- long period = 86400000;
- Date firstTime = calendar.getTime();
-
- Date now = new Date();
-
- // If the given time today is past, schedule for tomorrow.
- if (firstTime.compareTo(now) < 0)
- {
- calendar.add(Calendar.DAY_OF_MONTH, 1);
- firstTime = calendar.getTime();
- }
-
- if (_logger.isInfoEnabled())
- {
- _logger.info("Alerts scheduler: the alerts engine will run each day, starting " + firstTime.toString());
- }
-
- _timer = new Timer("AlertsScheduler", true);
- _timer.schedule(this, firstTime, period);
- }
-
- @Override
- public void run()
- {
- AlertEngine alertEngine = new AlertEngine();
-
- try
- {
- // Initialize and configure the engine.
- alertEngine.initialize(_manager, _context);
- alertEngine.configure(_configuration);
- }
- catch (Exception e)
- {
- throw new RuntimeException("Unable to initialize the alerts engine", e);
- }
-
- // The thread will be started as daemon, as the scheduler is marked daemon itself.
- new Thread(alertEngine, "AlertEngine").start();
- }
-
- /**
- * Run the scheduler to send instant alerts on contents
- * @param contentIds The ids of concerned contents
- * @param message the message to send to authorized users
- */
- public void sendInstantAlerts (List contentIds, String message)
- {
- AlertEngine alertEngine = new AlertEngine(contentIds, message);
-
- try
- {
- // Initialize and configure the engine.
- alertEngine.initialize(_manager, _context);
- alertEngine.configure(_configuration);
- }
- catch (Exception e)
- {
- throw new RuntimeException("Unable to initialize the alerts engine", e);
- }
-
- // The thread will be started as daemon, as the scheduler is marked daemon itself.
- new Thread(alertEngine, "AlertEngine").start();
- }
-
- /**
- * Get the request URI.
- * @param request the request object.
- * @return the full request URI.
- */
- protected String _getRequestURI(Request request)
- {
- StringBuilder sb = new StringBuilder();
- sb.append(request.getScheme());
- sb.append("://");
- sb.append(request.getServerName());
-
- // Construire une uri sans :80 en http et sans :443 en https
- if (request.isSecure())
- {
- if (request.getServerPort() != 443)
- {
- sb.append(":");
- sb.append(request.getServerPort());
- }
- }
- else
- {
- if (request.getServerPort() != 80)
- {
- sb.append(":");
- sb.append(request.getServerPort());
- }
- }
-
- sb.append(request.getContextPath());
-
- return sb.toString();
- }
-
- @Override
- public void dispose()
- {
- _context = null;
- _logger = null;
- _manager = null;
- _configuration = null;
-
- cancel();
- if (_timer != null)
- {
- _timer.cancel();
- _timer = null;
- }
- }
-
-}
Index: main/plugin-cms/src/org/ametys/cms/alerts/AlertsConstants.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/AlertsConstants.java (revision 42093)
+++ main/plugin-cms/src/org/ametys/cms/alerts/AlertsConstants.java (working copy)
@@ -33,15 +33,6 @@
/** The name of the metadata storing when the "unmodified content" alert was last sent. */
public static final String UNMODIFIED_ALERT_LAST_DATE = "unmodifiedAlertLastDate";
- /** The name of the metadata storing whether the reminder is enabled. */
- public static final String REMINDER_ENABLED = "reminderEnabled";
-
- /** The name of the metadata storing the reminder date. */
- public static final String REMINDER_DATE = "reminderDate";
-
- /** The name of the metadata storing the reminder text. */
- public static final String REMINDER_TEXT = "reminderText";
-
/** The name of the metadata storing when the "scheduled archiving" alert was last sent. */
public static final String SCHEDULED_ARCHIVING_REMINDER_LAST_DATE = "scheduledArchivingLastDate";
Index: main/plugin-cms/src/org/ametys/cms/alerts/ContentAlertHelper.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/ContentAlertHelper.java (revision 0)
+++ main/plugin-cms/src/org/ametys/cms/alerts/ContentAlertHelper.java (revision 0)
@@ -0,0 +1,826 @@
+/*
+ * Copyright 2016 Anyware Services
+ *
+ * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
+ */
+package org.ametys.cms.alerts;
+
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.mail.MessagingException;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.component.Component;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.context.Context;
+import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.context.Contextualizable;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.commons.lang.StringUtils;
+import org.quartz.JobKey;
+import org.quartz.SchedulerException;
+
+import org.ametys.cms.content.archive.ArchiveConstants;
+import org.ametys.cms.repository.Content;
+import org.ametys.cms.repository.ContentQueryHelper;
+import org.ametys.cms.repository.ModifiableContent;
+import org.ametys.cms.repository.WorkflowStepExpression;
+import org.ametys.cms.repository.WorkflowStepExpression.LogicalOperator;
+import org.ametys.core.right.RightsManager;
+import org.ametys.core.user.User;
+import org.ametys.core.user.UserIdentity;
+import org.ametys.core.user.UserManager;
+import org.ametys.core.util.I18nUtils;
+import org.ametys.core.util.mail.SendMailHelper;
+import org.ametys.plugins.core.schedule.Scheduler;
+import org.ametys.plugins.repository.AmetysObjectIterable;
+import org.ametys.plugins.repository.AmetysObjectResolver;
+import org.ametys.plugins.repository.AmetysRepositoryException;
+import org.ametys.plugins.repository.metadata.CompositeMetadata;
+import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
+import org.ametys.plugins.repository.query.expression.AndExpression;
+import org.ametys.plugins.repository.query.expression.BooleanExpression;
+import org.ametys.plugins.repository.query.expression.DateExpression;
+import org.ametys.plugins.repository.query.expression.Expression;
+import org.ametys.plugins.repository.query.expression.Expression.Operator;
+import org.ametys.plugins.repository.query.expression.MetadataExpression;
+import org.ametys.plugins.repository.query.expression.NotExpression;
+import org.ametys.plugins.repository.query.expression.OrExpression;
+import org.ametys.plugins.repository.version.MetadataAndVersionAwareAmetysObject;
+import org.ametys.plugins.repository.version.ModifiableMetadataAwareVersionableAmetysObject;
+import org.ametys.runtime.config.Config;
+import org.ametys.runtime.i18n.I18nizableText;
+import org.ametys.runtime.plugin.component.AbstractLogEnabled;
+
+/**
+ * Helper for content alerts.
+ */
+public class ContentAlertHelper extends AbstractLogEnabled implements Component, Serviceable, Configurable, Initializable, Contextualizable, Disposable
+{
+ /** The Avalon role */
+ public static final String ROLE = ContentAlertHelper.class.getName();
+
+ /** The avalon context. */
+ protected Context _context;
+ /** The ametys object resolver. */
+ protected AmetysObjectResolver _ametysResolver;
+ /** The right manager. */
+ protected RightsManager _rightManager;
+ /** The user manager. */
+ protected UserManager _userManager;
+ /** The i18n utils. */
+ protected I18nUtils _i18nUtils;
+ /** The scheduler */
+ protected Scheduler _scheduler;
+
+ /** The reminder e-mail will be sent to users that have this at least one of this rights. */
+ protected Set _reminderRights;
+ /** The reminder e-mail subject i18n key. */
+ protected String _reminderSubject;
+ /** The reminder e-mail body i18n key. */
+ protected String _reminderBody;
+
+ /** The instant alert e-mail will be sent to users that have this at least one of this rights. */
+ protected Set _instantAlertRights;
+ /** The instant alert e-mail subject i18n key. */
+ protected String _instantAlertSubject;
+ /** The instant alert e-mail body i18n key. */
+ protected String _instantAlertBody;
+
+ /** The "waiting for validation" e-mail will be sent to users that have at least one of this rights. */
+ protected Set _awaitingValidationRights;
+ /** The "waiting for validation" e-mail subject i18n key. */
+ protected String _awaitingValidationSubject;
+ /** The "waiting for validation" e-mail body i18n key. */
+ protected String _awaitingValidationBody;
+
+ /** Only contents in this steps will be taken into account for the "unmodified content" alert. */
+ protected int[] _unmodifiedContentStepIds;
+ /** The "unmodified content" e-mail will be sent to users that have at least one of this rights. */
+ protected Set _unmodifiedContentRights;
+ /** The "unmodified content" e-mail subject i18n key. */
+ protected String _unmodifiedContentSubject;
+ /** The "unmodified content" e-mail body i18n key. */
+ protected String _unmodifiedContentBody;
+
+ /** The scheduled archiving reminder e-mail will be sent to users that have this at least one of this rights. */
+ protected Set _scheduledArchivingReminderRights;
+ /** The scheduled archiving reminder e-mail subject i18n key. */
+ protected String _scheduledArchivingReminderSubject;
+ /** The scheduled archiving reminder e-mail body i18n key. */
+ protected String _scheduledArchivingReminderBody;
+
+ /** The server base URL. */
+ protected String _baseUrl;
+ /** The content of "from" field in emails. */
+ protected String _mailFrom;
+
+ @Override
+ public void configure(Configuration configuration) throws ConfigurationException
+ {
+ Configuration instantConf = configuration.getChild("instantAlert");
+ Configuration validationConf = configuration.getChild("awaitingValidation");
+ Configuration unmodifiedConf = configuration.getChild("unmodifiedContent");
+ Configuration reminderConf = configuration.getChild("reminder");
+ Configuration scheduledArchivingReminderConf = configuration.getChild("scheduledArchiving");
+
+ // Configure the rights.
+ _instantAlertRights = _getRightsFromConf(instantConf);
+ _awaitingValidationRights = _getRightsFromConf(validationConf);
+ _unmodifiedContentRights = _getRightsFromConf(unmodifiedConf);
+ _reminderRights = _getRightsFromConf(reminderConf);
+ _scheduledArchivingReminderRights = _getRightsFromConf(scheduledArchivingReminderConf);
+ Configuration[] stepIds = unmodifiedConf.getChildren("stepId");
+ _unmodifiedContentStepIds = new int[stepIds.length];
+ int i = 0;
+ for (Configuration stepId : stepIds)
+ {
+ try
+ {
+ _unmodifiedContentStepIds[i] = Integer.parseInt(stepId.getValue(""));
+ i++;
+ }
+ catch (NumberFormatException e)
+ {
+ // Ignore
+ }
+ }
+
+ // Configure the i18n texts.
+ _awaitingValidationSubject = validationConf.getChild("subjectKey").getValue();
+ _awaitingValidationBody = validationConf.getChild("bodyKey").getValue();
+ _unmodifiedContentSubject = unmodifiedConf.getChild("subjectKey").getValue();
+ _unmodifiedContentBody = unmodifiedConf.getChild("bodyKey").getValue();
+ _reminderSubject = reminderConf.getChild("subjectKey").getValue();
+ _reminderBody = reminderConf.getChild("bodyKey").getValue();
+ _scheduledArchivingReminderSubject = scheduledArchivingReminderConf.getChild("subjectKey").getValue();
+ _scheduledArchivingReminderBody = scheduledArchivingReminderConf.getChild("bodyKey").getValue();
+ _instantAlertSubject = instantConf.getChild("subjectKey").getValue();
+ _instantAlertBody = instantConf.getChild("bodyKey").getValue();
+ }
+
+ /**
+ * Get a set of rights from a configuration.
+ * @param configuration the configuration.
+ * @return the set of rights.
+ * @throws ConfigurationException if the configuration is not valid.
+ */
+ protected Set _getRightsFromConf(Configuration configuration) throws ConfigurationException
+ {
+ Set rights = new HashSet<>();
+
+ for (Configuration rightConf : configuration.getChildren("right"))
+ {
+ String right = rightConf.getValue("");
+ if (StringUtils.isNotBlank(right))
+ {
+ rights.add(right);
+ }
+ }
+
+ return rights;
+ }
+
+ @Override
+ public void service(ServiceManager manager) throws ServiceException
+ {
+ _ametysResolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
+ _rightManager = (RightsManager) manager.lookup(RightsManager.ROLE);
+ _userManager = (UserManager) manager.lookup(UserManager.ROLE);
+ _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
+ _scheduler = (Scheduler) manager.lookup(Scheduler.ROLE);
+ }
+
+ @Override
+ public void contextualize(Context context) throws ContextException
+ {
+ _context = context;
+ }
+
+ @Override
+ public void initialize() throws Exception
+ {
+ _baseUrl = StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValueAsString("cms.url"), "index.html"), "/");
+ _mailFrom = Config.getInstance().getValueAsString("smtp.mail.from");
+ }
+
+ @Override
+ public void dispose()
+ {
+ _ametysResolver = null;
+ _rightManager = null;
+ _userManager = null;
+
+ _context = null;
+ }
+
+ /**
+ * Send instant alerts on contents
+ * @param contentIds The content ids
+ * @param message The email message
+ * @throws AmetysRepositoryException if an error occurred
+ */
+ public void sendInstantAlerts(List contentIds, String message)
+ {
+ if (contentIds != null && !contentIds.isEmpty())
+ {
+ for (String contentId : contentIds)
+ {
+ Content content = _ametysResolver.resolveById(contentId);
+ _scheduleInstantAlertEmail(content, message);
+ }
+ }
+ }
+
+ /**
+ * Schedule the sending of a reminder e-mail to all the users who have the right to edit.
+ * @param content the content about which to send the reminder.
+ * @param reminderText The text included in the mail
+ * @param date The date when the mail will be sent
+ */
+ public void scheduleReminderEmail(Content content, String reminderText, ZonedDateTime date)
+ {
+ String context = _getContentContext(content);
+
+ Set users = new HashSet<>();
+ for (String right : _reminderRights)
+ {
+ users.addAll(_rightManager.getGrantedUsers(right, context));
+ }
+
+ List params = _getReminderParams(content, reminderText);
+
+ I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_reminderSubject, content), params);
+ I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_reminderBody, content), params);
+
+ String subject = _i18nUtils.translate(i18nSubject);
+ String body = _i18nUtils.translate(i18nBody);
+
+ org.ametys.core.schedule.Runnable reminderContentAlertRunnable = new ReminderContentAlertRunnable(content.getId(), content.getName(), _mailFrom, _getMails(users), subject, body, date, reminderText);
+ try
+ {
+ JobKey jobKey = new JobKey(reminderContentAlertRunnable.getId(), Scheduler.JOB_GROUP);
+ if (_scheduler.getScheduler().checkExists(jobKey))
+ {
+ _scheduler.getScheduler().deleteJob(jobKey);
+ }
+ _scheduler.scheduleJob(reminderContentAlertRunnable);
+ }
+ catch (SchedulerException e)
+ {
+ if (getLogger().isErrorEnabled())
+ {
+ getLogger().error("An error occured when trying to schedule the reminder alert of the content " + content.getId(), e);
+ }
+ }
+ }
+
+ /**
+ * Unschedule the sending of a reminder email
+ * @param content the content concerned by the alert
+ */
+ public void unscheduleReminderEmail(Content content)
+ {
+ try
+ {
+ JobKey jobKey = new JobKey(ReminderContentAlertRunnable.ID_PREFIX + content.getId(), Scheduler.JOB_GROUP);
+ if (_scheduler.getScheduler().checkExists(jobKey))
+ {
+ _scheduler.getScheduler().deleteJob(jobKey);
+ }
+ }
+ catch (SchedulerException e)
+ {
+ if (getLogger().isErrorEnabled())
+ {
+ getLogger().error("An error occured when trying to unschedule the reminder alert of the content " + content.getId(), e);
+ }
+ }
+ }
+
+ /**
+ * Schedule the sending if an instant e-mail alert to all the users who have the right to edit the content.
+ * @param content the content about which to send the alert.
+ * @param message the message
+ */
+ protected void _scheduleInstantAlertEmail(Content content, String message)
+ {
+ String context = _getContentContext(content);
+
+ Set users = new HashSet<>();
+ for (String right : _instantAlertRights)
+ {
+ users.addAll(_rightManager.getGrantedUsers(right, context));
+ }
+
+ List params = _getInstantAlertParams(content, message);
+
+ I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_instantAlertSubject, content), params);
+ I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_instantAlertBody, content), params);
+
+ String subject = _i18nUtils.translate(i18nSubject);
+ String body = _i18nUtils.translate(i18nBody);
+
+ org.ametys.core.schedule.Runnable instantContentAlertRunnable = new InstantContentAlertRunnable(content.getId(), content.getName(), _mailFrom, _getMails(users), subject, body);
+ try
+ {
+ JobKey jobKey = new JobKey(instantContentAlertRunnable.getId(), Scheduler.JOB_GROUP);
+ if (_scheduler.getScheduler().checkExists(jobKey))
+ {
+ _scheduler.getScheduler().deleteJob(jobKey);
+ }
+ _scheduler.scheduleJob(instantContentAlertRunnable);
+ }
+ catch (SchedulerException e)
+ {
+ if (getLogger().isErrorEnabled())
+ {
+ getLogger().error("An error occured when trying to schedule the instant alert of the content " + content.getId(), e);
+ }
+ }
+ }
+
+ private String _getMails(Set users)
+ {
+ StringBuilder mails = new StringBuilder();
+ for (UserIdentity identity : users)
+ {
+ User user = _userManager.getUser(identity.getPopulationId(), identity.getLogin());
+
+ if (user != null && StringUtils.isNotBlank(user.getEmail()))
+ {
+ if (mails.length() != 0)
+ {
+ mails.append("\\n");
+ }
+ mails.append(user.getEmail());
+ }
+ }
+
+ return mails.toString();
+ }
+
+ /**
+ * Get the mail parameters.
+ * @param content the content.
+ * @param reminderText The reminder text
+ * @return the parameters.
+ */
+ protected List _getReminderParams(Content content, String reminderText)
+ {
+ List params = new ArrayList<>();
+
+ params.add(content.getTitle()); // {0}
+ params.add(_getContentUrl(content)); // {1}
+ params.add(reminderText); // {2}
+
+ return params;
+ }
+
+ /**
+ * Send all the alerts that cannot be a Runnable themselves (for example, the instant and reminder alerts are not sent through this call). Can be overridden to add alerts.
+ * @throws AmetysRepositoryException if an error occurs.
+ */
+ public void sendAlerts() throws AmetysRepositoryException
+ {
+ _sendAwaitingValidationAlerts();
+ _sendUnmodifiedAlerts();
+ _sendScheduledArchivingReminders();
+ }
+
+ /**
+ * Send the "awaiting validation" alerts.
+ * @throws AmetysRepositoryException if an error occurs.
+ */
+ protected void _sendAwaitingValidationAlerts() throws AmetysRepositoryException
+ {
+ Long delay = Config.getInstance().getValueAsLong("remind.content.validation.delay");
+ if (delay != null && delay > 0)
+ {
+ Calendar calendar = new GregorianCalendar();
+ _removeTimeParts(calendar);
+ calendar.add(Calendar.DAY_OF_MONTH, 1 - delay.intValue());
+
+ // No last date and X days after the proposal date.
+ Expression noLastDateExpr = new NotExpression(new MetadataExpression(AlertsConstants.AWAITING_VALIDATION_ALERT_LAST_DATE, true));
+ Expression waitingExpression = new DateExpression("proposalDate", Operator.LT, calendar.getTime(), true);
+ // Or proposal date before the last "awaiting validation" date and the and X days after the last "awaiting validation" date.
+ Expression proposalBeforeLastDateExpr = new BinaryExpression("proposalDate", true, Operator.LT, AlertsConstants.AWAITING_VALIDATION_ALERT_LAST_DATE, true);
+ Expression lastDateExpr = new DateExpression(AlertsConstants.AWAITING_VALIDATION_ALERT_LAST_DATE, Operator.LT, calendar.getTime(), true);
+ Expression expression = new OrExpression(new AndExpression(noLastDateExpr, waitingExpression),
+ new AndExpression(proposalBeforeLastDateExpr, lastDateExpr));
+
+ String query = ContentQueryHelper.getContentXPathQuery(expression);
+
+
+
+ try (AmetysObjectIterable contents = _ametysResolver.query(query))
+ {
+ if (getLogger().isInfoEnabled())
+ {
+ getLogger().info("Contents waiting for validation: " + contents.getSize());
+ }
+
+ for (ModifiableContent content : contents)
+ {
+ // Send the alert e-mails.
+ _sendAwaitingValidationEmail(content);
+
+ // Set the last validation alert date to now.
+ ModifiableCompositeMetadata meta = ((ModifiableMetadataAwareVersionableAmetysObject) content).getUnversionedMetadataHolder();
+ meta.setMetadata(AlertsConstants.AWAITING_VALIDATION_ALERT_LAST_DATE, new Date());
+
+ content.saveChanges();
+ }
+ }
+ }
+ }
+
+ /**
+ * Send the unmodified content alerts.
+ * @throws AmetysRepositoryException if an error occurs.
+ */
+ protected void _sendUnmodifiedAlerts() throws AmetysRepositoryException
+ {
+ Long delay = Config.getInstance().getValueAsLong("remind.unmodified.content.delay");
+ if (delay != null && delay > 0)
+ {
+ Calendar calendar = new GregorianCalendar();
+ _removeTimeParts(calendar);
+ calendar.add(Calendar.DAY_OF_MONTH, 1 - delay.intValue());
+
+ // If no step is configured, stepExpr will return the empty string.
+ Expression stepExpr = new WorkflowStepExpression(Operator.EQ, _unmodifiedContentStepIds, LogicalOperator.OR);
+ // Get only the contents on which the alert is enabled.
+ Expression unmodifiedExpr = new BooleanExpression(AlertsConstants.UNMODIFIED_ALERT_ENABLED, true, true);
+ // No last date and X days after the proposal date, or X days after the last date.
+ Expression noLastDateExpr = new NotExpression(new MetadataExpression(AlertsConstants.UNMODIFIED_ALERT_LAST_DATE, true));
+ Expression lastModifiedExpression = new DateExpression("lastModified", Operator.LT, calendar.getTime());
+ Expression lastDateExpr = new DateExpression(AlertsConstants.UNMODIFIED_ALERT_LAST_DATE, Operator.LT, calendar.getTime(), true);
+ Expression dateExpr = new OrExpression(new AndExpression(noLastDateExpr, lastModifiedExpression), lastDateExpr);
+ // Full AND expression.
+ Expression expression = new AndExpression(unmodifiedExpr, dateExpr, stepExpr);
+
+ String query = ContentQueryHelper.getContentXPathQuery(expression);
+
+ try (AmetysObjectIterable contents = _ametysResolver.query(query))
+ {
+ if (getLogger().isInfoEnabled())
+ {
+ getLogger().info("Contents not modified for " + delay + " days: " + contents.getSize());
+ }
+
+ for (ModifiableContent content : contents)
+ {
+ // Send the alert e-mail.
+ _sendUnmodifiedContentEmail(content);
+
+ // Set the last unmodified alert date to now.
+ ModifiableCompositeMetadata meta = ((ModifiableMetadataAwareVersionableAmetysObject) content).getUnversionedMetadataHolder();
+ meta.setMetadata(AlertsConstants.UNMODIFIED_ALERT_LAST_DATE, new Date());
+
+ content.saveChanges();
+ }
+ }
+ }
+ }
+
+ /**
+ * Send the scheduled archiving reminders on contents.
+ * @throws AmetysRepositoryException if an error occurs.
+ */
+ protected void _sendScheduledArchivingReminders() throws AmetysRepositoryException
+ {
+ Long delay = Config.getInstance().getValueAsLong("archive.scheduler.reminder.delay");
+ if (delay != null && delay > 0)
+ {
+ Calendar calendar = new GregorianCalendar();
+ _removeTimeParts(calendar);
+ calendar.add(Calendar.DAY_OF_MONTH, delay.intValue());
+
+ // No last date and X days before the scheduled date.
+ Expression noLastDateExpr = new NotExpression(new MetadataExpression(AlertsConstants.SCHEDULED_ARCHIVING_REMINDER_LAST_DATE, true));
+ Expression scheduledDelayExpression = new DateExpression(ArchiveConstants.META_ARCHIVE_SCHEDULED_DATE, Operator.LE, calendar.getTime(), true);
+ Expression expression = new AndExpression(noLastDateExpr, scheduledDelayExpression);
+
+ String query = ContentQueryHelper.getContentXPathQuery(expression);
+
+ try (AmetysObjectIterable contents = _ametysResolver.query(query))
+ {
+ if (getLogger().isInfoEnabled())
+ {
+ getLogger().info("Contents with scheduled archiving reminder today: " + contents.getSize());
+ }
+
+ for (ModifiableContent content : contents)
+ {
+ _sendScheduledArchivingReminderEmail(content);
+
+ // Set the last scheduled archiving reminder date to now.
+ ModifiableCompositeMetadata meta = ((ModifiableMetadataAwareVersionableAmetysObject) content).getUnversionedMetadataHolder();
+ meta.setMetadata(AlertsConstants.SCHEDULED_ARCHIVING_REMINDER_LAST_DATE, new Date());
+
+ content.saveChanges();
+ }
+ }
+ }
+ }
+
+ /**
+ * Send a "waiting for validation" e-mail alert to all the users who have the right to validate.
+ * @param content the content about which to send the alert.
+ * @throws AmetysRepositoryException if an error occured on the repository
+ */
+ protected void _sendAwaitingValidationEmail(Content content) throws AmetysRepositoryException
+ {
+ String context = _getContentContext(content);
+
+ Set users = new HashSet<>();
+ for (String right : _awaitingValidationRights)
+ {
+ users.addAll(_rightManager.getGrantedUsers(right, context));
+ }
+
+ List params = _getAwaitingValidationParams(content);
+
+ I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_awaitingValidationSubject, content), params);
+ I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_awaitingValidationBody, content), params);
+
+ String subject = _i18nUtils.translate(i18nSubject);
+ String body = _i18nUtils.translate(i18nBody);
+
+ _sendMails(subject, body, users, _mailFrom);
+ }
+
+ /**
+ * Send a "unmodified content" e-mail alert to all the users who have the right to edit.
+ * @param content the content about which to send the alert.
+ * @throws AmetysRepositoryException if an error occured on the repository
+ */
+ protected void _sendUnmodifiedContentEmail(Content content) throws AmetysRepositoryException
+ {
+ String context = _getContentContext(content);
+
+ Set users = new HashSet<>();
+ for (String right : _unmodifiedContentRights)
+ {
+ users.addAll(_rightManager.getGrantedUsers(right, context));
+ }
+
+ List params = _getUnmodifiedContentParams(content);
+
+ I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_unmodifiedContentSubject, content), params);
+ I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_unmodifiedContentBody, content), params);
+
+ String subject = _i18nUtils.translate(i18nSubject);
+ String body = _i18nUtils.translate(i18nBody);
+
+ _sendMails(subject, body, users, _mailFrom);
+ }
+
+ /**
+ * Send a "scheduled archiving reminder" e-mail to all the users who have the right to archive.
+ * @param content the content about which to send the alert.
+ * @throws AmetysRepositoryException if an error occured on the repository
+ */
+ protected void _sendScheduledArchivingReminderEmail(ModifiableContent content) throws AmetysRepositoryException
+ {
+ String context = _getContentContext(content);
+
+ Set users = new HashSet<>();
+ for (String right : _scheduledArchivingReminderRights)
+ {
+ users.addAll(_rightManager.getGrantedUsers(right, context));
+ }
+
+ List params = _getScheduledArchivingReminderParams(content);
+
+ I18nizableText i18nSubject = new I18nizableText(null, getI18nKeyBody(_scheduledArchivingReminderSubject, content), params);
+ I18nizableText i18nBody = new I18nizableText(null, getI18nKeyBody(_scheduledArchivingReminderBody, content), params);
+
+ String subject = _i18nUtils.translate(i18nSubject);
+ String body = _i18nUtils.translate(i18nBody);
+
+ _sendMails(subject, body, users, _mailFrom);
+ }
+
+ /**
+ * Get the transform i18n body key for specific content
+ * @param bodyI18nKey the original body key
+ * @param content the content
+ * @return the transform i18n body key
+ */
+ protected String getI18nKeyBody(String bodyI18nKey, Content content)
+ {
+ return bodyI18nKey;
+ }
+
+ /**
+ * Get the mail parameters for instant alert.
+ * @param content the content.
+ * @param message the message
+ * @return the parameters.
+ */
+ protected List _getInstantAlertParams(Content content, String message)
+ {
+ List params = new ArrayList<>();
+
+ params.add(content.getTitle()); // {0}
+ params.add(_getContentUrl(content)); // {1}
+ params.add(message); // {2}
+
+ return params;
+ }
+
+ /**
+ * Get the mail parameters.
+ * @param content the content.
+ * @return the parameters.
+ */
+ protected List _getAwaitingValidationParams(Content content)
+ {
+ List params = new ArrayList<>();
+
+ String delay = Config.getInstance().getValueAsString("remind.content.validation.delay");
+
+ params.add(content.getTitle()); // {0}
+ params.add(_getContentUrl(content)); // {1}
+ params.add(delay); // {2}
+
+ return params;
+ }
+
+ /**
+ * Get the mail parameters.
+ * @param content the content.
+ * @return the parameters.
+ */
+ protected List _getUnmodifiedContentParams(Content content)
+ {
+ List params = new ArrayList<>();
+
+ String delay = Config.getInstance().getValueAsString("remind.unmodified.content.delay");
+
+ params.add(content.getTitle()); // {0}
+ params.add(_getContentUrl(content)); // {1}
+ params.add(delay); // {2}
+
+ CompositeMetadata meta = ((MetadataAndVersionAwareAmetysObject) content).getUnversionedMetadataHolder();
+ String alertText = meta.getString(AlertsConstants.UNMODIFIED_ALERT_TEXT, "");
+ params.add(alertText); // {3}
+
+ return params;
+ }
+
+ /**
+ * Get the mail parameters.
+ * @param content the content.
+ * @return the parameters.
+ */
+ protected List _getScheduledArchivingReminderParams(ModifiableContent content)
+ {
+ List params = new ArrayList<>();
+
+ String delay = Config.getInstance().getValueAsString("archive.scheduler.reminder.delay");
+
+ params.add(content.getTitle()); // {0}
+ params.add(_getContentUrl(content)); // {1}
+ params.add(delay); // {2}
+
+ return params;
+ }
+
+ /**
+ * Send the alert emails.
+ * @param subject the e-mail subject.
+ * @param body the e-mail body.
+ * @param users users to send the mail to.
+ * @param from the address sending the e-mail.
+ */
+ protected void _sendMails(String subject, String body, Set users, String from)
+ {
+ for (UserIdentity identity : users)
+ {
+ User user = _userManager.getUser(identity.getPopulationId(), identity.getLogin());
+
+ if (user != null && StringUtils.isNotBlank(user.getEmail()))
+ {
+ String mail = user.getEmail();
+
+ try
+ {
+ SendMailHelper.sendMail(subject, null, body, mail, from);
+ }
+ catch (MessagingException e)
+ {
+ if (getLogger().isWarnEnabled())
+ {
+ getLogger().warn("Could not send an alert e-mail to " + mail, e);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the rights context on the given content.
+ * @param content the content.
+ * @return the rights context.
+ * @throws AmetysRepositoryException if an error occured on the repository
+ */
+ protected String _getContentContext(Content content) throws AmetysRepositoryException
+ {
+ return "/contents/" + content.getName();
+ }
+
+ /**
+ * Get the URL to the given content tool.
+ * @param content the content.
+ * @return the content URL.
+ */
+ protected String _getContentUrl(Content content)
+ {
+ StringBuilder url = new StringBuilder(_baseUrl);
+ url.append("/index.html?uitool=uitool-content,id:%27").append(content.getId()).append("%27");
+
+ return url.toString();
+ }
+
+ /**
+ * Remove the time parts from a calendar, leaving only date parts.
+ * @param calendar the calendar.
+ */
+ protected void _removeTimeParts(Calendar calendar)
+ {
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ }
+
+ /**
+ * Binary date expression: test on two metadatas.
+ */
+ protected class BinaryExpression implements Expression
+ {
+ private MetadataExpression _metadata1;
+ private MetadataExpression _metadata2;
+ private Operator _operator;
+
+ /**
+ * Creates the comparison Expression.
+ * @param metadata1 the first metadata name.
+ * @param operator the operator to make the comparison
+ * @param metadata2 the second metadata name.
+ */
+ public BinaryExpression(String metadata1, Operator operator, String metadata2)
+ {
+ _metadata1 = new MetadataExpression(metadata1);
+ _operator = operator;
+ _metadata2 = new MetadataExpression(metadata2);
+ }
+
+ /**
+ * Creates the comparison Expression.
+ * @param metadata1 the first metadata name.
+ * @param unversioned1 true if the first metadata is unversioned.
+ * @param operator the operator to make the comparison.
+ * @param metadata2 the second metadata name.
+ * @param unversioned2 true if the second metadata is unversioned.
+ */
+ public BinaryExpression(String metadata1, boolean unversioned1, Operator operator, String metadata2, boolean unversioned2)
+ {
+ _metadata1 = new MetadataExpression(metadata1, unversioned1);
+ _operator = operator;
+ _metadata2 = new MetadataExpression(metadata2, unversioned2);
+ }
+
+ @Override
+ public String build()
+ {
+ return _metadata1.build() + " " + _operator + " " + _metadata2.build();
+ }
+ }
+}
Index: main/plugin-cms/src/org/ametys/cms/alerts/ContentAlertsClientSideElement.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/ContentAlertsClientSideElement.java (revision 42093)
+++ main/plugin-cms/src/org/ametys/cms/alerts/ContentAlertsClientSideElement.java (working copy)
@@ -15,12 +15,12 @@
*/
package org.ametys.cms.alerts;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -28,12 +28,16 @@
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.commons.lang.StringUtils;
+import org.quartz.JobDataMap;
+import org.quartz.JobKey;
+import org.quartz.SchedulerException;
import org.ametys.cms.lock.LockContentManager;
import org.ametys.cms.repository.Content;
import org.ametys.cms.repository.ModifiableContent;
import org.ametys.core.ui.Callable;
import org.ametys.core.ui.StaticClientSideElement;
+import org.ametys.plugins.core.schedule.Scheduler;
import org.ametys.plugins.repository.AmetysObjectResolver;
import org.ametys.plugins.repository.AmetysRepositoryException;
import org.ametys.plugins.repository.lock.LockAwareAmetysObject;
@@ -50,7 +54,7 @@
public class ContentAlertsClientSideElement extends StaticClientSideElement
{
/** The date format. */
- protected static final DateFormat _DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+ protected static final String __CLIENT_DATE_FORMAT = "yyyy-MM-dd HH:mm";
/** Repository content. */
protected AmetysObjectResolver _resolver;
@@ -60,7 +64,13 @@
/** The service manager */
protected ServiceManager _smanager;
-
+
+ /** The content alert helper */
+ protected ContentAlertHelper _contentAlertHelper;
+
+ /** The scheduler */
+ protected Scheduler _scheduler;
+
@Override
public void service(ServiceManager serviceManager) throws ServiceException
{
@@ -68,6 +78,8 @@
_smanager = serviceManager;
_resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
_lockManager = (LockContentManager) serviceManager.lookup(LockContentManager.ROLE);
+ _contentAlertHelper = (ContentAlertHelper) serviceManager.lookup(ContentAlertHelper.ROLE);
+ _scheduler = (Scheduler) serviceManager.lookup(Scheduler.ROLE);
}
enum AlertsStatus
@@ -86,10 +98,11 @@
* Get information on reminders state.
* @param contentsId The list of contents' ids
* @return informations on reminders state.
+ * @throws SchedulerException if an error occurs
*/
@SuppressWarnings("unchecked")
@Callable
- public Map getAlertsInformations(List contentsId)
+ public Map getAlertsInformations(List contentsId) throws SchedulerException
{
Map results = new HashMap<>();
@@ -135,11 +148,14 @@
unmodifiedAlertStatus = AlertsStatus.MIXED;
}
- boolean reminderEnabled = meta.getBoolean(AlertsConstants.REMINDER_ENABLED, false);
+ JobKey jobKey = new JobKey(ReminderContentAlertRunnable.ID_PREFIX + contentId, Scheduler.JOB_GROUP);
+ boolean reminderEnabled = _scheduler.getScheduler().checkExists(jobKey);
if (reminderEnabled)
{
- String reminderDateStr = meta.getString(AlertsConstants.REMINDER_DATE, "");
- String reminderText = meta.getString(AlertsConstants.REMINDER_TEXT, "");
+ JobDataMap jobDataMap = _scheduler.getScheduler().getJobDetail(jobKey).getJobDataMap();
+ long reminderDate = jobDataMap.getLong(Scheduler.PARAM_VALUES_PREFIX + ReminderContentAlertRunnable.DATE_KEY);
+ String reminderDateStr = DateTimeFormatter.ofPattern(__CLIENT_DATE_FORMAT).format(ZonedDateTime.ofInstant(Instant.ofEpochMilli(reminderDate), ZoneId.systemDefault()));
+ String reminderText = jobDataMap.getString(Scheduler.PARAM_VALUES_PREFIX + ReminderContentAlertRunnable.REMINDER_TEXT_KEY);
results.put("reminderDate", reminderDateStr);
results.put("reminderText", reminderText);
@@ -257,20 +273,14 @@
for (String contentId : contentIds)
{
Content content = _resolver.resolveById(contentId);
- if (content instanceof ModifiableMetadataAwareVersionableAmetysObject)
- {
- _setAlerts((ModifiableMetadataAwareVersionableAmetysObject) content, params);
- }
+ _setAlerts(content, params);
}
- String role = params.containsKey("role") ? (String) params.get("role") : AlertScheduler.ROLE;
- AlertScheduler alertScheduler = (AlertScheduler) _smanager.lookup(role);
-
boolean instantAlertEnabled = (Boolean) params.get("instantAlertEnabled");
if (instantAlertEnabled)
{
String instantAlertText = (String) params.get("instantAlertText");
- alertScheduler.sendInstantAlerts(contentIds, org.apache.commons.lang3.StringUtils.trimToEmpty(instantAlertText));
+ _contentAlertHelper.sendInstantAlerts(contentIds, org.apache.commons.lang3.StringUtils.trimToEmpty(instantAlertText));
}
}
@@ -280,47 +290,40 @@
* @param params the alerts' parameters
* @throws AmetysRepositoryException if a repository error occurs.
*/
- protected void _setAlerts(ModifiableMetadataAwareVersionableAmetysObject content, Map params) throws AmetysRepositoryException
+ protected void _setAlerts(Content content, Map params) throws AmetysRepositoryException
{
- ModifiableCompositeMetadata meta = content.getUnversionedMetadataHolder();
-
// Set alert for unmodified contents
if (params.get("unmodifiedAlertEnabled") != null)
{
- boolean unmodifiedAlertEnabled = (Boolean) params.get("unmodifiedAlertEnabled");
- String unmodifiedAlertText = (String) params.get("unmodifiedAlertText");
-
- meta.setMetadata(AlertsConstants.UNMODIFIED_ALERT_ENABLED, unmodifiedAlertEnabled);
- meta.setMetadata(AlertsConstants.UNMODIFIED_ALERT_TEXT, org.apache.commons.lang3.StringUtils.trimToEmpty(unmodifiedAlertText));
+ if (content instanceof ModifiableMetadataAwareVersionableAmetysObject)
+ {
+ ModifiableCompositeMetadata meta = ((ModifiableMetadataAwareVersionableAmetysObject) content).getUnversionedMetadataHolder();
+ boolean unmodifiedAlertEnabled = (Boolean) params.get("unmodifiedAlertEnabled");
+ String unmodifiedAlertText = (String) params.get("unmodifiedAlertText");
+
+ meta.setMetadata(AlertsConstants.UNMODIFIED_ALERT_ENABLED, unmodifiedAlertEnabled);
+ meta.setMetadata(AlertsConstants.UNMODIFIED_ALERT_TEXT, org.apache.commons.lang3.StringUtils.trimToEmpty(unmodifiedAlertText));
+
+ ((ModifiableMetadataAwareVersionableAmetysObject) content).saveChanges();
+ }
}
// Set reminders
- if (params.get("reminderEnabled") != null)
+ if (params.get("reminderEnabled") != null && (Boolean) params.get("reminderEnabled"))
{
- boolean reminderEnabled = (Boolean) params.get("reminderEnabled");
- meta.setMetadata(AlertsConstants.REMINDER_ENABLED, reminderEnabled);
-
String reminderDateStr = (String) params.get("reminderDate");
String reminderText = (String) params.get("reminderText");
- meta.setMetadata(AlertsConstants.REMINDER_TEXT, org.apache.commons.lang3.StringUtils.trimToEmpty(reminderText));
- // Parse the reminder date.
- Date reminderDate = null;
- try
+ if (StringUtils.isNotBlank(reminderDateStr))
{
- if (StringUtils.isNotBlank(reminderDateStr))
- {
- reminderDate = _DATE_FORMAT.parse(reminderDateStr);
- meta.setMetadata(AlertsConstants.REMINDER_DATE, reminderDate);
- }
- }
- catch (ParseException e)
- {
- // Ignore
+ ZonedDateTime reminderDate = DateTimeFormatter.ofPattern(__CLIENT_DATE_FORMAT).withZone(ZoneId.systemDefault()).parse(reminderDateStr, ZonedDateTime::from);
+ _contentAlertHelper.scheduleReminderEmail(content, reminderText, reminderDate);
}
}
-
- content.saveChanges();
+ else
+ {
+ _contentAlertHelper.unscheduleReminderEmail(content);
+ }
}
@Override
Index: main/plugin-cms/src/org/ametys/cms/alerts/InstantContentAlertRunnable.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/InstantContentAlertRunnable.java (revision 0)
+++ main/plugin-cms/src/org/ametys/cms/alerts/InstantContentAlertRunnable.java (revision 0)
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2016 Anyware Services
+ *
+ * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
+ */
+package org.ametys.cms.alerts;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.ametys.core.schedule.Runnable;
+import org.ametys.plugins.core.impl.schedule.SendMailSchedulable;
+import org.ametys.runtime.i18n.I18nizableText;
+
+/**
+ * A {@link Runnable} which schedules a {@link SendMailSchedulable} for sending instantly an alert email about a content.
+ */
+public class InstantContentAlertRunnable implements Runnable
+{
+ /** The content id */
+ protected String _contentId;
+ /** The content name */
+ protected String _contentName;
+ /** The sender of the mail */
+ protected String _sender;
+ /** The recipients of the mail (separated by a newline character)*/
+ protected String _recipients;
+ /** The subject of the mail */
+ protected String _subject;
+ /** The body of the mail */
+ protected String _body;
+
+ /**
+ * Constructor
+ * @param contentId The id of the contenet
+ * @param contentName
+ * @param sender The sender
+ * @param recipients The recipients
+ * @param subject The subject
+ * @param body The body
+ */
+ public InstantContentAlertRunnable(String contentId, String contentName, String sender, String recipients, String subject, String body)
+ {
+ _contentId = contentId;
+ _contentName = contentName;
+ _sender = sender;
+ _recipients = recipients;
+ _subject = subject;
+ _body = body;
+ }
+
+ @Override
+ public String getId()
+ {
+ return this.getClass().getName() + "." + _contentId;
+ }
+
+ @Override
+ public I18nizableText getLabel()
+ {
+ return new I18nizableText("plugin.cms", "PLUGINS_CMS_INSTANT_CONTENT_ALERT_RUNNABLE_LABEL", Collections.singletonList(_contentName));
+ }
+
+ @Override
+ public I18nizableText getDescription()
+ {
+ List parameters = new ArrayList<>();
+ parameters.add(_contentId);
+ parameters.add(_contentName);
+ return new I18nizableText("plugin.cms", "PLUGINS_CMS_INSTANT_CONTENT_ALERT_RUNNABLE_DESCRIPTION", parameters);
+ }
+
+ @Override
+ public FireProcess getFireProcess()
+ {
+ return FireProcess.NOW;
+ }
+
+ @Override
+ public String getCronExpression()
+ {
+ return null;
+ }
+
+ @Override
+ public String getSchedulableId()
+ {
+ return "org.ametys.core.schedule.SendMail";
+ }
+
+ @Override
+ public boolean isRemovable()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isModifiable()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isDeactivatable()
+ {
+ return false;
+ }
+
+ @Override
+ public MisfirePolicy getMisfirePolicy()
+ {
+ return MisfirePolicy.FIRE_ONCE;
+ }
+
+ @Override
+ public boolean isVolatile()
+ {
+ return false;
+ }
+
+ @Override
+ public Map getParameterValues()
+ {
+ Map values = new HashMap<>();
+ values.put(SendMailSchedulable.SENDER_KEY, _sender);
+ values.put(SendMailSchedulable.RECIPIENTS_KEY, _recipients);
+ values.put(SendMailSchedulable.SUBJECT_KEY, _subject);
+ values.put(SendMailSchedulable.BODY_KEY, _body);
+ values.put(SendMailSchedulable.IS_HTML_BODY_KEY, false);
+ return values;
+ }
+}
Index: main/plugin-cms/src/org/ametys/cms/alerts/ReminderContentAlertRunnable.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/ReminderContentAlertRunnable.java (revision 0)
+++ main/plugin-cms/src/org/ametys/cms/alerts/ReminderContentAlertRunnable.java (revision 0)
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2016 Anyware Services
+ *
+ * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
+ */
+package org.ametys.cms.alerts;
+
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.ametys.core.schedule.Runnable;
+import org.ametys.plugins.core.impl.schedule.SendMailSchedulable;
+import org.ametys.runtime.i18n.I18nizableText;
+
+/**
+ * A {@link Runnable} which schedules a {@link SendMailSchedulable} for sending a reminder alert email about a content.
+ */
+public class ReminderContentAlertRunnable implements Runnable
+{
+ /** The prefix for the id of this kinf of Runnable. The full id is the concatenation of this prefix and the content id */
+ public static final String ID_PREFIX = ReminderContentAlertRunnable.class.getName() + ".";
+ /** The key for the date */
+ public static final String DATE_KEY = "date";
+ /** The key for the reminder text */
+ public static final String REMINDER_TEXT_KEY = "reminderText";
+
+ /** The content id */
+ protected String _contentId;
+ /** The content name */
+ protected String _contentName;
+ /** The sender of the mail */
+ protected String _sender;
+ /** The recipients of the mail (separated by a newline character)*/
+ protected String _recipients;
+ /** The subject of the mail */
+ protected String _subject;
+ /** The body of the mail */
+ protected String _body;
+ /** The date when to send the mail */
+ protected ZonedDateTime _date;
+ /** The reminder text */
+ protected String _reminderText;
+
+ /**
+ * Constructor
+ * @param contentId The id of the contenet
+ * @param contentName
+ * @param sender The sender
+ * @param recipients The recipients
+ * @param subject The subject
+ * @param body The body
+ * @param date The date when to send the mail
+ * @param reminderText The reminder text
+ */
+ public ReminderContentAlertRunnable(String contentId, String contentName, String sender, String recipients, String subject, String body, ZonedDateTime date, String reminderText)
+ {
+ _contentId = contentId;
+ _contentName = contentName;
+ _sender = sender;
+ _recipients = recipients;
+ _subject = subject;
+ _body = body;
+ _date = date;
+ _reminderText = reminderText;
+ }
+
+ @Override
+ public String getId()
+ {
+ return ID_PREFIX + _contentId;
+ }
+
+ @Override
+ public I18nizableText getLabel()
+ {
+ return new I18nizableText("plugin.cms", "PLUGINS_CMS_REMINDER_CONTENT_ALERT_RUNNABLE_LABEL", Collections.singletonList(_contentName));
+ }
+
+ @Override
+ public I18nizableText getDescription()
+ {
+ List parameters = new ArrayList<>();
+ parameters.add(_contentId);
+ parameters.add(_contentName);
+ return new I18nizableText("plugin.cms", "PLUGINS_CMS_REMINDER_CONTENT_ALERT_RUNNABLE_DESCRIPTION", parameters);
+ }
+
+ @Override
+ public FireProcess getFireProcess()
+ {
+ return FireProcess.CRON;
+ }
+
+ @Override
+ public String getCronExpression()
+ {
+ return _date.getSecond() + " " + _date.getMinute() + " " + _date.getHour() + " " + _date.getDayOfMonth() + " " + _date.getMonthValue() + " ? " + _date.getYear();
+ }
+
+ @Override
+ public String getSchedulableId()
+ {
+ return "org.ametys.core.schedule.SendMail";
+ }
+
+ @Override
+ public boolean isRemovable()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isModifiable()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isDeactivatable()
+ {
+ return false;
+ }
+
+ @Override
+ public MisfirePolicy getMisfirePolicy()
+ {
+ return MisfirePolicy.FIRE_ONCE;
+ }
+
+ @Override
+ public boolean isVolatile()
+ {
+ return false;
+ }
+
+ @Override
+ public Map getParameterValues()
+ {
+ Map values = new HashMap<>();
+ // Schedulable parameters
+ values.put(SendMailSchedulable.SENDER_KEY, _sender);
+ values.put(SendMailSchedulable.RECIPIENTS_KEY, _recipients);
+ values.put(SendMailSchedulable.SUBJECT_KEY, _subject);
+ values.put(SendMailSchedulable.BODY_KEY, _body);
+ values.put(SendMailSchedulable.IS_HTML_BODY_KEY, false);
+ // Additional parameters
+ values.put(DATE_KEY, _date.toInstant().toEpochMilli());
+ values.put(REMINDER_TEXT_KEY, _reminderText);
+ return values;
+ }
+}
Index: main/plugin-cms/src/org/ametys/cms/alerts/UnmodifiedContentAlertRunnable.java
===================================================================
--- main/plugin-cms/src/org/ametys/cms/alerts/UnmodifiedContentAlertRunnable.java (revision 0)
+++ main/plugin-cms/src/org/ametys/cms/alerts/UnmodifiedContentAlertRunnable.java (revision 0)
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2016 Anyware Services
+ *
+ * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
+ */
+package org.ametys.cms.alerts;
+
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.ametys.core.schedule.Runnable;
+import org.ametys.plugins.core.impl.schedule.SendMailSchedulable;
+import org.ametys.runtime.i18n.I18nizableText;
+
+/**
+ * A {@link Runnable} which schedules a {@link SendMailSchedulable} for sending an alert email about a content which is unmodified for a certain number of days.
+ */
+public class UnmodifiedContentAlertRunnable implements Runnable
+{
+ /** The content id */
+ protected String _contentId;
+ /** The content name */
+ protected String _contentName;
+ /** The sender of the mail */
+ protected String _sender;
+ /** The recipients of the mail (separated by a newline character)*/
+ protected String _recipients;
+ /** The subject of the mail */
+ protected String _subject;
+ /** The body of the mail */
+ protected String _body;
+ /** The date when to send the mail */
+ protected ZonedDateTime _date;
+
+ /**
+ * Constructor
+ * @param contentId The id of the contenet
+ * @param contentName
+ * @param sender The sender
+ * @param recipients The recipients
+ * @param subject The subject
+ * @param body The body
+ * @param date The date when to send the mail
+ */
+ public UnmodifiedContentAlertRunnable(String contentId, String contentName, String sender, String recipients, String subject, String body, ZonedDateTime date)
+ {
+ _contentId = contentId;
+ _contentName = contentName;
+ _sender = sender;
+ _recipients = recipients;
+ _subject = subject;
+ _body = body;
+ _date = date;
+ }
+
+ @Override
+ public String getId()
+ {
+ return UnmodifiedContentAlertRunnable.class.getName() + "." + _contentId;
+ }
+
+ @Override
+ public I18nizableText getLabel()
+ {
+ return new I18nizableText("plugin.cms", "PLUGINS_CMS_UNMODIFIED_CONTENT_ALERT_RUNNABLE_LABEL", Collections.singletonList(_contentName));
+ }
+
+ @Override
+ public I18nizableText getDescription()
+ {
+ List parameters = new ArrayList<>();
+ parameters.add(_contentId);
+ parameters.add(_contentName);
+ return new I18nizableText("plugin.cms", "PLUGINS_CMS_UNMODIFIED_CONTENT_ALERT_RUNNABLE_DESCRIPTION", parameters);
+ }
+
+ @Override
+ public FireProcess getFireProcess()
+ {
+ return FireProcess.CRON;
+ }
+
+ @Override
+ public String getCronExpression()
+ {
+ return _date.getSecond() + " " + _date.getMinute() + " " + _date.getHour() + " " + _date.getDayOfMonth() + " " + _date.getMonthValue() + " ? " + _date.getYear();
+ }
+
+ @Override
+ public String getSchedulableId()
+ {
+ return "org.ametys.core.schedule.SendMail";
+ }
+
+ @Override
+ public boolean isRemovable()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isModifiable()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isDeactivatable()
+ {
+ return false;
+ }
+
+ @Override
+ public MisfirePolicy getMisfirePolicy()
+ {
+ return MisfirePolicy.FIRE_ONCE;
+ }
+
+ @Override
+ public boolean isVolatile()
+ {
+ return false;
+ }
+
+ @Override
+ public Map getParameterValues()
+ {
+ Map values = new HashMap<>();
+ values.put(SendMailSchedulable.SENDER_KEY, _sender);
+ values.put(SendMailSchedulable.RECIPIENTS_KEY, _recipients);
+ values.put(SendMailSchedulable.SUBJECT_KEY, _subject);
+ values.put(SendMailSchedulable.BODY_KEY, _body);
+ values.put(SendMailSchedulable.IS_HTML_BODY_KEY, false);
+ return values;
+ }
+
+}
#P Ametys - 08 WEB
Index: main/plugin-web/src/org/ametys/web/alerts/AlertEngine.java
===================================================================
--- main/plugin-web/src/org/ametys/web/alerts/AlertEngine.java (revision 42093)
+++ main/plugin-web/src/org/ametys/web/alerts/AlertEngine.java (working copy)
@@ -1,401 +0,0 @@
-/*
- * Copyright 2010 Anyware Services
- *
- * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
- */
-package org.ametys.web.alerts;
-
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-import org.apache.cocoon.components.ContextHelper;
-import org.apache.cocoon.environment.Request;
-
-import org.ametys.cms.repository.Content;
-import org.ametys.cms.repository.ModifiableContent;
-import org.ametys.core.user.UserIdentity;
-import org.ametys.plugins.repository.AmetysObjectIterable;
-import org.ametys.plugins.repository.AmetysRepositoryException;
-import org.ametys.plugins.repository.query.expression.DateExpression;
-import org.ametys.plugins.repository.query.expression.Expression;
-import org.ametys.plugins.repository.query.expression.Expression.Operator;
-import org.ametys.runtime.config.Config;
-import org.ametys.runtime.i18n.I18nizableText;
-import org.ametys.web.repository.content.WebContent;
-import org.ametys.web.repository.page.Page;
-import org.ametys.web.repository.page.PageQueryHelper;
-import org.ametys.web.repository.page.jcr.DefaultPage;
-
-/**
- * Alerts engine: sends alerts mail.
- * This is the web version of the engine: it sets the currently processed content's
- * site name in the request object, and sends additional site and page information
- * in the alerts e-mails.
- */
-public class AlertEngine extends org.ametys.cms.alerts.AlertEngine
-{
- /** True if the alert of page publication ending is enabled */
- protected boolean _pagePublicationEnabled;
-
- /** The "page nearing end of publication" e-mail will be sent to users that have this right. */
- protected Set _pagePublicationEndRights;
-
- /** The "page nearing end of publication" e-mail subject i18n key. */
- protected String _pagePublicationEndSubject;
-
- /** The "page nearing end of publication" e-mail body i18n key. */
- protected String _pagePublicationEndBody;
-
- /**
- * Default constructor
- */
- public AlertEngine()
- {
- super();
- }
-
- /**
- * Constructor used to send instant alerts
- * @param contentIds The content's id
- * @param message the message
- */
- public AlertEngine (List contentIds, String message)
- {
- super(contentIds, message);
- }
-
- @Override
- public void configure(Configuration configuration) throws ConfigurationException
- {
- super.configure(configuration);
-
- Configuration pagePublicationEndConf = configuration.getChild("pagePublicationEnd", false);
-
- if (pagePublicationEndConf != null)
- {
- _pagePublicationEnabled = true;
- _pagePublicationEndRights = _getRightsFromConf(pagePublicationEndConf);
- _pagePublicationEndSubject = pagePublicationEndConf.getChild("subjectKey").getValue();
- _pagePublicationEndBody = pagePublicationEndConf.getChild("bodyKey").getValue();
- }
- }
-
- @Override
- protected void _sendAlerts() throws AmetysRepositoryException
- {
- // Send the content alerts.
- super._sendAlerts();
-
- if (!_instantMode && _pagePublicationEnabled)
- {
- // Send the page alerts.
- _sendPagePublicationEndAlerts();
- }
-
- }
-
- /**
- * Send the "page nearing end of publication" alerts.
- * @throws AmetysRepositoryException if an error occurs.
- */
- protected void _sendPagePublicationEndAlerts() throws AmetysRepositoryException
- {
- Long delay = Config.getInstance().getValueAsLong("remind.before.publication.end");
- if (delay != null && delay > 0)
- {
- Calendar calendar = new GregorianCalendar();
- _removeTimeParts(calendar);
- calendar.add(Calendar.DAY_OF_MONTH, delay.intValue());
-
- // Get all the pages which publication end is in X days.
- Expression nearPublicationEndExpr = new DateExpression(DefaultPage.METADATA_PUBLICATION_END_DATE, Operator.EQ, calendar.getTime());
-
- String query = PageQueryHelper.getPageXPathQuery(null, null, null, nearPublicationEndExpr, null);
-
- try (AmetysObjectIterable pages = _ametysResolver.query(query))
- {
- if (_LOGGER.isInfoEnabled())
- {
- _LOGGER.info("Pages within " + Long.toString(delay) + " days of publication end: " + pages.getSize());
- }
-
- for (Page page : pages)
- {
- // Send the alert e-mails.
- _sendPagePublicationEndEmail(page);
- }
- }
- }
- }
-
- @Override
- protected void _sendInstantAlertEmail(Content content, String message) throws AmetysRepositoryException
- {
- setSiteNameInRequestAttribute(content);
- super._sendInstantAlertEmail(content, message);
- }
-
- @Override
- protected void _sendAwaitingValidationEmail(Content content) throws AmetysRepositoryException
- {
- setSiteNameInRequestAttribute(content);
- super._sendAwaitingValidationEmail(content);
- }
-
- @Override
- protected void _sendUnmodifiedContentEmail(Content content) throws AmetysRepositoryException
- {
- setSiteNameInRequestAttribute(content);
- super._sendUnmodifiedContentEmail(content);
- }
-
- @Override
- protected void _sendReminderEmail(Content content) throws AmetysRepositoryException
- {
- setSiteNameInRequestAttribute(content);
- super._sendReminderEmail(content);
- }
-
- /**
- * Set the site name in request attributes if found
- * @param content the content
- */
- protected void setSiteNameInRequestAttribute (Content content)
- {
- // Set the site name into the request for the other components to be able to retrieve it.
- if (content instanceof WebContent)
- {
- Request request = ContextHelper.getRequest(_context);
- request.setAttribute("siteName", ((WebContent) content).getSiteName());
- }
- }
-
- @Override
- protected void _sendScheduledArchivingReminderEmail(ModifiableContent content) throws AmetysRepositoryException
- {
- // Set the site name into the request for the other components to be able to retrieve it.
- if (content instanceof WebContent)
- {
- Request request = ContextHelper.getRequest(_context);
- request.setAttribute("siteName", ((WebContent) content).getSiteName());
- }
-
- super._sendScheduledArchivingReminderEmail(content);
- }
-
- /**
- * Send the "page publication end" alert e-mail.
- * @param page the page nearing publication end.
- * @throws AmetysRepositoryException if an error occurs.
- */
- protected void _sendPagePublicationEndEmail(Page page) throws AmetysRepositoryException
- {
- // Set the site name into the request for the other components to be able to retrieve it.
- Request request = ContextHelper.getRequest(_context);
- request.setAttribute("siteName", page.getSiteName());
-
- String context = _getPageContext(page);
-
- Set users = new HashSet<>();
- for (String right : _pagePublicationEndRights)
- {
- users.addAll(_rightsManager.getGrantedUsers(right, context));
- }
-
- List params = _getPagePublicationEndParams(page);
-
- I18nizableText i18nSubject = new I18nizableText(null, _pagePublicationEndSubject, params);
- I18nizableText i18nBody = new I18nizableText(null, _pagePublicationEndBody, params);
-
- String subject = _i18nUtils.translate(i18nSubject);
- String body = _i18nUtils.translate(i18nBody);
-
- _sendMails(subject, body, users, _mailFrom);
- }
-
- @Override
- protected String getI18nKeyBody(String bodyI18nKey, Content content)
- {
- String i18nKey = bodyI18nKey;
-
- if (content instanceof WebContent)
- {
- WebContent webContent = (WebContent) content;
- if (webContent.getReferencingPages().size() == 0)
- {
- // Orphan content
- i18nKey += "_ORPHAN";
- }
- }
- else
- {
- i18nKey += "_NOSITE";
- }
-
- return i18nKey;
- }
-
- /**
- * Get the additional i18n parameters for a web content.
- * Checks if the content is a Web content. If true, add the site and page title.
- * @param content the content
- * @return the additional i18n parameters
- */
- protected List _getAdditionalParamsForWebContent (Content content)
- {
- List params = new ArrayList<>();
-
- if (content instanceof WebContent)
- {
- WebContent webContent = (WebContent) content;
-
- params.add(webContent.getSite().getTitle()); // {4}
-
- Iterator pages = webContent.getReferencingPages().iterator();
- if (pages.hasNext())
- {
- Page page = pages.next();
- params.add(page.getTitle()); // {5}
- }
- }
-
- return params;
- }
-
- @Override
- protected List _getInstantAlertParams(Content content, String message)
- {
- List params = super._getInstantAlertParams(content, message);
- params.addAll(_getAdditionalParamsForWebContent(content));
- return params;
- }
-
- @Override
- protected List _getUnmodifiedContentParams(Content content)
- {
- List params = super._getUnmodifiedContentParams(content);
- params.addAll(_getAdditionalParamsForWebContent(content));
- return params;
- }
-
- @Override
- protected List _getAwaitingValidationParams(Content content)
- {
- List params = super._getAwaitingValidationParams(content);
- params.addAll(_getAdditionalParamsForWebContent(content));
- return params;
- }
-
- @Override
- protected List _getReminderParams(Content content)
- {
- List params = super._getReminderParams(content);
- params.addAll(_getAdditionalParamsForWebContent(content));
- return params;
- }
-
- @Override
- protected List _getScheduledArchivingReminderParams(ModifiableContent content)
- {
- List params = super._getScheduledArchivingReminderParams(content);
- params.addAll(_getAdditionalParamsForWebContent(content));
- return params;
- }
-
- /**
- * Get the "page nearing end of publication" mail parameters.
- * @param page the page.
- * @return the mail parameters.
- */
- protected List _getPagePublicationEndParams(Page page)
- {
- List params = new ArrayList<>();
-
- String siteTitle = page.getSite().getTitle();
- String delay = Config.getInstance().getValueAsString("remind.before.publication.end");
-
- params.add(page.getTitle());
- params.add(_getPageUrl(page));
- params.add(delay);
- params.add(siteTitle);
-
- return params;
- }
-
- /**
- * Get the page rights context.
- * @param page the page.
- * @return the page context.
- * @throws AmetysRepositoryException if an error occurs.
- */
- protected String _getPageContext(Page page) throws AmetysRepositoryException
- {
- return "/pages/" + page.getSitemapName() + "/" + page.getPathInSitemap();
- }
-
- @Override
- protected String _getContentUrl(Content content)
- {
- if (content instanceof WebContent)
- {
- WebContent webContent = (WebContent) content;
-
- StringBuilder url = new StringBuilder(_baseUrl);
- if (!_baseUrl.endsWith("/"))
- {
- url.append('/');
- }
-
- Iterator pages = webContent.getReferencingPages().iterator();
- if (pages.hasNext())
- {
- Page page = pages.next();
- url.append(webContent.getSite().getName()).append("/index.html?uitool=uitool-page,id:%27").append(page.getId()).append("%27");
- }
- else
- {
- url.append(webContent.getSite().getName()).append("/index.html?uitool=uitool-content,id:%27").append(content.getId()).append("%27");
- }
-
- return url.toString();
- }
- else
- {
- return super._getContentUrl(content);
- }
- }
-
- /**
- * Get the URL of the back-office, opening on the page tool.
- * @param page the page to link to.
- * @return the page URL.
- */
- protected String _getPageUrl(Page page)
- {
- StringBuilder url = new StringBuilder(_baseUrl);
- if (!_baseUrl.endsWith("/"))
- {
- url.append('/');
- }
- url.append(page.getSite().getName()).append("/index.html?uitool=uitool-page,id:%27").append(page.getId()).append("%27");
- return url.toString();
- }
-
-}
Index: main/plugin-web/src/org/ametys/web/alerts/AlertScheduler.java
===================================================================
--- main/plugin-web/src/org/ametys/web/alerts/AlertScheduler.java (revision 42093)
+++ main/plugin-web/src/org/ametys/web/alerts/AlertScheduler.java (working copy)
@@ -1,67 +0,0 @@
-/*
- * Copyright 2010 Anyware Services
- *
- * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
- */
-
-package org.ametys.web.alerts;
-
-import java.util.List;
-
-/**
- * Alerts scheduler: launches a cron which sends the alerts each night.
- * This scheduler is the same as the CMS' AlertScheduler, except it runs the web version of AlertEngine.
- */
-public class AlertScheduler extends org.ametys.cms.alerts.AlertScheduler
-{
- @Override
- public void run()
- {
- AlertEngine alertEngine = new AlertEngine();
-
- try
- {
- // Initialize and configure the engine.
- alertEngine.initialize(_manager, _context);
- alertEngine.configure(_configuration);
- }
- catch (Exception e)
- {
- throw new RuntimeException("Unable to initialize the alerts engine", e);
- }
-
- // The thread will be started as daemon, as the scheduler is marked daemon itself.
- new Thread(alertEngine, "AlertEngine").start();
- }
-
- @Override
- public void sendInstantAlerts(List contentIds, String message)
- {
- AlertEngine alertEngine = new AlertEngine(contentIds, message);
-
- try
- {
- // Initialize and configure the engine.
- alertEngine.initialize(_manager, _context);
- alertEngine.configure(_configuration);
- }
- catch (Exception e)
- {
- throw new RuntimeException("Unable to initialize the alerts engine", e);
- }
-
- // The thread will be started as daemon, as the scheduler is marked daemon itself.
- new Thread(alertEngine, "AlertEngine").start();
- }
-
-}
Index: main/plugin-web/src/org/ametys/web/alerts/ContentAlertHelper.java
===================================================================
--- main/plugin-web/src/org/ametys/web/alerts/ContentAlertHelper.java (revision 0)
+++ main/plugin-web/src/org/ametys/web/alerts/ContentAlertHelper.java (revision 0)
@@ -0,0 +1,375 @@
+/*
+ * Copyright 2016 Anyware Services
+ *
+ * Licensed under the Apache 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://www.apache.org/licenses/LICENSE-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.
+ */
+package org.ametys.web.alerts;
+
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.cocoon.components.ContextHelper;
+import org.apache.cocoon.environment.Request;
+
+import org.ametys.cms.repository.Content;
+import org.ametys.cms.repository.ModifiableContent;
+import org.ametys.core.user.UserIdentity;
+import org.ametys.plugins.repository.AmetysObjectIterable;
+import org.ametys.plugins.repository.AmetysRepositoryException;
+import org.ametys.plugins.repository.query.expression.DateExpression;
+import org.ametys.plugins.repository.query.expression.Expression;
+import org.ametys.plugins.repository.query.expression.Expression.Operator;
+import org.ametys.runtime.config.Config;
+import org.ametys.runtime.i18n.I18nizableText;
+import org.ametys.web.repository.content.WebContent;
+import org.ametys.web.repository.page.Page;
+import org.ametys.web.repository.page.PageQueryHelper;
+import org.ametys.web.repository.page.jcr.DefaultPage;
+
+/**
+ * Helper for web content alerts.
+ */
+public class ContentAlertHelper extends org.ametys.cms.alerts.ContentAlertHelper
+{
+ /** True if the alert of page publication ending is enabled */
+ protected boolean _pagePublicationEnabled;
+ /** The "page nearing end of publication" e-mail will be sent to users that have this right. */
+ protected Set _pagePublicationEndRights;
+ /** The "page nearing end of publication" e-mail subject i18n key. */
+ protected String _pagePublicationEndSubject;
+ /** The "page nearing end of publication" e-mail body i18n key. */
+ protected String _pagePublicationEndBody;
+
+ @Override
+ public void configure(Configuration configuration) throws ConfigurationException
+ {
+ super.configure(configuration);
+
+ Configuration pagePublicationEndConf = configuration.getChild("pagePublicationEnd", false);
+
+ if (pagePublicationEndConf != null)
+ {
+ _pagePublicationEnabled = true;
+ _pagePublicationEndRights = _getRightsFromConf(pagePublicationEndConf);
+ _pagePublicationEndSubject = pagePublicationEndConf.getChild("subjectKey").getValue();
+ _pagePublicationEndBody = pagePublicationEndConf.getChild("bodyKey").getValue();
+ }
+ }
+
+ @Override
+ public void sendAlerts() throws AmetysRepositoryException
+ {
+ // Send the content alerts.
+ super.sendAlerts();
+
+ if (_pagePublicationEnabled)
+ {
+ // Send the page alerts.
+ _sendPagePublicationEndAlerts();
+ }
+ }
+
+ /**
+ * Send the "page nearing end of publication" alerts.
+ * @throws AmetysRepositoryException if an error occurs.
+ */
+ protected void _sendPagePublicationEndAlerts() throws AmetysRepositoryException
+ {
+ Long delay = Config.getInstance().getValueAsLong("remind.before.publication.end");
+ if (delay != null && delay > 0)
+ {
+ Calendar calendar = new GregorianCalendar();
+ _removeTimeParts(calendar);
+ calendar.add(Calendar.DAY_OF_MONTH, delay.intValue());
+
+ // Get all the pages which publication end is in X days.
+ Expression nearPublicationEndExpr = new DateExpression(DefaultPage.METADATA_PUBLICATION_END_DATE, Operator.EQ, calendar.getTime());
+
+ String query = PageQueryHelper.getPageXPathQuery(null, null, null, nearPublicationEndExpr, null);
+
+ try (AmetysObjectIterable pages = _ametysResolver.query(query))
+ {
+ getLogger().info("Pages within {} days of publication end: {}", Long.toString(delay), pages.getSize());
+
+ for (Page page : pages)
+ {
+ // Send the alert e-mails.
+ _sendPagePublicationEndEmail(page);
+ }
+ }
+ }
+ }
+
+
+ @Override
+ protected void _scheduleInstantAlertEmail(Content content, String message) throws AmetysRepositoryException
+ {
+ setSiteNameInRequestAttribute(content);
+ super._scheduleInstantAlertEmail(content, message);
+ }
+
+ @Override
+ protected void _sendAwaitingValidationEmail(Content content) throws AmetysRepositoryException
+ {
+ setSiteNameInRequestAttribute(content);
+ super._sendAwaitingValidationEmail(content);
+ }
+
+ @Override
+ protected void _sendUnmodifiedContentEmail(Content content) throws AmetysRepositoryException
+ {
+ setSiteNameInRequestAttribute(content);
+ super._sendUnmodifiedContentEmail(content);
+ }
+
+ @Override
+ public void scheduleReminderEmail(Content content, String reminderText, ZonedDateTime date)
+ {
+ setSiteNameInRequestAttribute(content);
+ super.scheduleReminderEmail(content, reminderText, date);
+ }
+
+
+ /**
+ * Set the site name in request attributes if found
+ * @param content the content
+ */
+ protected void setSiteNameInRequestAttribute (Content content)
+ {
+ // Set the site name into the request for the other components to be able to retrieve it.
+ if (content instanceof WebContent)
+ {
+ Request request = ContextHelper.getRequest(_context);
+ request.setAttribute("siteName", ((WebContent) content).getSiteName());
+ }
+ }
+
+ @Override
+ protected void _sendScheduledArchivingReminderEmail(ModifiableContent content) throws AmetysRepositoryException
+ {
+ // Set the site name into the request for the other components to be able to retrieve it.
+ if (content instanceof WebContent)
+ {
+ Request request = ContextHelper.getRequest(_context);
+ request.setAttribute("siteName", ((WebContent) content).getSiteName());
+ }
+
+ super._sendScheduledArchivingReminderEmail(content);
+ }
+
+ /**
+ * Send the "page publication end" alert e-mail.
+ * @param page the page nearing publication end.
+ * @throws AmetysRepositoryException if an error occurs.
+ */
+ protected void _sendPagePublicationEndEmail(Page page) throws AmetysRepositoryException
+ {
+ // Set the site name into the request for the other components to be able to retrieve it.
+ Request request = ContextHelper.getRequest(_context);
+ request.setAttribute("siteName", page.getSiteName());
+
+ String context = _getPageContext(page);
+
+ Set users = new HashSet<>();
+ for (String right : _pagePublicationEndRights)
+ {
+ users.addAll(_rightManager.getGrantedUsers(right, context));
+ }
+
+ List params = _getPagePublicationEndParams(page);
+
+ I18nizableText i18nSubject = new I18nizableText(null, _pagePublicationEndSubject, params);
+ I18nizableText i18nBody = new I18nizableText(null, _pagePublicationEndBody, params);
+
+ String subject = _i18nUtils.translate(i18nSubject);
+ String body = _i18nUtils.translate(i18nBody);
+
+ _sendMails(subject, body, users, _mailFrom);
+ }
+
+ @Override
+ protected String getI18nKeyBody(String bodyI18nKey, Content content)
+ {
+ String i18nKey = bodyI18nKey;
+
+ if (content instanceof WebContent)
+ {
+ WebContent webContent = (WebContent) content;
+ if (webContent.getReferencingPages().size() == 0)
+ {
+ // Orphan content
+ i18nKey += "_ORPHAN";
+ }
+ }
+ else
+ {
+ i18nKey += "_NOSITE";
+ }
+
+ return i18nKey;
+ }
+
+ /**
+ * Get the additional i18n parameters for a web content.
+ * Checks if the content is a Web content. If true, add the site and page title.
+ * @param content the content
+ * @return the additional i18n parameters
+ */
+ protected List _getAdditionalParamsForWebContent (Content content)
+ {
+ List params = new ArrayList<>();
+
+ if (content instanceof WebContent)
+ {
+ WebContent webContent = (WebContent) content;
+
+ params.add(webContent.getSite().getTitle()); // {4}
+
+ Iterator pages = webContent.getReferencingPages().iterator();
+ if (pages.hasNext())
+ {
+ Page page = pages.next();
+ params.add(page.getTitle()); // {5}
+ }
+ }
+
+ return params;
+ }
+
+ @Override
+ protected List _getInstantAlertParams(Content content, String message)
+ {
+ List params = super._getInstantAlertParams(content, message);
+ params.addAll(_getAdditionalParamsForWebContent(content));
+ return params;
+ }
+
+ @Override
+ protected List _getUnmodifiedContentParams(Content content)
+ {
+ List params = super._getUnmodifiedContentParams(content);
+ params.addAll(_getAdditionalParamsForWebContent(content));
+ return params;
+ }
+
+ @Override
+ protected List _getAwaitingValidationParams(Content content)
+ {
+ List params = super._getAwaitingValidationParams(content);
+ params.addAll(_getAdditionalParamsForWebContent(content));
+ return params;
+ }
+
+ @Override
+ protected List _getReminderParams(Content content, String reminderText)
+ {
+ List params = super._getReminderParams(content, reminderText);
+ params.addAll(_getAdditionalParamsForWebContent(content));
+ return params;
+ }
+
+ @Override
+ protected List _getScheduledArchivingReminderParams(ModifiableContent content)
+ {
+ List params = super._getScheduledArchivingReminderParams(content);
+ params.addAll(_getAdditionalParamsForWebContent(content));
+ return params;
+ }
+
+ /**
+ * Get the "page nearing end of publication" mail parameters.
+ * @param page the page.
+ * @return the mail parameters.
+ */
+ protected List _getPagePublicationEndParams(Page page)
+ {
+ List params = new ArrayList<>();
+
+ String siteTitle = page.getSite().getTitle();
+ String delay = Config.getInstance().getValueAsString("remind.before.publication.end");
+
+ params.add(page.getTitle());
+ params.add(_getPageUrl(page));
+ params.add(delay);
+ params.add(siteTitle);
+
+ return params;
+ }
+
+ /**
+ * Get the page rights context.
+ * @param page the page.
+ * @return the page context.
+ * @throws AmetysRepositoryException if an error occurs.
+ */
+ protected String _getPageContext(Page page) throws AmetysRepositoryException
+ {
+ return "/pages/" + page.getSitemapName() + "/" + page.getPathInSitemap();
+ }
+
+ @Override
+ protected String _getContentUrl(Content content)
+ {
+ if (content instanceof WebContent)
+ {
+ WebContent webContent = (WebContent) content;
+
+ StringBuilder url = new StringBuilder(_baseUrl);
+ if (!_baseUrl.endsWith("/"))
+ {
+ url.append('/');
+ }
+
+ Iterator pages = webContent.getReferencingPages().iterator();
+ if (pages.hasNext())
+ {
+ Page page = pages.next();
+ url.append(webContent.getSite().getName()).append("/index.html?uitool=uitool-page,id:%27").append(page.getId()).append("%27");
+ }
+ else
+ {
+ url.append(webContent.getSite().getName()).append("/index.html?uitool=uitool-content,id:%27").append(content.getId()).append("%27");
+ }
+
+ return url.toString();
+ }
+ else
+ {
+ return super._getContentUrl(content);
+ }
+ }
+
+ /**
+ * Get the URL of the back-office, opening on the page tool.
+ * @param page the page to link to.
+ * @return the page URL.
+ */
+ protected String _getPageUrl(Page page)
+ {
+ StringBuilder url = new StringBuilder(_baseUrl);
+ if (!_baseUrl.endsWith("/"))
+ {
+ url.append('/');
+ }
+ url.append(page.getSite().getName()).append("/index.html?uitool=uitool-page,id:%27").append(page.getId()).append("%27");
+ return url.toString();
+ }
+}
#P Ametys - Template CMS
Index: webapp/plugins/default-workflow/plugin.xml
===================================================================
--- webapp/plugins/default-workflow/plugin.xml (revision 42093)
+++ webapp/plugins/default-workflow/plugin.xml (working copy)
@@ -269,4 +269,63 @@
+
+
+
+
+ Workflow_Rights_Edition_Online
+ plugin.cms:CONTENT_ALERTS_MAIL_REMINDER_SUBJECT
+ plugin.cms:CONTENT_ALERTS_MAIL_REMINDER_BODY
+
+
+ Workflow_Rights_Validate
+ plugin.cms:CONTENT_ALERTS_MAIL_AWAITING_VALIDATION_SUBJECT
+ plugin.cms:CONTENT_ALERTS_MAIL_AWAITING_VALIDATION_BODY
+
+
+ 1
+ 2
+ 3
+ Workflow_Rights_Edition_Online
+ plugin.cms:CONTENT_ALERTS_MAIL_UNMODIFIED_CONTENT_SUBJECT
+ plugin.cms:CONTENT_ALERTS_MAIL_UNMODIFIED_CONTENT_BODY
+
+
+ Workflow_Rights_Edition_Online
+ plugin.cms:CONTENT_ALERTS_MAIL_REMINDER_SUBJECT
+ plugin.cms:CONTENT_ALERTS_MAIL_REMINDER_BODY
+
+
+ Workflow_Rights_Archive
+ plugin.cms:CONTENT_ALERTS_MAIL_SCHEDULED_ARCHIVING_REMINDER_SUBJECT
+ plugin.cms:CONTENT_ALERTS_MAIL_SCHEDULED_ARCHIVING_REMINDER_BODY
+
+
+
+
+
+
+
+ plugin.cms:PLUGINS_CMS_CONTENT_ALERT_ENGINE_SCHEDULABLE_DESCRIPTION
+ flaticon-envelope14
+ true
+
+
+
+
+ plugin.cms:PLUGINS_CMS_CONTENT_ALERT_ENGINE_RUNNABLE_DESCRIPTION
+ org.ametys.cms.alerts.AlertEngineSchedulable
+ false
+ false
+ false
+ fire_once
+
+
+
#P Ametys - Template CMSWEB
Index: webapp/cms/plugins/default-workflow/plugin.xml
===================================================================
--- webapp/cms/plugins/default-workflow/plugin.xml (revision 42093)
+++ webapp/cms/plugins/default-workflow/plugin.xml (working copy)
@@ -350,11 +350,10 @@
-
-
+
+
Workflow_Rights_Edition_Online
plugin.web:CONTENT_ALERTS_MAIL_REMINDER_SUBJECT
@@ -390,5 +389,28 @@
+
+
+
+
+ plugin.cms:PLUGINS_CMS_CONTENT_ALERT_ENGINE_SCHEDULABLE_DESCRIPTION
+ flaticon-envelope14
+ true
+
+
+
+
+ plugin.cms:PLUGINS_CMS_CONTENT_ALERT_ENGINE_RUNNABLE_DESCRIPTION
+ org.ametys.cms.alerts.AlertEngineSchedulable
+ false
+ false
+ false
+ fire_once
+
+