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.broadcastproxy.business.providers.dolist;
35  
36  import java.io.IOException;
37  import java.util.ArrayList;
38  import java.util.HashMap;
39  import java.util.List;
40  import java.util.Map;
41  
42  import org.apache.commons.lang3.StringUtils;
43  
44  import com.fasterxml.jackson.databind.JsonNode;
45  import com.fasterxml.jackson.databind.ObjectMapper;
46  
47  import fr.paris.lutece.portal.service.util.AppLogService;
48  import fr.paris.lutece.portal.service.util.AppPropertiesService;
49  import fr.paris.lutece.util.httpaccess.HttpAccess;
50  import fr.paris.lutece.util.httpaccess.HttpAccessException;
51  
52  public class DolistAPI
53  {
54  
55      // URLs
56      private static final String PROPERTY_ACCOUNT_ID = AppPropertiesService.getProperty( "dolist.CONSTANTE_ACCOUNT_ID" );
57      private static final String URL_BASE_API = AppPropertiesService.getProperty( "dolist.URL_PATH_BASE_API" );
58      private static final String URL_CONTACTS = AppPropertiesService.getProperty( "dolist.URL_PATH_CONTACTS" );
59      private static final String URL_EXISTS = AppPropertiesService.getProperty( "dolist.URL_PATH_EXISTS" );
60      private static final String URL_ACCOUNT_ID = AppPropertiesService.getProperty( "dolist.URL_PATH_ACCOUNT_ID" );
61      private static final String URL_SUBSRIPTIONS = AppPropertiesService.getProperty( "dolist.URL_PATH_SUBSRIPTIONS" );
62      private static final String URL_INTERESTS = AppPropertiesService.getProperty( "dolist.URL_PATH_INTERESTS" );
63      private static final String URL_CHANNEL = AppPropertiesService.getProperty( "dolist.URL_PATH_CHANNEL" );
64      private static final String URL_GROUP_INTERESTS = AppPropertiesService.getProperty( "dolist.URL_PATH_GROUP_INTERESTS" );
65      private static final String URL_OPERATION_MODE = AppPropertiesService.getProperty( "dolist.URL_PATH_OPERATION_MODE" );
66      private static final String URL_CONTACT_INTEREST_ORIGIN = AppPropertiesService.getProperty( "dolist.URL_PATH_CONTACT_INTEREST_ORIGIN" );
67      private static final String URL_INTERESTS_ACTIVE_ONLY = AppPropertiesService.getProperty( "dolist.URL_PATH_INTERESTS_ACTIVE_ONLY" );
68  
69      // Markers
70      private static final String MARK_HEADER_CONTENT_TYPE = AppPropertiesService.getProperty( "dolist.MARK_HEADER_CONTENT_TYPE" );
71      private static final String MARK_HEADER_ACCEPT = AppPropertiesService.getProperty( "dolist.MARK_HEADER_ACCEPT" );
72      private static final String MARK_HEADER_ACCEPT_LANGUAGE = AppPropertiesService.getProperty( "dolist.MARK_HEADER_ACCEPT_LANGUAGE" );
73      private static final String MARK_HEADER_X_API_KEY = AppPropertiesService.getProperty( "dolist.MARK_HEADER_X_API_KEY" );
74  
75      // Header constants
76      private static final String CONSTANTE_HEADER_CONTENT_TYPE = AppPropertiesService.getProperty( "dolist.CONSTANTE_HEADER_CONTENT_TYPE" );
77      private static final String CONSTANTE_HEADER_ACCEPT = AppPropertiesService.getProperty( "dolist.CONSTANTE_HEADER_ACCEPT" );
78      private static final String CONSTANTE_HEADER_ACCEPT_LANGUAGE = AppPropertiesService.getProperty( "dolist.CONSTANTE_HEADER_ACCEPT_LANGUAGE" );
79      private static final String CONSTANTE_HEADER_X_API_KEY = AppPropertiesService.getProperty( "dolist.CONSTANTE_HEADER_X_API_KEY" );
80      private static final String CONSTANTE_HEADER_X_API_KEY_PREFIX = "dolist.CONSTANTE_HEADER_X_API_KEY_PARIS_";
81      
82      // URL parameter's constants
83      private static final String CONSTANTE_CHANNEL = AppPropertiesService.getProperty( "dolist.CONSTANTE_CHANNEL" );
84      private static final String CONSTANTE_EMAIL_FIELD_ID = AppPropertiesService.getProperty( "dolist.CONSTANTE_EMAIL_FIELD_ID" );
85      private static final String CONSTANTE_CONTACT_INTEREST_ORIGIN = AppPropertiesService.getProperty( "dolist.CONSTANTE_CONTACT_INTEREST_ORIGIN" );
86      private static final String CONSTANTE_INTERESTS_ACTIVE_ONLY = AppPropertiesService.getProperty( "dolist.CONSTANTE_INTERESTS_ACTIVE_ONLY" );
87  
88      private static final String CONSTANTE_REQUEST_BODY_CONTACT = AppPropertiesService.getProperty( "dolist.CONSTANTE_REQUEST_BODY_CONTACT" );
89      private static final String CONSTANTE_REQUEST_BODY_COMPOSITE_LIST = AppPropertiesService.getProperty( "dolist.CONSTANTE_REQUEST_BODY_COMPOSITE_LIST" );
90      private static final String CONSTANTE_REQUEST_BODY_SUBSCRIPTIONS_LIST = AppPropertiesService
91              .getProperty( "dolist.CONSTANTE_REQUEST_BODY_SUBSCRIPTIONS_LIST" );
92      private static final String CONSTANTE_REQUEST_BODY_INTERESTS_LIST = AppPropertiesService.getProperty( "dolist.CONSTANTE_REQUEST_BODY_INTERESTS_LIST" );
93  
94      // Other constants
95      private static final String JSON_NODE_USER_ID = AppPropertiesService.getProperty( "dolist.jsonNode.user.ID" );
96      private static final String JSON_NODE_SEARCH_NAME = AppPropertiesService.getProperty( "dolist.jsonNode.item.Name" );
97      private static final String JSON_NODE_FIELD_LIST = AppPropertiesService.getProperty( "dolist.jsonNode.FieldList" );
98  
99      // Instance variables
100     private String _userEmail;
101     private String _contactId;
102     private String _accountId;
103 
104     /**
105      * get ContactID
106      * 
107      * @param userEmail
108      * @param strAccountId
109      * @return Dolist contact id
110      * @throws Exception
111      */
112     public String getDolistContactId( String userEmail, String strAccountId ) throws Exception
113     {
114         if ( userEmail == null )
115             return null;        
116 
117         if ( userEmail.equals( _userEmail ) && strAccountId.equals( _accountId ) )
118             return _contactId;
119 
120         ObjectMapper mapper = new ObjectMapper( );
121         Map<String, Object> queryParams = new HashMap<>( );
122         String strResponse = null;
123         String strContactId = "";
124 
125         String strUrl = URL_BASE_API + URL_CONTACTS + URL_EXISTS + "?" + URL_ACCOUNT_ID + "=" + strAccountId;
126 
127         try
128         {
129             // Set Headers
130             Map<String, String> mapHeaders = constructHeader( strAccountId );
131 
132             // Set request parameters
133             queryParams.put( JSON_NODE_SEARCH_NAME, userEmail );
134             queryParams.put( JSON_NODE_USER_ID, Integer.parseInt( CONSTANTE_EMAIL_FIELD_ID ) );
135 
136             String strParamsInJson = "{ \"" + CONSTANTE_REQUEST_BODY_COMPOSITE_LIST + "\":{\"FieldValueList\":[" + mapper.writeValueAsString( queryParams ) + "]}}";
137 
138             // Call Dolist API
139             strResponse = callDoPost( strUrl, strParamsInJson, mapHeaders );
140 
141             // Get ContactId from response
142             JsonNode nodes = mapper.readTree( strResponse );
143 
144             if ( Integer.parseInt( nodes.get( JSON_NODE_USER_ID ).asText( ) ) > 0 )
145             {
146                 strContactId = nodes.get( JSON_NODE_USER_ID ).asText( );
147                 if ( strContactId == null || strContactId.isEmpty( ) )
148                 {
149                     throw new Exception( );
150                 }
151 
152                 // set instance variables
153                 _userEmail = userEmail;
154                 _contactId = strContactId;
155                 _accountId = strAccountId;
156             }
157 //            else if ( Integer.parseInt( nodes.get( "Count" ).asText( ) ) > 1 ) // There is some accounts with the same email
158 //            {
159 //            	String strError = "There is some accounts with the same email : '" + userEmail;
160 //                AppLogService.error( strError );
161 //                return null;
162 //            }
163             else // There is not account for this user
164             {
165                 return "";            	
166             }
167 
168         }
169         catch( Exception e )
170         {
171             String strError = "Error occured while getting Contact ID from '" + strUrl + "' : " + e.getMessage( );
172             AppLogService.error( strError + e.getMessage( ), e );
173             throw new Exception( strError );
174         }
175 
176         return strContactId;
177     }
178 
179     /**
180      * ADD user
181      * 
182      * @param eMail
183      * @param strAccountId
184      * @throws IOException
185      */
186     public String addUser( String userEmail, String strAccountId ) throws IOException
187     {
188         ObjectMapper mapper = new ObjectMapper( );
189         Map<String, String> param = new HashMap<>( );
190         List<Map<String, String>> paramsList = new ArrayList<Map<String, String>>( );
191         String strResponse = null;
192         String strContactId = "";
193 
194         // Set URL
195         String strUrl = URL_BASE_API + URL_CONTACTS + "?" + URL_ACCOUNT_ID + "=" + strAccountId;
196 
197         try
198         {
199             // Set Headers
200             Map<String, String> mapHeaders = constructHeader( strAccountId );
201 
202             param.put( "ID", CONSTANTE_EMAIL_FIELD_ID );
203             param.put( "Value", userEmail );
204 
205             paramsList.add( param );
206 
207             String strParamsInJson = "{ \"" + CONSTANTE_REQUEST_BODY_CONTACT + "\":{\"" + JSON_NODE_FIELD_LIST + "\":" + mapper.writeValueAsString( paramsList )
208                     + "}}";
209 
210             // Call Dolist API
211             strResponse = callDoPost( strUrl, strParamsInJson, mapHeaders );
212 
213             // Get ContactId from response
214             JsonNode nodes = mapper.readTree( strResponse );
215 
216             strContactId = nodes.get( JSON_NODE_USER_ID ).asText( );
217         }
218         catch( IOException | HttpAccessException e )
219         {
220             String strError = "Error occured while add/delete user. '" + strUrl + "' : ";
221             AppLogService.error( strError + e.getMessage( ), e );
222             return null;
223         }
224 
225         // set instance variables
226         _userEmail = userEmail;
227         _contactId = strContactId;
228 
229         return strContactId;
230     }
231 
232     /**
233      * get subscriptions Names (label)
234      * 
235      * @param typeSubscription
236      * @param strAccountId
237      * @return json
238      * @throws Exception
239      */
240     public String getAllSubscriptions( String typeSubscription, String strAccountId ) throws Exception
241     {
242         String strResponse = StringUtils.EMPTY;
243         String strUrl = StringUtils.EMPTY;
244 
245         try
246         {
247             if ( typeSubscription.equals( DolistConstants.TYPE_SUBSCRIPTION ) )
248             {
249                 // Get dolist newsletters ids and names (Dolist subscriptions)
250                 strUrl = URL_BASE_API + URL_SUBSRIPTIONS + "?" + URL_CHANNEL + "=" + CONSTANTE_CHANNEL + "&" + URL_ACCOUNT_ID + "=" + strAccountId;
251             }
252             else
253                 if ( typeSubscription.equals( DolistConstants.TYPE_INTEREST ) )
254                 {
255                     // Get dolist alerts ids and names (Dolist interests)
256                     strUrl = URL_BASE_API + URL_INTERESTS + URL_GROUP_INTERESTS + "?" + URL_ACCOUNT_ID + "=" + strAccountId + "&"
257                             + URL_INTERESTS_ACTIVE_ONLY + "=" + CONSTANTE_INTERESTS_ACTIVE_ONLY;
258                 }
259 
260             Map<String, String> mapHeaders = constructHeader( strAccountId );
261 
262             strResponse = callDoGet( strUrl, mapHeaders );
263         }
264         catch( IOException e )
265         {
266             String strError = "Error occured while getting the list of subscriptions names '" + strUrl + "' : " + e.getMessage( );
267             AppLogService.error( strError + e.getMessage( ), e );
268             throw new Exception( strError );
269         }
270 
271         return strResponse;
272         
273     }
274 
275     /**
276      * get Contact's subscriptions
277      * 
278      * @param userEmail
279      * @param strAccountId
280      * @return json
281      * @throws Exception
282      */
283     public String getUserSubscriptions( String userEmail, String typeSubscription, String strAccountId ) throws Exception
284     {
285         String strResponse = StringUtils.EMPTY;
286         String strUrl = StringUtils.EMPTY;
287 
288         // Get contact ID
289         String idContact = getDolistContactId( userEmail, strAccountId );
290 
291         if ( idContact == null )
292         	return null;
293         
294         // if Email (user) does not exist
295         if ( idContact.equals( "" ) )
296         	return "";
297 
298         try
299         {
300             if ( typeSubscription.equals( DolistConstants.TYPE_SUBSCRIPTION ) )
301             {
302                 // Get user newsletters (Dolist subscriptions)
303                 strUrl = URL_BASE_API + URL_CONTACTS + "/" + idContact + URL_SUBSRIPTIONS + "?" + URL_ACCOUNT_ID + "=" + strAccountId + "&"
304                         + URL_CHANNEL + "=" + CONSTANTE_CHANNEL;
305             }
306             else
307                 if ( typeSubscription.equals( DolistConstants.TYPE_INTEREST ) )
308                 {
309                     // Get user alerts (Dolist interests)
310                     strUrl = URL_BASE_API + URL_CONTACTS + "/" + idContact + URL_INTERESTS + "?" + URL_ACCOUNT_ID + "=" + strAccountId;
311                 }
312 
313             Map<String, String> mapHeaders = constructHeader( strAccountId );
314 
315             strResponse = callDoGet( strUrl, mapHeaders );
316 
317         }
318         catch( IOException e )
319         {
320             String strError = "Error occured while getting Contact subscriptions list from '" + strUrl + "' : " + e.getMessage( );
321             AppLogService.error( strError + e.getMessage( ), e );
322             throw new Exception( strError );
323         }
324 
325         return strResponse;
326         
327     }
328 
329     /**
330      * update subscriptions
331      * 
332      * @param ContactName
333      * @param mapSubscriptions
334      * @param typeSubscription
335      * @param strAccountId
336      * @return response
337      * @throws Exception
338      */
339     public String updateSubscribtions( String userEmail, Map<String, String> subscriptionsToUpdate, String strAccountId ) throws Exception
340     {
341         ObjectMapper mapper = new ObjectMapper( );
342         List<Map<String, Object>> listModifiedSubscriptions = new ArrayList<>( );
343 
344         // Get dolist contact ID
345         String userDolistId = getDolistContactId( userEmail, strAccountId );
346 
347         // if Email (user) does not exist ==> Create user
348         if ( userDolistId.equals( "" ) || userDolistId.equals( "0" )  )
349             userDolistId = addUser( userEmail, strAccountId );
350 
351         // Set Headers
352         Map<String, String> mapHeaders = constructHeader( strAccountId );
353 
354         // Update Dolist Subscriptions
355         String strUrl = URL_BASE_API + URL_CONTACTS + "/" + userDolistId + URL_SUBSRIPTIONS + "?" + URL_ACCOUNT_ID + "=" + strAccountId;
356 
357         // Set request parameters
358         for ( Map.Entry<String, String> subStatus : subscriptionsToUpdate.entrySet( ) )
359         {
360             Map<String, Object> sub = new HashMap<>( );
361             sub.put( "SubscriptionID", Integer.parseInt( subStatus.getKey( ) ) );
362             sub.put( "Status", subStatus.getValue( ) );
363             listModifiedSubscriptions.add( sub );
364         }
365 
366         String strParamsInJson = "{ \"" + CONSTANTE_REQUEST_BODY_SUBSCRIPTIONS_LIST + "\":" + mapper.writeValueAsString( listModifiedSubscriptions ) + "}";
367 
368         // Call http method (PUT)
369         String response = callDoPut( strUrl, strParamsInJson, mapHeaders );
370 
371         return response;
372     }
373 
374     public String updateInterests( String userEmail, List<Integer> subscriptionsToUpdate, String action, String strAccountId ) throws Exception
375     {
376         ObjectMapper mapper = new ObjectMapper( );
377         String response = StringUtils.EMPTY;
378 
379         // Get dolist contact ID
380         String userDolistId = getDolistContactId( userEmail, strAccountId );
381         
382         // if Email (user) does not exist ==> Create user
383         if ( userDolistId.equals( "" ) )
384             userDolistId = addUser( userEmail, strAccountId );
385 
386         // Set Headers
387         Map<String, String> mapHeaders = constructHeader( strAccountId );
388 
389         String strUrl = URL_BASE_API + URL_CONTACTS + "/" + userDolistId + URL_INTERESTS + "?" + URL_CONTACT_INTEREST_ORIGIN + "="
390                 + CONSTANTE_CONTACT_INTEREST_ORIGIN + "&" + URL_OPERATION_MODE + "=" + action + "&" + URL_ACCOUNT_ID + "=" + strAccountId;
391 
392         try
393         {
394             // Update Dolist Interests
395             String strParamsInJson = "{\"" + CONSTANTE_REQUEST_BODY_INTERESTS_LIST + "\":" + mapper.writeValueAsString( subscriptionsToUpdate ) + "}";
396 
397             // Call http method (PUT)
398             response = callDoPut( strUrl, strParamsInJson, mapHeaders );
399 
400         }
401         catch( IOException e )
402         {
403             String strError = "Error connecting to '" + strUrl + "' : " + e.getMessage( );
404             AppLogService.error( strError + e.getMessage( ), e );
405             throw new Exception( strError );
406         }
407 
408         return response;
409     }
410 
411     /*** HTTP METHODS ***/
412 
413     /**
414      * call get method
415      * 
416      * @param strUrl
417      * @param mapHeaders
418      * @param typeSubscription
419      * @return the response message
420      * @throws IOException
421      */
422     private String callDoGet( String strUrl, Map<String, String> mapHeaders ) throws IOException
423     {
424         HttpAccess httpAccess = new HttpAccess( );
425 
426         String strResponse = StringUtils.EMPTY;
427 
428         try
429         {
430             strResponse = httpAccess.doGet( strUrl, null, null, mapHeaders );
431         }
432         catch( HttpAccessException e )
433         {
434             AppLogService.error( "Returned Dolist error : " + strResponse );
435         }
436 
437         return strResponse;
438     }
439 
440     /**
441      * call post method
442      * 
443      * @param strUrl
444      * @param params
445      * @param mapHeaders
446      * @return true or false
447      * @throws IOException
448      * @throws HttpAccessException
449      */
450     private String callDoPost( String strUrl, String jsonParams, Map<String, String> mapHeaders ) throws IOException, HttpAccessException
451     {
452         DolistHttpAccesstproxy/business/providers/dolist/DolistHttpAccess.html#DolistHttpAccess">DolistHttpAccess dlhttpaccess = new DolistHttpAccess( );
453 
454         return dlhttpaccess.doPost( strUrl, jsonParams, mapHeaders );
455     }
456 
457     /**
458      * call post method
459      * 
460      * @param strUrl
461      * @param params
462      * @param mapHeaders
463      * @return true or false
464      * @throws IOException
465      * @throws HttpAccessException
466      */
467     private String callDoPut( String strUrl, String jsonParams, Map<String, String> mapHeaders ) throws IOException, HttpAccessException
468     {
469         DolistHttpAccesstproxy/business/providers/dolist/DolistHttpAccess.html#DolistHttpAccess">DolistHttpAccess dlhttpaccess = new DolistHttpAccess( );
470 
471         return dlhttpaccess.doPut( strUrl, jsonParams, mapHeaders );
472     }
473 
474     private Map<String, String> constructHeader( String strAccountId )
475     {
476         Map<String, String> mapHeader = new HashMap<>( );
477         
478         String strApiKey = CONSTANTE_HEADER_X_API_KEY;
479         if ( StringUtils.isNotEmpty( strAccountId ) && !strAccountId.equals( PROPERTY_ACCOUNT_ID )  )
480         {
481             strApiKey = AppPropertiesService.getProperty( CONSTANTE_HEADER_X_API_KEY_PREFIX + strAccountId  ) ;
482         }
483         
484         mapHeader.put( MARK_HEADER_X_API_KEY, strApiKey );
485         mapHeader.put( MARK_HEADER_CONTENT_TYPE, CONSTANTE_HEADER_CONTENT_TYPE );
486         mapHeader.put( MARK_HEADER_ACCEPT, CONSTANTE_HEADER_ACCEPT );
487         mapHeader.put( MARK_HEADER_ACCEPT_LANGUAGE, CONSTANTE_HEADER_ACCEPT_LANGUAGE );
488 
489         return mapHeader;
490     }
491     
492 }