View Javadoc
1   /*
2    * Copyright (c) 2002-2023, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.document.modules.rulenotifyusers.business;
35  
36  import fr.paris.lutece.plugins.document.business.rules.AbstractRule;
37  import fr.paris.lutece.plugins.document.business.workflow.DocumentState;
38  import fr.paris.lutece.plugins.document.business.workflow.DocumentStateHome;
39  import fr.paris.lutece.plugins.document.service.DocumentEvent;
40  import fr.paris.lutece.plugins.document.service.DocumentException;
41  import fr.paris.lutece.plugins.document.service.spaces.DocumentSpacesService;
42  import fr.paris.lutece.plugins.document.service.spaces.SpaceRemovalListenerService;
43  import fr.paris.lutece.plugins.document.utils.IntegerUtils;
44  import fr.paris.lutece.portal.business.mailinglist.MailingList;
45  import fr.paris.lutece.portal.business.mailinglist.MailingListHome;
46  import fr.paris.lutece.portal.business.mailinglist.Recipient;
47  import fr.paris.lutece.portal.business.user.AdminUser;
48  import fr.paris.lutece.portal.service.i18n.I18nService;
49  import fr.paris.lutece.portal.service.mail.MailService;
50  import fr.paris.lutece.portal.service.mailinglist.AdminMailingListService;
51  import fr.paris.lutece.portal.service.mailinglist.MailingListRemovalListenerService;
52  import fr.paris.lutece.portal.service.template.AppTemplateService;
53  import fr.paris.lutece.portal.service.util.AppLogService;
54  import fr.paris.lutece.portal.service.util.AppPathService;
55  import fr.paris.lutece.portal.service.util.AppPropertiesService;
56  import fr.paris.lutece.util.ReferenceItem;
57  import fr.paris.lutece.util.ReferenceList;
58  import fr.paris.lutece.util.html.HtmlTemplate;
59  import fr.paris.lutece.util.url.UrlItem;
60  
61  import org.apache.commons.lang3.StringUtils;
62  
63  import java.util.Collection;
64  import java.util.HashMap;
65  import java.util.Locale;
66  import java.util.Map;
67  import java.util.StringTokenizer;
68  
69  
70  /**
71   * This class provides a rule to notify users on document events
72   */
73  public class NotifyUsersRule extends AbstractRule
74  {
75      ////////////////////////////////////////////////////////////////////////////
76      // Constants
77      private static final String REGEX_ID = "^[\\d]+$";
78      private static final String NO_MAILING_LIST = "none";
79      private static final String TEMPLATE_CREATE_RULE = "/admin/plugins/document/modules/rulenotifyusers/create_rule_notify_users.html";
80      private static final String MARK_SPACE_SOURCE_PATH = "path_space_source";
81      private static final String MARK_SPACE_SOURCE_ID = "id_space_source";
82      private static final String MARK_STATE_ID = "id_state";
83      private static final String MARK_MAILINGLIST_ID = "id_mailinglist";
84  
85      //    private static final String MARK_MESSAGE_TEMPLATE_KEY = "message_template_key";
86      private static final String MARK_STATES_LIST = "states_list";
87      private static final String MARK_MAILINGLISTS_LIST = "mailinglists_list";
88      private static final String MARK_MESSAGE_TEMPLATES_LIST = "message_templates_list";
89      private static final String MARK_USER = "user";
90      private static final String MARK_DOCUMENT = "document";
91      private static final String MARK_URL_PREVIEW = "url_preview";
92      private static final String MARK_BASE_URL = "base_url";
93      private static final String PARAMETER_SPACE_SOURCE_ID = "id_space_source";
94      private static final String PARAMETER_STATE_ID = "id_state";
95      private static final String PARAMETER_MAILINGLIST_ID = "id_mailinglist";
96      private static final String PARAMETER_MESSAGE_TEMPLATE_KEY = "message_template_key";
97  
98      // defined in rulenotifyusers_messages.properties
99      private static final String PROPERTY_RULE_NAME = "module.document.rulenotifyusers.ruleName";
100     private static final String PROPERTY_RULE_DESCRIPTION = "module.document.rulenotifyusers.ruleLiteral";
101     private static final String PROPERTY_MAIL_SENDER_NAME = "module.document.rulenotifyusers.mailSenderName";
102     private static final String PROPERTY_RULE_ERROR_MAILING_LIST_ID = "module.document.rulenotifyusers.message.create_rule_notify_users.errorMailingListId";
103     private static final String PROPERTY_CHOOSE_MAILING_LIST = "module.document.rulenotifyusers.create_rule_notify_users.chooseMailingList";
104     private static final String PROPERTY_RULE_ERROR_NOT_SELECT_SPACE_SOURCE = "module.document.rulenotifyusers.message.create_rule_notify_users.errorNotSelectSpaceSource";
105 
106     // defined in document-rulenotifyusers.properties
107     private static final String PROPERTY_MESSAGE_TEMPLATES_ENTRIES = "document-rulenotifyusers.messages";
108     private static final String PROPERTY_MESSAGE_PREFIX = "document-rulenotifyusers.message.";
109     private static final String PROPERTY_MESSAGE_PREFIX_INTERNATIONALIZATION = "module.document.rulenotifyusers.notify_users_rule.message.";
110     private static final String SUFFIX_TEMPLATE = ".template";
111     private static final String SUFFIX_SUBJECT = ".subject";
112     private static final String SUFFIX_DESCRIPTION = ".description";
113 
114     // suffix that allows to get the url used in the mail - defined in document-rulenotifyusers.properties
115     private static final String SUFFIX_URL_PREVIEW = "document-rulenotifyusers.previewDocument";
116     private static String[] _attributes = 
117         {
118             PARAMETER_SPACE_SOURCE_ID, PARAMETER_MAILINGLIST_ID, PARAMETER_STATE_ID, PARAMETER_MESSAGE_TEMPLATE_KEY,
119         };
120     private static NotifyUsersMailingListRemovalListener _listenerMailingList;
121     private static NotifyUsersSpaceRemovalListener _listenerSpace;
122     private static final String PROPERTY_PROD_BASE_URL = "lutece.prod.url";
123 
124     /**
125      * Initialize the rule
126      */
127     public void init(  )
128     {
129         // Create removal listeners and register them
130         if ( _listenerMailingList == null )
131         {
132             _listenerMailingList = new NotifyUsersMailingListRemovalListener(  );
133             MailingListRemovalListenerService.getService(  ).registerListener( _listenerMailingList );
134         }
135 
136         if ( _listenerSpace == null )
137         {
138             _listenerSpace = new NotifyUsersSpaceRemovalListener(  );
139             SpaceRemovalListenerService.getService(  ).registerListener( _listenerSpace );
140         }
141     }
142 
143     /**
144      * Gets the Rule name key
145      * @return The Rule name key
146      */
147     public String getNameKey(  )
148     {
149         return PROPERTY_RULE_NAME;
150     }
151 
152     /**
153      * Execute the rule
154      * @param event The document event
155      * @throws DocumentException raise when error occurs in event or rule
156      */
157     public void apply( DocumentEvent event ) throws DocumentException
158     {
159         try
160         {
161             int nSourceSpace = Integer.parseInt( getAttribute( PARAMETER_SPACE_SOURCE_ID ) );
162             int nState = Integer.parseInt( getAttribute( PARAMETER_STATE_ID ) );
163             int nMailingListId = Integer.parseInt( getAttribute( PARAMETER_MAILINGLIST_ID ) );
164 
165             UrlItem url = AppPathService.buildRedirectUrlItem( "", SUFFIX_URL_PREVIEW );
166 
167             if ( event.getStateId(  ) == nState )
168             {
169                 if ( event.getSpaceId(  ) == nSourceSpace )
170                 {
171                     Collection<Recipient> listRecipients = AdminMailingListService.getRecipients( nMailingListId );
172 
173                     for ( Recipient recipient : listRecipients )
174                     {
175                         // Build the mail message
176                         Map<String, Object> model = new HashMap<String, Object>(  );
177                         model.put( MARK_USER, event.getUser(  ) );
178                         model.put( MARK_DOCUMENT, event.getDocument(  ) );
179                         model.put( MARK_URL_PREVIEW, url.getUrl(  ) );
180                         model.put( MARK_BASE_URL, AppPropertiesService.getProperty( PROPERTY_PROD_BASE_URL ) );
181 
182                         String strMessageTemplate = getMessageTemplate( getAttribute( PARAMETER_MESSAGE_TEMPLATE_KEY ) );
183                         String strSubject = getMessageSubject( getAttribute( PARAMETER_MESSAGE_TEMPLATE_KEY ),
184                                 event.getUser(  ).getLocale(  ) );
185                         HtmlTemplate t = AppTemplateService.getTemplate( strMessageTemplate,
186                                 event.getUser(  ).getLocale(  ), model );
187 
188                         // Send Mail
189                         String strSenderName = I18nService.getLocalizedString( PROPERTY_MAIL_SENDER_NAME,
190                                 event.getUser(  ).getLocale(  ) );
191                         String strSenderEmail = MailService.getNoReplyEmail(  );
192 
193                         MailService.sendMailHtml( recipient.getEmail(  ), strSenderName, strSenderEmail, strSubject,
194                             t.getHtml(  ) );
195                     }
196                 }
197             }
198         }
199         catch ( Exception e )
200         {
201             AppLogService.error( "Error in NotifyUserRule event : " + e.getMessage(  ), e );
202         }
203     }
204 
205     /**
206      * Gets the Rule create form
207      * @param user The current user using the form
208      * @param locale The current locale
209      * @return The HTML form
210      */
211     public String getCreateForm( AdminUser user, Locale locale )
212     {
213         Map<String, Object> model = new HashMap<String, Object>(  );
214 
215         Collection<ReferenceItem> listStates = DocumentStateHome.getDocumentStatesList( locale );
216         ReferenceList listMailingLists = new ReferenceList(  );
217 
218         if ( this.getAttribute( PARAMETER_STATE_ID ) != null )
219         {
220             model.put( MARK_STATE_ID, this.getAttribute( PARAMETER_STATE_ID ) );
221         }
222 
223         if ( this.getAttribute( PARAMETER_MAILINGLIST_ID ) != null )
224         {
225             model.put( MARK_MAILINGLIST_ID, this.getAttribute( PARAMETER_MAILINGLIST_ID ) );
226         }
227 
228         if ( this.getAttribute( PARAMETER_MESSAGE_TEMPLATE_KEY ) != null )
229         {
230             model.put( PARAMETER_MESSAGE_TEMPLATE_KEY, this.getAttribute( PARAMETER_MESSAGE_TEMPLATE_KEY ) );
231         }
232 
233         if ( this.getAttribute( PARAMETER_SPACE_SOURCE_ID ) != null )
234         {
235             int nIdSpaceSource = -1;
236             String strPathSpaceSource;
237 
238             try
239             {
240                 nIdSpaceSource = Integer.parseInt( this.getAttribute( PARAMETER_SPACE_SOURCE_ID ) );
241                 model.put( MARK_SPACE_SOURCE_ID, nIdSpaceSource );
242             }
243             catch ( NumberFormatException ne )
244             {
245                 AppLogService.error( ne );
246             }
247 
248             strPathSpaceSource = DocumentSpacesService.getInstance(  ).getLabelSpacePath( nIdSpaceSource, user );
249             model.put( MARK_SPACE_SOURCE_PATH, strPathSpaceSource );
250         }
251 
252         listMailingLists.addItem( NO_MAILING_LIST,
253             I18nService.getLocalizedString( PROPERTY_CHOOSE_MAILING_LIST, locale ) );
254         listMailingLists.addAll( AdminMailingListService.getMailingLists( user ) );
255 
256         model.put( MARK_STATES_LIST, listStates );
257         model.put( MARK_MAILINGLISTS_LIST, listMailingLists );
258         model.put( MARK_MESSAGE_TEMPLATES_LIST, getMessageTemplatesList( locale ) );
259 
260         HtmlTemplate template = AppTemplateService.getTemplate( TEMPLATE_CREATE_RULE, locale, model );
261 
262         return template.getHtml(  );
263     }
264 
265     /**
266      * Check the rule
267      *
268      * @return null if rule is valid, message if rule not valid
269      */
270     public String validateRule(  )
271     {
272         String strMailingListId = getAttribute( PARAMETER_MAILINGLIST_ID );
273         String strSourceSpaceId = getAttribute( PARAMETER_SPACE_SOURCE_ID );
274 
275         if ( strSourceSpaceId == null )
276         {
277             return PROPERTY_RULE_ERROR_NOT_SELECT_SPACE_SOURCE;
278         }
279 
280         if ( ( strMailingListId == null ) || !strMailingListId.matches( REGEX_ID ) )
281         {
282             return PROPERTY_RULE_ERROR_MAILING_LIST_ID;
283         }
284 
285         return null;
286     }
287 
288     /**
289      * true if the user is authorized to view the rule
290      * @param user the current user
291      * @return true if the user is authorized to view the rule
292      */
293     public boolean isAuthorized( AdminUser user )
294     {
295         int nSourceSpaceId = IntegerUtils.convert( getAttribute( PARAMETER_SPACE_SOURCE_ID ) );
296 
297         if ( !DocumentSpacesService.getInstance(  ).isAuthorizedViewByWorkgroup( nSourceSpaceId, user ) )
298         {
299             return false;
300         }
301 
302         return true;
303     }
304 
305     /**
306      * Gets all attributes of the rule
307      * @return attributes of the rule
308      */
309     public String[] getAttributesList(  )
310     {
311         return _attributes;
312     }
313 
314     /**
315      * Gets the explicit text of the rule
316      * @return The text of the rule
317      */
318     public String getRule(  )
319     {
320         int nSourceSpaceId = IntegerUtils.convert( getAttribute( PARAMETER_SPACE_SOURCE_ID ) );
321         String strSourceSpace = DocumentSpacesService.getInstance(  ).getLabelSpacePath( nSourceSpaceId, getUser(  ) );
322         String strMailingListId = getAttribute( PARAMETER_MAILINGLIST_ID );
323         String strMailingList = null;
324 
325         if ( StringUtils.isNotBlank( strMailingListId ) && strMailingListId.matches( REGEX_ID ) )
326         {
327             int nMailingListId = IntegerUtils.convert( strMailingListId );
328             MailingList mailinglist = MailingListHome.findByPrimaryKey( nMailingListId );
329 
330             if ( mailinglist != null )
331             {
332                 strMailingList = mailinglist.getDescription(  );
333             }
334         }
335 
336         String strMessageTemplate = getMessageDescription( getAttribute( PARAMETER_MESSAGE_TEMPLATE_KEY ), getLocale(  ) );
337         int nStateId = IntegerUtils.convert( getAttribute( PARAMETER_STATE_ID ) );
338         DocumentState state = DocumentStateHome.findByPrimaryKey( nStateId );
339         String strState = StringUtils.EMPTY;
340 
341         if ( state != null )
342         {
343             state.setLocale( getLocale(  ) );
344             strState = state.getName(  );
345         }
346 
347         String[] ruleArgs = { strSourceSpace, strState, strMailingList, strMessageTemplate };
348 
349         return I18nService.getLocalizedString( PROPERTY_RULE_DESCRIPTION, ruleArgs, getLocale(  ) );
350     }
351 
352     /**
353      * Get the parameter key for the mailing list Id
354      * @return The parameter key
355      */
356     public static String getParameterKeyMailingListId(  )
357     {
358         return PARAMETER_MAILINGLIST_ID;
359     }
360 
361     /**
362      * Get the parameter key for the source space Id
363      * @return The parameter key
364      */
365     public static String getParameterKeySourceSpaceId(  )
366     {
367         return PARAMETER_SPACE_SOURCE_ID;
368     }
369 
370     /**
371      * Get the parameter key for the state Id
372      * @return The parameter key
373      */
374     public static String getParameterKeyStateId(  )
375     {
376         return PARAMETER_STATE_ID;
377     }
378 
379     /**
380      * Gets the list of message templates
381      *
382      * @param locale The current locale
383      * @return A ReferenceList containing all available messages templates
384      */
385     private ReferenceList getMessageTemplatesList( Locale locale )
386     {
387         ReferenceList listTemplates = new ReferenceList(  );
388 
389         String strEntries = AppPropertiesService.getProperty( PROPERTY_MESSAGE_TEMPLATES_ENTRIES );
390 
391         // extracts each item (separated by a comma) from the list
392         StringTokenizer strTokens = new StringTokenizer( strEntries, "," );
393 
394         while ( strTokens.hasMoreTokens(  ) )
395         {
396             String strMessageKey = strTokens.nextToken(  );
397             String strTemplateDescription = getMessageDescription( strMessageKey, locale );
398             listTemplates.addItem( strMessageKey, strTemplateDescription );
399         }
400 
401         return listTemplates;
402     }
403 
404     /**
405      * Gets the message description from the
406      * @param strMessageKey The message key
407      * @param locale The current locale
408      * @return The message description
409      */
410     private String getMessageDescription( String strMessageKey, Locale locale )
411     {
412         return I18nService.getLocalizedString( PROPERTY_MESSAGE_PREFIX_INTERNATIONALIZATION + strMessageKey +
413             SUFFIX_DESCRIPTION, locale );
414     }
415 
416     /**
417      * Gets the message subject from the
418      * @param strMessageKey The message key
419      * @param locale The current locale
420      * @return The message subject
421      */
422     private String getMessageSubject( String strMessageKey, Locale locale )
423     {
424         return I18nService.getLocalizedString( PROPERTY_MESSAGE_PREFIX_INTERNATIONALIZATION + strMessageKey +
425             SUFFIX_SUBJECT, locale );
426     }
427 
428     /**
429      * Gets the message template from the
430      * @param strMessageKey The message key
431      * @return The message template
432      */
433     private String getMessageTemplate( String strMessageKey )
434     {
435         return AppPropertiesService.getProperty( PROPERTY_MESSAGE_PREFIX + strMessageKey + SUFFIX_TEMPLATE );
436     }
437 
438     @Override
439     public boolean equals( Object obj )
440     {
441         if ( obj == null )
442         {
443             return false;
444         }
445 
446         if ( obj instanceof NotifyUsersRule )
447         {
448             NotifyUsersRule./../../../../../fr/paris/lutece/plugins/document/modules/rulenotifyusers/business/NotifyUsersRule.html#NotifyUsersRule">NotifyUsersRule rule = (NotifyUsersRule) obj;
449 
450             if ( ( this.getAttribute( PARAMETER_SPACE_SOURCE_ID ) == null ) ||
451                     ( this.getAttribute( PARAMETER_MAILINGLIST_ID ) == null ) ||
452                     ( this.getAttribute( PARAMETER_STATE_ID ) == null ) ||
453                     ( this.getAttribute( PARAMETER_MESSAGE_TEMPLATE_KEY ) == null ) ||
454                     ( rule.getAttribute( PARAMETER_SPACE_SOURCE_ID ) == null ) ||
455                     ( rule.getAttribute( PARAMETER_MAILINGLIST_ID ) == null ) ||
456                     ( rule.getAttribute( PARAMETER_STATE_ID ) == null ) ||
457                     ( rule.getAttribute( PARAMETER_MESSAGE_TEMPLATE_KEY ) == null ) )
458             {
459                 return false;
460             }
461 
462             if ( this.getAttribute( PARAMETER_SPACE_SOURCE_ID ).equals( rule.getAttribute( PARAMETER_SPACE_SOURCE_ID ) ) &&
463                     this.getAttribute( PARAMETER_MAILINGLIST_ID ).equals( rule.getAttribute( PARAMETER_MAILINGLIST_ID ) ) &&
464                     this.getAttribute( PARAMETER_STATE_ID ).equals( rule.getAttribute( PARAMETER_STATE_ID ) ) &&
465                     this.getAttribute( PARAMETER_MESSAGE_TEMPLATE_KEY )
466                             .equals( rule.getAttribute( PARAMETER_MESSAGE_TEMPLATE_KEY ) ) )
467             {
468                 return true;
469             }
470         }
471 
472         return false;
473     }
474 }