/*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
* This file is part of Entando software.
* Entando is a free software;
* You can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; version 2.
*
* See the file License for the specific language governing permissions
* and limitations under the License
*
*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
*/
package com.agiletec.plugins.jpcontentnotifier.aps.system.services.contentnotifier;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.agiletec.aps.system.ApsSystemUtils;
import com.agiletec.aps.system.SystemConstants;
import com.agiletec.aps.system.common.AbstractService;
import com.agiletec.aps.system.exception.ApsSystemException;
import com.agiletec.aps.system.services.authorization.IAuthorizationManager;
import com.agiletec.aps.system.services.authorization.authorizator.IApsAuthorityManager;
import com.agiletec.aps.system.services.baseconfig.ConfigInterface;
import com.agiletec.aps.system.services.group.Group;
import com.agiletec.aps.system.services.lang.ILangManager;
import com.agiletec.aps.system.services.role.Permission;
import com.agiletec.aps.system.services.user.AbstractUser;
import com.agiletec.aps.system.services.user.IUserManager;
import com.agiletec.aps.system.services.user.UserDetails;
import com.agiletec.aps.util.DateConverter;
import com.agiletec.plugins.jacms.aps.system.services.content.IContentManager;
import com.agiletec.plugins.jacms.aps.system.services.content.event.PublicContentChangedEvent;
import com.agiletec.plugins.jacms.aps.system.services.content.event.PublicContentChangedObserver;
import com.agiletec.plugins.jacms.aps.system.services.content.model.SmallContentType;
import com.agiletec.plugins.jpcontentnotifier.aps.system.JpcontentnotifierSystemConstants;
import com.agiletec.plugins.jpcontentnotifier.aps.system.services.contentnotifier.model.ContentMailInfo;
import com.agiletec.plugins.jpcontentnotifier.aps.system.services.contentnotifier.model.NotifierConfig;
import com.agiletec.plugins.jpcontentnotifier.aps.system.services.contentnotifier.parse.ContentNotifierConfigDOM;
import com.agiletec.plugins.jpcontentnotifier.aps.system.services.contentnotifier.scheduler.MailSenderTask;
import com.agiletec.plugins.jpcontentnotifier.aps.system.services.contentnotifier.scheduler.Scheduler;
import com.agiletec.plugins.jpcontentnotifier.aps.system.services.contentnotifier.scheduler.Task;
import com.agiletec.plugins.jpmail.aps.services.mail.IMailManager;
import org.entando.entando.aps.system.services.userprofile.IUserProfileManager;
import org.entando.entando.aps.system.services.userprofile.model.IUserProfile;
/**
* Service to notify to users the content creation or update,
* the communication happens by email .
* @author E.Santoboni
*/
public class ContentNotifierManager extends AbstractService implements PublicContentChangedObserver, IContentNotifierManager {
@Override
public void init() throws ApsSystemException {
this.loadConfigs();
this.openScheduler();
ApsSystemUtils.getLogger().debug(this.getName() + ": service for notifications on contents changes initialized");
}
@Override
public void release() {
this.closeScheduler();
}
@Override
public void destroy() {
this.closeScheduler();
}
@Override
public void updateFromPublicContentChanged(PublicContentChangedEvent event) {
NotifierConfig config = this.getConfig();
if (config.isActive()) {
if ((config.isNotifyRemove() || PublicContentChangedEvent.REMOVE_OPERATION_CODE!=event.getOperationCode())) {
try {
this.getContentNotifierDao().saveEvent(event);
ApsSystemUtils.getLogger().trace("Traced operation " + event.getOperationCode() + " on Content " + event.getContent().getId());
} catch (ApsSystemException e) {
ApsSystemUtils.logThrowable(e, this, "updateFromPublicContentChanged");
throw new RuntimeException("error in updateFromPublicContentChanged", e);
}
}
}
}
@Override
public void updateNotifierConfig(NotifierConfig config) throws ApsSystemException {
try {
String xml = new ContentNotifierConfigDOM().createConfigXml(config);
this.getConfigManager().updateConfigItem(JpcontentnotifierSystemConstants.CONTENT_NOTIFIER_CONFIG_ITEM, xml);
this.setSchedulerConfig(config);
this.openScheduler();
ApsSystemUtils.getLogger().trace("Updated Content Notifier Configuration");
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "updateNotifierConfig");
throw new ApsSystemException("Errore in aggiornamento configurazione ContentNotifier", t);
}
}
public List<ContentMailInfo> getContentsToNotify() throws ApsSystemException {
return this.getContentNotifierDao().getContentsToNotify();
}
/**
* Notifica via eMail la modifica dei contenuti.
*/
@Override
public void sendEMails() throws ApsSystemException {
if (!this.getConfig().isActive()) {
ApsSystemUtils.getLogger().info("Content Notifier not active");
return;
}
try {
List<ContentMailInfo> contentsToNotify = this.getContentsToNotify();
ApsSystemUtils.getLogger().info("Starting to notify " + contentsToNotify.size() + " Contents");
processContents(contentsToNotify);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "sendEMails");
throw new ApsSystemException("Error sending emails", t);
}
}
public List<ContentMailInfo> getContentsToNotifyToUser(UserDetails user, List<ContentMailInfo> contentsToNotify) {
IAuthorizationManager authManager = this.getAuthorizationManager();
if (authManager.isAuthOnGroup(user, Group.ADMINS_GROUP_NAME)) {
return contentsToNotify;
} else {
List<ContentMailInfo> contentsToNotifyToUser = new ArrayList<ContentMailInfo>();
boolean onlyOwner = this.getConfig().isOnlyOwner();
for (ContentMailInfo info : contentsToNotify) {
String mainGroup = info.getMainGroup();
boolean allowedContent = authManager.isAuthOnGroup(user, mainGroup);
if (!allowedContent && !onlyOwner && info.getGroups()!=null) {
for (String group : info.getGroups()) {
if (authManager.isAuthOnGroup(user, group)) {
allowedContent = true;
break;
}
}
}
if (allowedContent) {
contentsToNotifyToUser.add(info);
}
}
return contentsToNotifyToUser;
}
}
protected void loadConfigs() throws ApsSystemException {
try {
ConfigInterface configManager = this.getConfigManager();
String xml = configManager.getConfigItem(JpcontentnotifierSystemConstants.CONTENT_NOTIFIER_CONFIG_ITEM);
if (xml == null) {
throw new ApsSystemException("Missing content item: " + JpcontentnotifierSystemConstants.CONTENT_NOTIFIER_CONFIG_ITEM);
}
ApsSystemUtils.getLogger().trace(JpcontentnotifierSystemConstants.CONTENT_NOTIFIER_CONFIG_ITEM + ": " + xml);
ContentNotifierConfigDOM configDOM = new ContentNotifierConfigDOM();
this.setSchedulerConfig(configDOM.extractConfig(xml));
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "loadConfigs");
throw new ApsSystemException("Error loading config", t);
}
}
/**
* Apre lo scheduler istanziando il task relativo
* alla spedizione degli sms con i rilevamenti meteo.
*/
protected void openScheduler() {
this.closeScheduler();
NotifierConfig config = this.getConfig();
if (config.isActive()) {
Date startTime = config.getStartScheduler();
long milliSecondsDelay = config.getHoursDelay() * 3600000l; // x minuti secondi millisecondi
startTime = this.calculateStartTime(startTime, milliSecondsDelay);
Task task = new MailSenderTask(this);
this._mailSenderScheduler = new Scheduler(task, startTime, milliSecondsDelay);
}
}
protected void closeScheduler() {
if (this._mailSenderScheduler != null) {
this._mailSenderScheduler.cancel();
this._mailSenderScheduler = null;
}
}
protected List<UserDetails> findContentOperators() throws ApsSystemException {
IAuthorizationManager authManager = this.getAuthorizationManager();
IUserManager userManager = this.getUserManager();
IUserProfileManager profileManager = this.getProfileManager();
List<UserDetails> systemUsers = userManager.getUsers();
List<UserDetails> allowedUsers = new ArrayList<UserDetails>();
for (UserDetails user : systemUsers){
user.addAutorities(this.getRoleManager().getAuthorizationsByUser(user));
if (authManager.isAuthOnPermission(user, Permission.SUPERVISOR) || authManager.isAuthOnPermission(user, "editContents")) {
try {
AbstractUser userDetails = (AbstractUser) user;
IUserProfile profile = profileManager.getProfile(userDetails.getUsername());
userDetails.setProfile(profile);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "findContentOperators", "Error searching profile for user " + user.getUsername());
}
user.addAutorities(this.getGroupManager().getAuthorizationsByUser(user));
allowedUsers.add(user);
}
}
return allowedUsers;
}
protected boolean sendEMailToUser(UserDetails user, List<ContentMailInfo> contentsToNotify, Map<String, SmallContentType> smallContentTypes) throws ApsSystemException {
boolean sent = false;
NotifierConfig config = this.getConfig();
IUserProfile profile = (IUserProfile) user.getProfile();
if (profile!=null) {
String emailAttributeName = config.getMailAttrName();
Object eMailValue = profile.getValue(emailAttributeName);
String eMail = eMailValue!=null ? eMailValue.toString() : null;
if (eMail != null && eMail.length() > 0) {
List<ContentMailInfo> contentsToNotifyToUser = this.getContentsToNotifyToUser(user, contentsToNotify);
if (!contentsToNotifyToUser.isEmpty()) {
String[] eMailAddresses = {eMail};
String mailBody = this.createBody(user, contentsToNotifyToUser, smallContentTypes);
String contentType = config.isHtml() ? IMailManager.CONTENTTYPE_TEXT_HTML : IMailManager.CONTENTTYPE_TEXT_PLAIN;
sent = this.getMailManager().sendMail(mailBody, config.getSubject(),
eMailAddresses, null, null, config.getSenderCode(), contentType);
}
}
}
return sent;
}
protected void signNotifiedContents(List<ContentMailInfo> contentsNotified) throws ApsSystemException, SQLException {
try {
this.getContentNotifierDao().signNotifiedContents(contentsNotified);
} catch (Throwable t) {
ApsSystemUtils.logThrowable(t, this, "signNotifiedContents");
throw new ApsSystemException ("Error sign Notified Contents ", t);
}
}
protected String createLink(ContentMailInfo info, String langCode) {
StringBuilder link = new StringBuilder();
String applicationBaseUrl = this.getConfigManager().getParam(SystemConstants.PAR_APPL_BASE_URL);
link.append(applicationBaseUrl);
link.append(langCode);
link.append("/");
link.append(this.getContentManager().getViewPage(info.getContentId()));
link.append(".page?contentId=");
link.append(info.getContentId());
return link.toString();
}
/**
* @param defaultText Il testo di partenza, contenente le stringhe da rimpiazzare secondo la sintassi {chiaveStringa}.
* @param params La mappa dei parametri da rimpiazzare (solo il nome, esluse le { })<br />
* ATTENZIONE: le chiavi non devono contenere caratteri speciali per le regular expressions.<br />
* In tal caso vanno utilizzati i caratteri di escape.
* @return Il testo con tutte le occorrenze delle parole chiave sostituite.
*/
protected String replaceParams(String defaultText, Map<String, String> params) {
String body = defaultText;
for (Entry<String, String> pairs : params.entrySet()) {
String field = "\\{" + pairs.getKey() + "\\}";
body = body.replaceAll(field, (String) pairs.getValue());
}
return body;
}
protected Map<String, String> prepareContentParams(ContentMailInfo info, SmallContentType smallContentType, String link) {
Map<String, String> params = new HashMap<String, String>();
params.put("link", link);
params.put("type", smallContentType.getDescr());
params.put("descr", info.getContentDescr());
params.put("date", DateConverter.getFormattedDate(info.getDate(), "dd MMMM yyyy"));
params.put("time", DateConverter.getFormattedDate(info.getDate(), "HH:mm"));
return params;
}
private void processContents(List<ContentMailInfo> contentsToNotify) throws ApsSystemException, SQLException {
if (contentsToNotify.isEmpty()) return;
List<UserDetails> allowedUsers = this.findContentOperators();
ApsSystemUtils.getLogger().info("Starting to notify contents to " + allowedUsers.size() + " Operators");
Map<String, SmallContentType> smallContentTypes = this.getContentManager().getSmallContentTypesMap();
int notified = 0;
for (UserDetails user : allowedUsers) {
boolean sent = this.sendEMailToUser(user, contentsToNotify, smallContentTypes);
if (sent) notified++;
}
ApsSystemUtils.getLogger().info("Notified " + contentsToNotify.size() + " Contents to " + notified + " Operators");
if (notified > 0) {
this.signNotifiedContents(contentsToNotify);
}
}
private String createBody(UserDetails user, List<ContentMailInfo> contentsToNotifyToUser, Map<String, SmallContentType> smallContentTypes) {
String defaultLangCode = this.getLangManager().getDefaultLang().getCode();
NotifierConfig config = this.getConfig();
StringBuffer body = new StringBuffer(config.getHeader());
for (ContentMailInfo info : contentsToNotifyToUser) {
SmallContentType smallContentType = (SmallContentType) smallContentTypes.get(info.getContentTypeCode());
String link = this.createLink(info, defaultLangCode);
Map<String, String> params = this.prepareContentParams(info, smallContentType, link);
switch (info.getOperationCode()) {
case PublicContentChangedEvent.INSERT_OPERATION_CODE:
body.append(this.replaceParams(config.getTemplateInsert(), params));
break;
case PublicContentChangedEvent.UPDATE_OPERATION_CODE:
body.append(this.replaceParams(config.getTemplateUpdate(), params));
break;
case PublicContentChangedEvent.REMOVE_OPERATION_CODE:
body.append(this.replaceParams(config.getTemplateRemove(), params));
break;
}
}
body.append(config.getFooter());
return body.toString();
}
private Date calculateStartTime(Date startTime, long delay) {
Date current = new Date();
long waitTime = current.getTime() - startTime.getTime();
if (waitTime > 0) {
startTime = new Date((current.getTime() + delay) - (waitTime % delay));
}
return startTime;
}
@Override
public NotifierConfig getConfig() {
return this._schedulerConfig;
}
public void setSchedulerConfig(NotifierConfig schedulerConfig) {
this._schedulerConfig = schedulerConfig;
}
protected ConfigInterface getConfigManager() {
return _configManager;
}
public void setConfigManager(ConfigInterface configManager) {
this._configManager = configManager;
}
protected IContentManager getContentManager() {
return _contentManager;
}
public void setContentManager(IContentManager contentManager) {
this._contentManager = contentManager;
}
protected ILangManager getLangManager() {
return _langManager;
}
public void setLangManager(ILangManager langManager) {
this._langManager = langManager;
}
protected IUserManager getUserManager() {
return _userManager;
}
public void setUserManager(IUserManager userManager) {
this._userManager = userManager;
}
protected IMailManager getMailManager() {
return _mailManager;
}
public void setMailManager(IMailManager mailManager) {
this._mailManager = mailManager;
}
protected IAuthorizationManager getAuthorizationManager() {
return _authorizationManager;
}
public void setAuthorizationManager(IAuthorizationManager authorizationManager) {
this._authorizationManager = authorizationManager;
}
public IUserProfileManager getProfileManager() {
return _profileManager;
}
public void setProfileManager(IUserProfileManager profileManager) {
this._profileManager = profileManager;
}
public IApsAuthorityManager getRoleManager() {
return _roleManager;
}
public void setRoleManager(IApsAuthorityManager roleManager) {
this._roleManager = roleManager;
}
public IApsAuthorityManager getGroupManager() {
return _groupManager;
}
public void setGroupManager(IApsAuthorityManager groupManager) {
this._groupManager = groupManager;
}
protected IContentNotifierDAO getContentNotifierDao() {
return _contentNotifierDao;
}
public void setContentNotifierDao(IContentNotifierDAO contentNotifierDao) {
this._contentNotifierDao = contentNotifierDao;
}
protected Scheduler _mailSenderScheduler;
private NotifierConfig _schedulerConfig;
private ConfigInterface _configManager;
private IContentManager _contentManager;
private ILangManager _langManager;
private IUserManager _userManager;
private IMailManager _mailManager;
private IAuthorizationManager _authorizationManager;
private IUserProfileManager _profileManager;
private IApsAuthorityManager _roleManager;
private IApsAuthorityManager _groupManager;
private IContentNotifierDAO _contentNotifierDao;
}