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