001/*
002 *  Copyright 2020 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.mobileapp;
017
018import java.util.HashMap;
019import java.util.List;
020import java.util.Map;
021
022import org.apache.avalon.framework.component.Component;
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.avalon.framework.service.Serviceable;
026import org.apache.commons.lang3.StringUtils;
027
028import org.ametys.core.util.I18nUtils;
029import org.ametys.plugins.workspaces.ObservationConstants;
030import org.ametys.plugins.workspaces.project.ProjectsCatalogueManager;
031import org.ametys.plugins.workspaces.project.objects.Project;
032import org.ametys.runtime.i18n.I18nizableText;
033import org.ametys.runtime.i18n.I18nizableTextParameter;
034import org.ametys.runtime.plugin.component.AbstractLogEnabled;
035
036/**
037 * Helper to handle project feeds
038 */
039public class FeedHelper extends AbstractLogEnabled implements Serviceable, Component
040{
041    /** Avalon Role */
042    public static final String ROLE = FeedHelper.class.getName();
043    
044    /** I18N Utils */
045    protected I18nUtils _i18nUtils;
046    
047    /** The project catalogue manager component */
048    protected ProjectsCatalogueManager _projectsCatalogueManager;
049
050    public void service(ServiceManager manager) throws ServiceException
051    {
052        _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE);
053        _projectsCatalogueManager = (ProjectsCatalogueManager) manager.lookup(ProjectsCatalogueManager.ROLE);
054    }
055    
056
057    /**
058     * Generate a map of project names with the basic projects informations to return
059     * @return a map of basic information about projects
060     */
061    public Map<String, Map<String, Object>> getProjects()
062    {
063        Map<String, Map<String, Object>> result = new HashMap<>();
064        List<Map<String, Object>> userProjects = _projectsCatalogueManager.getUserProjects();
065        for (Map<String, Object> fullProjectMap : userProjects)
066        {
067            String name = (String) fullProjectMap.get("name");
068            Map<String, Object> neededInfos = new HashMap<>();
069
070            neededInfos.put("name", name);
071            neededInfos.put("description", fullProjectMap.get("description"));
072            neededInfos.put("title", fullProjectMap.get("title"));
073            neededInfos.put("url", fullProjectMap.get("url"));
074            neededInfos.put("illustration", fullProjectMap.get("illustration"));
075            neededInfos.put("id", fullProjectMap.get("id"));
076            neededInfos.put("category", fullProjectMap.get("category"));
077            
078            result.put(name, neededInfos);
079        }
080        
081        return result;
082    }
083    
084    /**
085     * Transform a {@link Project} into a json map
086     * @param project the project to parse
087     * @return a json map
088     */
089    public Map<String, Object> projectToMap(Project project)
090    {
091        return _projectsCatalogueManager.detailedProject2json(project);
092    }
093    /**
094     * Add infos to the event, so it can be displayed by the app
095     * @param event the event to parse
096     * @param project the project, as a json map (see {@link FeedHelper#projectToMap(Project)})
097     * @param lang language to use to translate the short description
098     * @return a map to return in json
099     */
100    public Map<String, Object> getEventInfos(Map<String, Object> event, Map<String, Object> project, String lang)
101    {
102        Map<String, Object> result = new HashMap<>();
103        
104        result.putAll(event);
105        
106        result.put("project", project);
107        
108        @SuppressWarnings("unchecked")
109        Map<String, String> author = new HashMap<>((Map<String, String>) event.get("author"));
110        author.put("avatarUrl", "/_plugins/workspaces/user/" + author.get("populationId") + "/" + author.get("login") + "/image_" + PostConstants.IMAGE_SIZE);
111        result.put("author", author);
112        
113        result.put("short-description", getEventDescription(event, lang));
114
115        result.put("content_id", getEventObjectId(event));
116        result.put("content_url", getEventUrl(event));
117        
118        return result;
119    }
120    
121    /**
122     * Generate a description for this event
123     * @param event the event to describe
124     * @return a String of the description
125     */
126    @SuppressWarnings("unchecked")
127    protected String getEventObjectId(Map<String, Object> event)
128    {
129        String id = null;
130        String eventType = (String) event.get("type");
131        
132        switch (eventType)
133        {
134            /*
135             * RESOURCES
136             */
137            case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED :
138            case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED :
139            case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED :
140                id = (String) ((Map<String, Object>) event.get("file")).get("id");
141                break;
142
143            /*
144             * CALENDAR
145             */
146            case org.ametys.plugins.explorer.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED :
147            case org.ametys.plugins.explorer.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED :
148                id = (String) event.get("eventId");
149                break;
150
151            /*
152             * THREAD
153             */
154            case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_CREATED :
155            case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_POST_CREATED :
156                id = (String) event.get("threadId");
157                break;
158
159            /*
160             * MEMBER
161             */
162            case ObservationConstants.EVENT_MEMBER_ADDED :
163                // no id available
164                break;
165            case ObservationConstants.EVENT_WALLCONTENT_ADDED :
166                id = (String) event.get("contentId");
167                break;
168
169            /**
170             * WIKI
171             */
172            case ObservationConstants.EVENT_EDITIONFO_CREATED :
173            case ObservationConstants.EVENT_EDITIONFO_UPDATED :
174            case ObservationConstants.EVENT_EDITIONFO_RENAMED :
175            case ObservationConstants.EVENT_EDITIONFO_DELETED :
176                id = (String) event.get("pageId");
177                break;
178
179            /**
180             * TASK
181             */
182            case org.ametys.plugins.explorer.ObservationConstants.EVENT_TASK_CREATED :
183            case org.ametys.plugins.explorer.ObservationConstants.EVENT_TASK_ASSIGNED :
184            case org.ametys.plugins.explorer.ObservationConstants.EVENT_TASK_STATUS_CHANGED :
185                id = (String) event.get("taskId");
186                break;
187            default:
188                break;
189        }
190        
191        return id;
192    }
193    
194
195    /**
196     * Generate a description for this event
197     * @param event the event to describe
198     * @return a String of the description
199     */
200    protected String getEventUrl(Map<String, Object> event)
201    {
202        String url = null;
203        String eventType = (String) event.get("type");
204        
205        switch (eventType)
206        {
207            /*
208             * RESOURCES
209             */
210            case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED :
211            case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED :
212            case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED :
213                url = (String) event.get("parentFolderUrl");
214                break;
215
216            /*
217             * CALENDAR
218             */
219            case org.ametys.plugins.explorer.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED :
220            case org.ametys.plugins.explorer.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED :
221                url = (String) event.get("eventUrl");
222                break;
223
224            /*
225             * THREAD
226             */
227            case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_CREATED :
228            case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_POST_CREATED :
229                url = (String) event.get("threadUrl");
230                break;
231
232            /*
233             * MEMBER
234             */
235            case ObservationConstants.EVENT_MEMBER_ADDED :
236                // no url available
237                break;
238            case ObservationConstants.EVENT_WALLCONTENT_ADDED :
239                // no url available
240                break;
241
242            /**
243             * WIKI
244             */
245            case ObservationConstants.EVENT_EDITIONFO_CREATED :
246            case ObservationConstants.EVENT_EDITIONFO_UPDATED :
247            case ObservationConstants.EVENT_EDITIONFO_RENAMED :
248            case ObservationConstants.EVENT_EDITIONFO_DELETED :
249                url = (String) event.get("pageUrl");
250                break;
251
252            /**
253             * TASK
254             */
255            case org.ametys.plugins.explorer.ObservationConstants.EVENT_TASK_CREATED :
256            case org.ametys.plugins.explorer.ObservationConstants.EVENT_TASK_ASSIGNED :
257            case org.ametys.plugins.explorer.ObservationConstants.EVENT_TASK_STATUS_CHANGED :
258                url = (String) event.get("taskUrl");
259                break;
260            default:
261                break;
262        }
263        if (StringUtils.isBlank(url))
264        {
265            url = (String) event.get("projectUrl");
266        }
267        return url;
268    }
269
270    /**
271     * Generate a description for this event
272     * @param event the event to describe
273     * @param lang the language to use
274     * @return a String of the description
275     */
276    @SuppressWarnings("unchecked")
277    protected String getEventDescription(Map<String, Object> event, String lang)
278    {
279        String description = null;
280        
281        String eventType = (String) event.get("type");
282        
283        Integer amount = (Integer) event.get("amount");
284        String i18nKey = null;
285        Map<String, I18nizableTextParameter> parameters = new HashMap<>();
286        parameters.put("author", new I18nizableText(((Map<String, String>) event.get("author")).get("fullname")));
287        parameters.put("project", new I18nizableText((String) event.get("projectTitle")));
288        parameters.put("nb", new I18nizableText(amount.toString()));
289        
290        switch (eventType)
291        {
292
293            /*
294             * RESOURCES
295             */
296            case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED :
297                parameters.put("folder", new I18nizableText((String) event.get("parentFolder")));
298                if (amount == 1)
299                {
300                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_ADDED_DESC";
301                }
302                else
303                {
304                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_ADDED_MULTI_DESC";
305                }
306                break;
307            case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED :
308                parameters.put("folder", new I18nizableText((String) event.get("parentFolder")));
309                if (amount == 1)
310                {
311                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_UPDATED_DESC";
312                }
313                else
314                {
315                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_UPDATED_MULTI_DESC";
316                }
317                break;
318            case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED :
319                parameters.put("folder", new I18nizableText((String) event.get("parentFolder")));
320                if (amount == 1)
321                {
322                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_RENAMED_DESC";
323                }
324                else
325                {
326                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_RENAMED_MULTI_DESC";
327                }
328                break;
329
330            /*
331             * CALENDAR
332             */
333            case org.ametys.plugins.explorer.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED :
334                parameters.put("calendar", new I18nizableText((String) event.get("calendarTitle")));
335                if (amount == 1)
336                {
337                    parameters.put("event", new I18nizableText(getTitles(event, "events", "eventTitle")));
338                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_ADDED_DESC";
339                }
340                else
341                {
342                    parameters.put("events", new I18nizableText(getTitles(event, "events", "eventTitle")));
343                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_ADDED_MULTI_DESC";
344                }
345                break;
346            case org.ametys.plugins.explorer.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED :
347                parameters.put("calendar", new I18nizableText((String) event.get("calendarTitle")));
348                if (amount == 1)
349                {
350                    parameters.put("event", new I18nizableText(getTitles(event, "events", "eventTitle")));
351                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_UPDATED_DESC";
352                }
353                else
354                {
355                    parameters.put("events", new I18nizableText(getTitles(event, "events", "eventTitle")));
356                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_UPDATED_MULTI_DESC";
357                }
358                break;
359
360            /*
361             * THREAD
362             */
363            case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_CREATED :
364                if (amount == 1)
365                {
366                    parameters.put("thread", new I18nizableText(getTitles(event, "threads", "threadTitle")));
367                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_CREATED_DESC";
368                }
369                else
370                {
371                    parameters.put("threads", new I18nizableText(getTitles(event, "threads", "threadTitle")));
372                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_CREATED_MULTI_DESC";
373                }
374                break;
375            case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_POST_CREATED :
376                parameters.put("thread", new I18nizableText(getTitles(event, "threads", "threadTitle")));
377                i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_POST_CREATED_DESC";
378                break;
379
380            /*
381             * MEMBER
382             */
383            case ObservationConstants.EVENT_MEMBER_ADDED :
384                if (amount == 1)
385                {
386                    parameters.put("member", new I18nizableText((String) event.get("member")));
387                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_MEMBER_ADDED_DESC";
388                }
389                else
390                {
391                    List<String> members = (List<String>) event.get("members");
392                    parameters.put("members", new I18nizableText(String.join(", ", members)));
393                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_MEMBERS_ADDED_DESC";
394                }
395                break;
396            case ObservationConstants.EVENT_WALLCONTENT_ADDED :
397                i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_WALLCONTENT_ADDED_DESC";
398                break;
399
400            /**
401             * WIKI
402             */
403            case ObservationConstants.EVENT_EDITIONFO_CREATED :
404                if (amount == 1)
405                {
406                    parameters.put("page", new I18nizableText(getTitles(event, "pages", "pageTitle")));
407                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_CREATED_DESC";
408                }
409                else
410                {
411                    parameters.put("pages", new I18nizableText(getTitles(event, "pages", "pageTitle")));
412                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGES_CREATED_DESC";
413                }
414                break;
415            case ObservationConstants.EVENT_EDITIONFO_UPDATED :
416                if (amount == 1)
417                {
418                    parameters.put("page", new I18nizableText(getTitles(event, "pages", "pageTitle")));
419                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_UPDATED_DESC";
420                }
421                else
422                {
423                    parameters.put("pages", new I18nizableText(getTitles(event, "pages", "pageTitle")));
424                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGES_UPDATED_DESC";
425                }
426                break;
427            case ObservationConstants.EVENT_EDITIONFO_RENAMED :
428                parameters.put("oldTitle", new I18nizableText((String) event.get("pageOldTitle")));
429                parameters.put("title", new I18nizableText((String) event.get("pageTitle")));
430                i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_RENAMED_DESC";
431                break;
432            case ObservationConstants.EVENT_EDITIONFO_DELETED :
433                if (amount == 1)
434                {
435                    parameters.put("page", new I18nizableText(getTitles(event, "pages", "pageTitle")));
436                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_DELETED_DESC";
437                }
438                else
439                {
440                    parameters.put("pages", new I18nizableText(getTitles(event, "pages", "pageTitle")));
441                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGES_DELETED_DESC";
442                }
443                break;
444
445            /**
446             * TASK
447             */
448            case org.ametys.plugins.explorer.ObservationConstants.EVENT_TASK_CREATED :
449                if (amount == 1)
450                {
451                    parameters.put("task", new I18nizableText(getTitles(event, "tasks", "taskTitle")));
452                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_ADDED_DESC";
453                }
454                else
455                {
456                    parameters.put("tasks", new I18nizableText(getTitles(event, "tasks", "taskTitle")));
457                    i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASKS_ADDED_DESC";
458                }
459                break;
460            case org.ametys.plugins.explorer.ObservationConstants.EVENT_TASK_ASSIGNED :
461                parameters.put("task", new I18nizableText((String) event.get("taskTitle")));
462                parameters.put("assignee", new I18nizableText((String) event.get("assignees")));
463                i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_ASSIGNED_DESC";
464                break;
465            case org.ametys.plugins.explorer.ObservationConstants.EVENT_TASK_STATUS_CHANGED :
466                parameters.put("task", new I18nizableText((String) event.get("taskTitle")));
467                parameters.put("status", new I18nizableText((String) event.get("status")));
468                i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_STATUS_CHANGED_DESC";
469                break;
470            default:
471                break;
472        }
473        
474        if (i18nKey != null)
475        {
476            I18nizableText descriptionI18n = new I18nizableText("plugin.workspaces", i18nKey, parameters);
477            description = _i18nUtils.translate(descriptionI18n, lang);
478        }
479        
480        return description;
481    }
482    
483    /**
484     * Aggregates a list of elements from the event.
485     * event = {
486     *      mapKey : [
487     *          {
488     *              titleKey : "Title 1",
489     *              …
490     *          },
491     *          {
492     *              titleKey : "Title 2",
493     *              …
494     *          },
495     *          {
496     *              titleKey : "Title 3",
497     *              …
498     *          }
499     *      ],
500     *      …
501     *  }
502     * @param event the event to use
503     * @param mapKey the key of the list to use
504     * @param titleKey title to use from the map
505     * @return a list, separated with commas, between each titles
506     */
507    protected String getTitles(Map<String, Object> event, String mapKey, String titleKey)
508    {
509        @SuppressWarnings("unchecked")
510        List<Map<String, String>> items = (List<Map<String, String>>) event.get(mapKey);
511        
512        String result = null;
513        
514        for (Map<String, String> item : items)
515        {
516            if (result == null)
517            {
518                result = item.get(titleKey);
519            }
520            else
521            {
522                result += ", " + item.get(titleKey);
523            }
524        }
525        
526        return result;
527    }
528
529}