1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.newsletter.service;
35
36 import fr.paris.lutece.plugins.newsletter.business.NewsLetter;
37 import fr.paris.lutece.plugins.newsletter.business.NewsLetterHome;
38 import fr.paris.lutece.plugins.newsletter.business.Subscriber;
39 import fr.paris.lutece.plugins.newsletter.business.SubscriberHome;
40 import fr.paris.lutece.plugins.newsletter.business.topic.NewsletterTopic;
41 import fr.paris.lutece.plugins.newsletter.business.topic.NewsletterTopicHome;
42 import fr.paris.lutece.plugins.newsletter.service.topic.INewsletterTopicService;
43 import fr.paris.lutece.plugins.newsletter.service.topic.NewsletterTopicService;
44 import fr.paris.lutece.plugins.newsletter.util.NewsLetterConstants;
45 import fr.paris.lutece.plugins.newsletter.util.NewsletterUtils;
46 import fr.paris.lutece.portal.business.user.AdminUser;
47 import fr.paris.lutece.portal.service.mail.MailService;
48 import fr.paris.lutece.portal.service.plugin.Plugin;
49 import fr.paris.lutece.portal.service.plugin.PluginService;
50 import fr.paris.lutece.portal.service.spring.SpringContextService;
51 import fr.paris.lutece.portal.service.template.AppTemplateService;
52 import fr.paris.lutece.portal.service.util.AppLogService;
53 import fr.paris.lutece.portal.service.util.AppPathService;
54 import fr.paris.lutece.portal.service.util.AppPropertiesService;
55 import fr.paris.lutece.portal.service.util.CryptoService;
56 import fr.paris.lutece.util.html.HtmlTemplate;
57 import fr.paris.lutece.util.mail.UrlAttachment;
58 import fr.paris.lutece.util.string.StringUtil;
59
60 import java.io.BufferedWriter;
61 import java.io.ByteArrayOutputStream;
62 import java.io.IOException;
63 import java.io.OutputStreamWriter;
64 import java.io.Serializable;
65 import java.io.UnsupportedEncodingException;
66 import java.util.ArrayList;
67 import java.util.Collection;
68 import java.util.Collections;
69 import java.util.HashMap;
70 import java.util.List;
71 import java.util.Locale;
72 import java.util.Map;
73
74 import org.apache.commons.lang3.StringUtils;
75
76 import au.com.bytecode.opencsv.CSVWriter;
77
78
79
80
81
82 public class NewsletterService implements Serializable
83 {
84
85
86
87 public static final String BEAN_NAME = "newsletter.newsletterService";
88
89
90
91
92 private static final long serialVersionUID = 1644159439192572037L;
93
94
95 private static final String PROPERTY_ABSOLUTE_URL_MAIL = "newsletter.absolute.mail.url";
96 private static final String PROPERTY_PATH_IMAGE_NEWSLETTER_TEMPLATE = "newsletter.path.image.newsletter.template";
97 private static final String PROPERTY_NO_SECURED_IMG_FOLDER = "newsletter.nosecured.img.folder.name";
98 private static final String PROPERTY_WEBAPP_PATH = "newsletter.nosecured.webapp.path";
99 private static final String PROPERTY_WEBAPP_URL = "newsletter.nosecured.webapp.url";
100 private static final String PROPERTY_NO_SECURED_IMG_OPTION = "newsletter.nosecured.img.option";
101 private static final String PROPERTY_UNSUBSCRIBE_KEY_ENCRYPTION_ALGORITHM = "newsletter.unsubscribe.key.encryptionAlgorithm";
102
103 private NewsletterTopicService _newsletterTopicService;
104
105
106
107
108
109
110 public static NewsletterService getService( )
111 {
112 return SpringContextService.getBean( BEAN_NAME );
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 public void sendMail( NewsLetter newsletter, String strObject, String strBaseUrl, HtmlTemplate templateNewsletter, Collection<Subscriber> listSubscribers )
130 {
131 List<UrlAttachment> urlAttachments = null;
132 HtmlTemplate templateNewsletterToUse = templateNewsletter;
133 if ( isMhtmlActivated( ) )
134 {
135
136 boolean useAbsoluteUrl = isAbsoluteUrl( );
137 String strTemplate = templateNewsletterToUse.getHtml( );
138 strTemplate = StringUtil.substitute( strTemplate, strBaseUrl, NewsLetterConstants.WEBAPP_PATH_FOR_LINKSERVICE );
139 urlAttachments = MailService.getUrlAttachmentList( strTemplate, strBaseUrl, useAbsoluteUrl );
140
141
142 if ( !useAbsoluteUrl )
143 {
144 templateNewsletterToUse.substitute( strBaseUrl, strBaseUrl.replaceFirst( "https?://[^/]+/", "/" ) );
145 }
146 else
147 {
148 String strContent = NewsletterUtils.rewriteUrls( templateNewsletterToUse.getHtml( ), strBaseUrl );
149 templateNewsletterToUse = new HtmlTemplate( strContent );
150 }
151 }
152
153 for ( Subscriber subscriber : listSubscribers )
154 {
155 HtmlTemplate t = new HtmlTemplate( templateNewsletterToUse );
156
157 t.substitute( NewsLetterConstants.MARK_SUBSCRIBER_EMAIL_EACH, subscriber.getEmail( ) );
158 if ( Boolean.parseBoolean( newsletter.getUnsubscribe( ) ) )
159 {
160 String strUnsubscribeKey = getUnsubscriptionKey( subscriber.getEmail( ) );
161 t.substitute( NewsLetterConstants.MARK_UNSUBSCRIBE_KEY_EACH, strUnsubscribeKey );
162 }
163
164 String strNewsLetterCode = t.getHtml( );
165
166 if ( ( urlAttachments == null ) || ( urlAttachments.size( ) == 0 ) )
167 {
168 MailService.sendMailHtml( subscriber.getEmail( ), newsletter.getNewsletterSenderName( ), newsletter.getNewsletterSenderMail( ), strObject,
169 strNewsLetterCode );
170 }
171 else
172 {
173 MailService.sendMailMultipartHtml( subscriber.getEmail( ), newsletter.getNewsletterSenderName( ), newsletter.getNewsletterSenderMail( ),
174 strObject, strNewsLetterCode, urlAttachments );
175 }
176 }
177 }
178
179
180
181
182
183
184 public boolean isAbsoluteUrl( )
185 {
186 boolean useAbsoluteUrl = false;
187 String strUseAbsoluteUrl = AppPropertiesService.getProperty( PROPERTY_ABSOLUTE_URL_MAIL );
188
189 if ( ( strUseAbsoluteUrl != null ) && strUseAbsoluteUrl.equalsIgnoreCase( Boolean.TRUE.toString( ) ) )
190 {
191 useAbsoluteUrl = true;
192 }
193
194 return useAbsoluteUrl;
195 }
196
197
198
199
200
201
202 public boolean isMhtmlActivated( )
203 {
204 String strProperty = AppPropertiesService.getProperty( NewsLetterConstants.PROPERTY_MAIL_MULTIPART );
205 return ( strProperty != null ) && Boolean.valueOf( strProperty ).booleanValue( );
206 }
207
208
209
210
211
212
213
214
215 public byte [ ] getSubscribersCsvExport( int nNewsletterId )
216 {
217 byte [ ] byteSubscribersList = null;
218
219 try
220 {
221 ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream( );
222 CSVWriter writer = new CSVWriter( new BufferedWriter( new OutputStreamWriter( byteArrayStream, "UTF-8" ) ) );
223 Collection<Subscriber> listSubscriber = SubscriberHome.findSubscribers( nNewsletterId, getPlugin( ) );
224
225 for ( Subscriber subscriber : listSubscriber )
226 {
227 String [ ] arraySubscriber = new String [ 3];
228 arraySubscriber [0] = Integer.toString( subscriber.getId( ) );
229 arraySubscriber [1] = subscriber.getEmail( );
230 arraySubscriber [2] = subscriber.getDateSubscription( ).toString( );
231 writer.writeNext( arraySubscriber );
232 }
233
234 writer.close( );
235 byteSubscribersList = byteArrayStream.toByteArray( );
236 }
237 catch( UnsupportedEncodingException e )
238 {
239 AppLogService.error( e );
240 }
241 catch( IOException e )
242 {
243 AppLogService.error( e );
244 }
245
246 return byteSubscribersList;
247 }
248
249
250
251
252
253
254
255
256
257
258
259 public void removeSubscriberFromNewsletter( Subscriber subscriber, int nNewsletterId, Plugin plugin )
260 {
261
262 NewsLetter newsletter = NewsLetterHome.findByPrimaryKey( nNewsletterId, plugin );
263
264 if ( ( subscriber != null ) && ( newsletter != null ) )
265 {
266 int nSubscriberId = subscriber.getId( );
267
268
269 if ( NewsLetterHome.findRegistration( nNewsletterId, nSubscriberId, plugin ) )
270 {
271
272 NewsLetterHome.removeSubscriber( nNewsletterId, nSubscriberId, plugin );
273 }
274
275
276
277
278 if ( SubscriberHome.findNewsLetters( nSubscriberId, plugin ) == 0 )
279 {
280 SubscriberHome.remove( nSubscriberId, plugin );
281 }
282 }
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300 public String generateNewsletterHtmlCode( NewsLetter newsletter, int nTemplateNewsLetterId, String strBaseUrl, AdminUser user, Locale locale )
301 {
302 String strTemplatePath = NewsletterUtils.getHtmlTemplatePath( nTemplateNewsLetterId, getPlugin( ) );
303
304
305 if ( strTemplatePath == null )
306 {
307 return null;
308 }
309
310 Map<String, Object> model = new HashMap<String, Object>( );
311 List<NewsletterTopic> listTopics = NewsletterTopicHome.findAllByIdNewsletter( newsletter.getId( ), getPlugin( ) );
312
313
314 Collections.sort( listTopics );
315
316 int nCurrentSection = 0;
317 String [ ] strContentBySection = new String [ newsletter.getNbSections( )];
318 List<NewsletterTopic> listSelectedTopics = new ArrayList<NewsletterTopic>( );
319 for ( int i = 0; i < listTopics.size( ) + 1; i++ )
320 {
321 NewsletterTopic newsletterTopic = null;
322 if ( i < listTopics.size( ) )
323 {
324 newsletterTopic = listTopics.get( i );
325 }
326 if ( newsletterTopic != null && newsletterTopic.getSection( ) == nCurrentSection )
327 {
328 listSelectedTopics.add( newsletterTopic );
329 }
330 else
331 {
332 if ( nCurrentSection != 0 )
333 {
334 StringBuilder sbSectionContent = new StringBuilder( );
335 for ( NewsletterTopic topic : listSelectedTopics )
336 {
337 sbSectionContent.append( getNewsletterTopicService( ).getTopicContent( topic, user, locale ) );
338 }
339 if ( nCurrentSection - 1 < strContentBySection.length )
340 {
341 strContentBySection [nCurrentSection - 1] = sbSectionContent.toString( );
342 }
343 }
344 if ( newsletterTopic != null )
345 {
346 nCurrentSection = newsletterTopic.getSection( );
347 listSelectedTopics = new ArrayList<NewsletterTopic>( );
348 listSelectedTopics.add( newsletterTopic );
349 }
350 }
351 }
352
353 model.put( NewsLetterConstants.MARK_CONTENT, strContentBySection [0] );
354 for ( int i = 0; i < strContentBySection.length; i++ )
355 {
356 model.put( NewsLetterConstants.MARK_CONTENT_SECTION + Integer.toString( i + 1 ), strContentBySection [i] );
357 }
358 model.put( NewsLetterConstants.MARK_BASE_URL, strBaseUrl );
359
360 HtmlTemplate templateNewsLetter = AppTemplateService.getTemplate( strTemplatePath, locale, model );
361
362 return templateNewsLetter.getHtml( );
363 }
364
365
366
367
368
369
370
371
372 public String getImageFolderPath( String strBaseUrl )
373 {
374 return strBaseUrl + AppPropertiesService.getProperty( PROPERTY_PATH_IMAGE_NEWSLETTER_TEMPLATE );
375 }
376
377
378
379
380
381
382 public boolean useUnsecuredImages( )
383 {
384 return Boolean.parseBoolean( AppPropertiesService.getProperty( PROPERTY_NO_SECURED_IMG_OPTION ) );
385 }
386
387
388
389
390
391
392 public String getUnsecuredImagefolder( )
393 {
394 return AppPropertiesService.getProperty( PROPERTY_NO_SECURED_IMG_FOLDER ) + NewsLetterConstants.CONSTANT_SLASH;
395 }
396
397
398
399
400
401
402 public String getUnsecuredFolderPath( )
403 {
404 return AppPropertiesService.getProperty( PROPERTY_WEBAPP_PATH, AppPathService.getWebAppPath( ) + NewsLetterConstants.CONSTANT_SLASH );
405 }
406
407
408
409
410
411
412 public String getUnsecuredWebappUrl( )
413 {
414 return AppPropertiesService.getProperty( PROPERTY_WEBAPP_URL, AppPathService.getBaseUrl( ) );
415 }
416
417
418
419
420
421
422
423
424 public String getUnsubscriptionKey( String strEmail )
425 {
426 return CryptoService.encrypt( CryptoService.getCryptoKey( ) + strEmail,
427 AppPropertiesService.getProperty( PROPERTY_UNSUBSCRIBE_KEY_ENCRYPTION_ALGORITHM ) );
428 }
429
430
431
432
433
434
435
436
437
438
439
440 public void modifySectionNumber( int nOldSectionNumber, int nNewSectionNumber, int nTemplateId )
441 {
442
443 if ( nOldSectionNumber != nNewSectionNumber && nNewSectionNumber > 0 )
444 {
445 Collection<NewsLetter> listNewsletters = NewsLetterHome.findAllByTemplateId( nTemplateId, getPlugin( ) );
446 for ( NewsLetter newsletter : listNewsletters )
447 {
448
449 if ( nOldSectionNumber > nNewSectionNumber )
450 {
451 List<NewsletterTopic> listTopics = NewsletterTopicHome.findAllByIdNewsletter( newsletter.getId( ), getPlugin( ) );
452 int nNewOrder = NewsletterTopicHome.getNewOrder( newsletter.getId( ), nNewSectionNumber, getPlugin( ) );
453 for ( NewsletterTopic topic : listTopics )
454 {
455 if ( topic.getSection( ) > nNewSectionNumber )
456 {
457 topic.setSection( nNewSectionNumber );
458 topic.setOrder( nNewOrder );
459 nNewOrder++;
460 NewsletterTopicHome.updateNewsletterTopic( topic, getPlugin( ) );
461 }
462 }
463 }
464 newsletter.setNbSections( nNewSectionNumber );
465 NewsLetterHome.update( newsletter, getPlugin( ) );
466 }
467 }
468 }
469
470
471
472
473
474
475 private Plugin getPlugin( )
476 {
477 return PluginService.getPlugin( NewsletterPlugin.PLUGIN_NAME );
478 }
479
480
481
482
483
484
485 private NewsletterTopicService getNewsletterTopicService( )
486 {
487 if ( _newsletterTopicService == null )
488 {
489 _newsletterTopicService = NewsletterTopicService.getService( );
490 }
491 return _newsletterTopicService;
492 }
493
494
495
496
497
498
499
500
501
502
503
504 public void copyExistingNewsletter( NewsLetter newsletter, AdminUser user, Locale locale )
505 {
506 int oldNewsLetterId = newsletter.getId( );
507 NewsLetterHome.create( newsletter, getPlugin( ) );
508
509
510 List<NewsletterTopic> topicList = NewsletterTopicHome.findAllByIdNewsletter( oldNewsLetterId, getPlugin( ) );
511 topicList.stream( ).forEach( ( NewsletterTopic nt ) -> {
512 int oldTopicId = nt.getId( );
513 nt.setIdNewsletter( newsletter.getId( ) );
514 for ( INewsletterTopicService service : SpringContextService.getBeansOfType( INewsletterTopicService.class ) )
515 {
516 if ( StringUtils.equals( service.getNewsletterTopicTypeCode( ), nt.getTopicTypeCode( ) ) )
517 {
518 NewsletterTopicHome.insertNewsletterTopic( nt, getPlugin( ) );
519 service.copyNewsletterTopic( oldTopicId, nt, user, locale );
520 }
521 }
522 } );
523 }
524 }