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.Collection; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.stream.Collectors; 023 024import org.apache.avalon.framework.component.Component; 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.avalon.framework.service.Serviceable; 028import org.apache.commons.lang3.StringUtils; 029 030import org.ametys.core.util.I18nUtils; 031import org.ametys.plugins.workspaces.ObservationConstants; 032import org.ametys.plugins.workspaces.project.ProjectsCatalogueManager; 033import org.ametys.plugins.workspaces.project.objects.Project; 034import org.ametys.runtime.i18n.I18nizableText; 035import org.ametys.runtime.i18n.I18nizableTextParameter; 036import org.ametys.runtime.plugin.component.AbstractLogEnabled; 037 038/** 039 * Helper to handle project feeds 040 */ 041public class FeedHelper extends AbstractLogEnabled implements Serviceable, Component 042{ 043 /** Avalon Role */ 044 public static final String ROLE = FeedHelper.class.getName(); 045 046 /** I18N Utils */ 047 protected I18nUtils _i18nUtils; 048 049 /** The project catalogue manager component */ 050 protected ProjectsCatalogueManager _projectsCatalogueManager; 051 052 public void service(ServiceManager manager) throws ServiceException 053 { 054 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 055 _projectsCatalogueManager = (ProjectsCatalogueManager) manager.lookup(ProjectsCatalogueManager.ROLE); 056 } 057 058 059 /** 060 * Generate a map of project names with the basic projects informations to return 061 * @return a map of basic information about projects 062 */ 063 public Map<String, Map<String, Object>> getProjects() 064 { 065 Map<String, Map<String, Object>> result = new HashMap<>(); 066 List<Map<String, Object>> userProjects = _projectsCatalogueManager.getUserProjects(); 067 for (Map<String, Object> fullProjectMap : userProjects) 068 { 069 String name = (String) fullProjectMap.get("name"); 070 Map<String, Object> neededInfos = new HashMap<>(); 071 072 neededInfos.put("name", name); 073 neededInfos.put("description", fullProjectMap.get("description")); 074 neededInfos.put("title", fullProjectMap.get("title")); 075 neededInfos.put("url", fullProjectMap.get("url")); 076 neededInfos.put("illustration", fullProjectMap.get("illustration")); 077 neededInfos.put("language", fullProjectMap.get("language")); 078 neededInfos.put("id", fullProjectMap.get("id")); 079 neededInfos.put("category", fullProjectMap.get("category")); 080 081 result.put(name, neededInfos); 082 } 083 084 return result; 085 } 086 087 /** 088 * Transform a {@link Project} into a json map 089 * @param project the project to parse 090 * @return a json map 091 */ 092 public Map<String, Object> projectToMap(Project project) 093 { 094 return _projectsCatalogueManager.detailedProject2json(project); 095 } 096 /** 097 * Add infos to the activity, so it can be displayed by the app 098 * @param activity the json representing the activity to parse 099 * @param project the project, as a json map (see {@link FeedHelper#projectToMap(Project)}) 100 * @param lang language to use to translate the short description 101 * @return a map to return in json 102 */ 103 public Map<String, Object> getActivityInfos(Map<String, Object> activity, Map<String, Object> project, String lang) 104 { 105 Map<String, Object> result = new HashMap<>(); 106 107 result.putAll(activity); 108 109 result.put("project", project); 110 111 @SuppressWarnings("unchecked") 112 Map<String, String> activityAuthor = (Map<String, String>) activity.get("author"); 113 114 Map<String, String> author = new HashMap<>(); 115 author.put("fullname", activityAuthor.get("fullname")); 116 result.put("author", author); 117 118 result.put("short-description", getActivityDescription(activity, lang)); 119 120 result.put("content_id", getActivityObjectId(activity)); 121 result.put("content_url", getActivityUrl(activity)); 122 123 return result; 124 } 125 126 /** 127 * Generate a description for this activity 128 * @param activity the activity to describe 129 * @return a String of the description 130 */ 131 @SuppressWarnings("unchecked") 132 protected String getActivityObjectId(Map<String, Object> activity) 133 { 134 String id = null; 135 String eventType = (String) activity.get("type"); 136 137 switch (eventType) 138 { 139 /* 140 * RESOURCES 141 */ 142 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED : 143 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED : 144 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED : 145 if (activity.containsKey("file")) 146 { 147 id = (String) ((Map<String, Object>) activity.get("file")).get("id"); 148 } 149 break; 150 151 /* 152 * CALENDAR 153 */ 154 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED : 155 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED : 156 id = (String) activity.get("eventId"); 157 break; 158 159 /* 160 * THREAD 161 */ 162 case ObservationConstants.EVENT_THREAD_CREATED : 163 case ObservationConstants.EVENT_THREAD_COMMENTED : 164 id = (String) activity.get("threadId"); 165 break; 166 167 /* 168 * MEMBER 169 */ 170 case ObservationConstants.EVENT_MEMBER_ADDED : 171 // no id available 172 break; 173 case ObservationConstants.EVENT_WALLCONTENT_ADDED : 174 id = (String) activity.get("contentId"); 175 break; 176 177 /** 178 * WIKI 179 */ 180 case ObservationConstants.EVENT_MINISITE_PAGE_CREATED : 181 case ObservationConstants.EVENT_MINISITE_PAGE_UPDATED : 182 case ObservationConstants.EVENT_MINISITE_PAGE_RENAMED : 183 case ObservationConstants.EVENT_MINISITE_PAGE_DELETED : 184 id = (String) activity.get("pageId"); 185 break; 186 187 /** 188 * TASK 189 */ 190 case ObservationConstants.EVENT_TASK_CREATED : 191 case ObservationConstants.EVENT_TASK_ASSIGNED : 192 case ObservationConstants.EVENT_TASK_CLOSED_STATUS_CHANGED : 193 id = (String) activity.get("taskId"); 194 break; 195 default: 196 break; 197 } 198 199 return id; 200 } 201 202 203 /** 204 * Generate a description for this activity 205 * @param activity the activity to describe 206 * @return a String of the description 207 */ 208 protected String getActivityUrl(Map<String, Object> activity) 209 { 210 String url = null; 211 String eventType = (String) activity.get("type"); 212 213 switch (eventType) 214 { 215 /* 216 * RESOURCES 217 */ 218 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED : 219 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED : 220 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED : 221 url = (String) activity.get("parentFolderUrl"); 222 break; 223 224 /* 225 * CALENDAR 226 */ 227 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED : 228 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED : 229 url = (String) activity.get("eventUrl"); 230 break; 231 232 /* 233 * THREAD 234 */ 235 case ObservationConstants.EVENT_THREAD_CREATED : 236 case ObservationConstants.EVENT_THREAD_COMMENTED : 237 url = (String) activity.get("threadUrl"); 238 break; 239 240 /* 241 * MEMBER 242 */ 243 case ObservationConstants.EVENT_MEMBER_ADDED : 244 // no url available 245 break; 246 case ObservationConstants.EVENT_WALLCONTENT_ADDED : 247 // no url available 248 break; 249 250 /** 251 * WIKI 252 */ 253 case ObservationConstants.EVENT_MINISITE_PAGE_CREATED : 254 case ObservationConstants.EVENT_MINISITE_PAGE_UPDATED : 255 case ObservationConstants.EVENT_MINISITE_PAGE_RENAMED : 256 case ObservationConstants.EVENT_MINISITE_PAGE_DELETED : 257 url = (String) activity.get("pageUrl"); 258 break; 259 260 /** 261 * TASK 262 */ 263 case ObservationConstants.EVENT_TASK_CREATED : 264 case ObservationConstants.EVENT_TASK_ASSIGNED : 265 case ObservationConstants.EVENT_TASK_CLOSED_STATUS_CHANGED : 266 url = (String) activity.get("taskUrl"); 267 break; 268 default: 269 break; 270 } 271 if (StringUtils.isBlank(url)) 272 { 273 url = (String) activity.get("projectUrl"); 274 } 275 return url; 276 } 277 278 /** 279 * Generate a description for this activity 280 * @param activity the activity to describe 281 * @param lang the language to use 282 * @return a String of the description 283 */ 284 @SuppressWarnings("unchecked") 285 protected String getActivityDescription(Map<String, Object> activity, String lang) 286 { 287 String description = null; 288 289 String eventType = (String) activity.get("type"); 290 291 Integer amount = (Integer) activity.get("amount"); 292 if (amount == null) 293 { 294 amount = 1; 295 } 296 297 String i18nKey = null; 298 Map<String, I18nizableTextParameter> parameters = new HashMap<>(); 299 parameters.put("author", new I18nizableText(((Map<String, String>) activity.get("author")).get("fullname"))); 300 parameters.put("project", new I18nizableText((String) activity.get("projectTitle"))); 301 parameters.put("nb", new I18nizableText(amount.toString())); 302 303 switch (eventType) 304 { 305 306 /* 307 * RESOURCES 308 */ 309 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED : 310 parameters.put("folder", new I18nizableText((String) activity.get("parentFolder"))); 311 if (amount == 1) 312 { 313 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_ADDED_DESC"; 314 } 315 else 316 { 317 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_ADDED_MULTI_DESC"; 318 } 319 break; 320 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED : 321 parameters.put("folder", new I18nizableText((String) activity.get("parentFolder"))); 322 if (amount == 1) 323 { 324 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_UPDATED_DESC"; 325 } 326 else 327 { 328 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_UPDATED_MULTI_DESC"; 329 } 330 break; 331 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED : 332 parameters.put("folder", new I18nizableText((String) activity.get("parentFolder"))); 333 if (amount == 1) 334 { 335 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_RENAMED_DESC"; 336 } 337 else 338 { 339 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_RENAMED_MULTI_DESC"; 340 } 341 break; 342 343 /* 344 * CALENDAR 345 */ 346 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED : 347 parameters.put("calendar", new I18nizableText((String) activity.get("calendarTitle"))); 348 if (amount == 1) 349 { 350 parameters.put("event", new I18nizableText(getTitles(activity, "events", "eventTitle"))); 351 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_ADDED_DESC"; 352 } 353 else 354 { 355 parameters.put("events", new I18nizableText(getTitles(activity, "events", "eventTitle"))); 356 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_ADDED_MULTI_DESC"; 357 } 358 break; 359 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED : 360 parameters.put("calendar", new I18nizableText((String) activity.get("calendarTitle"))); 361 if (amount == 1) 362 { 363 parameters.put("event", new I18nizableText(getTitles(activity, "events", "eventTitle"))); 364 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_UPDATED_DESC"; 365 } 366 else 367 { 368 parameters.put("events", new I18nizableText(getTitles(activity, "events", "eventTitle"))); 369 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_UPDATED_MULTI_DESC"; 370 } 371 break; 372 373 /* 374 * THREAD 375 */ 376 case ObservationConstants.EVENT_THREAD_CREATED : 377 if (amount == 1) 378 { 379 parameters.put("thread", new I18nizableText(getTitles(activity, "threads", "threadTitle"))); 380 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_CREATED_DESC"; 381 } 382 else 383 { 384 parameters.put("threads", new I18nizableText(getTitles(activity, "threads", "threadTitle"))); 385 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_CREATED_MULTI_DESC"; 386 } 387 break; 388 case ObservationConstants.EVENT_THREAD_COMMENTED : 389 parameters.put("thread", new I18nizableText(getTitles(activity, "threads", "threadTitle"))); 390 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_POST_CREATED_DESC"; 391 break; 392 393 /* 394 * MEMBER 395 */ 396 case ObservationConstants.EVENT_MEMBER_ADDED : 397 if (amount == 1) 398 { 399 parameters.put("member", new I18nizableText((String) activity.get("member"))); 400 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_MEMBER_ADDED_DESC"; 401 } 402 else 403 { 404 Collection<Map<String, Object>> members = (Collection<Map<String, Object>>) activity.get("members"); 405 List<String> names = members.stream().map(member -> (String) member.get("name")).collect(Collectors.toList()); 406 parameters.put("members", new I18nizableText(String.join(", ", names))); 407 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_MEMBERS_ADDED_DESC"; 408 } 409 break; 410 411 /** 412 * WIKI 413 */ 414 case ObservationConstants.EVENT_MINISITE_PAGE_CREATED : 415 if (amount == 1) 416 { 417 parameters.put("page", new I18nizableText(getTitles(activity, "pages", "pageTitle"))); 418 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_CREATED_DESC"; 419 } 420 else 421 { 422 parameters.put("pages", new I18nizableText(getTitles(activity, "pages", "pageTitle"))); 423 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGES_CREATED_DESC"; 424 } 425 break; 426 case ObservationConstants.EVENT_MINISITE_PAGE_UPDATED : 427 if (amount == 1) 428 { 429 parameters.put("page", new I18nizableText(getTitles(activity, "pages", "pageTitle"))); 430 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_UPDATED_DESC"; 431 } 432 else 433 { 434 parameters.put("pages", new I18nizableText(getTitles(activity, "pages", "pageTitle"))); 435 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGES_UPDATED_DESC"; 436 } 437 break; 438 case ObservationConstants.EVENT_MINISITE_PAGE_RENAMED : 439 parameters.put("oldTitle", new I18nizableText((String) activity.get("pageOldTitle"))); 440 parameters.put("title", new I18nizableText((String) activity.get("pageTitle"))); 441 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_RENAMED_DESC"; 442 break; 443 case ObservationConstants.EVENT_MINISITE_PAGE_DELETED : 444 if (amount == 1) 445 { 446 parameters.put("page", new I18nizableText(getTitles(activity, "pages", "pageTitle"))); 447 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_DELETED_DESC"; 448 } 449 else 450 { 451 parameters.put("pages", new I18nizableText(getTitles(activity, "pages", "pageTitle"))); 452 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGES_DELETED_DESC"; 453 } 454 break; 455 456 457 /** 458 * NEWS 459 */ 460 case ObservationConstants.EVENT_PROJECT_NEWS_PUBLISHED: 461 parameters.put("contentTitle", new I18nizableText((String) activity.get("contentTitle"))); 462 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PROJECT_NEWS_ADDED_DESC"; 463 break; 464 465 /** 466 * WALLCONTENT 467 */ 468 case ObservationConstants.EVENT_WALLCONTENT_ADDED : 469 parameters.put("contentSummary", new I18nizableText((String) activity.get("contentSummary"))); 470 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_WALLCONTENT_ADDED_WITH_TITLE_DESC"; 471 break; 472 473 /** 474 * NEWS AND WALLCONTENTS COMMENTS 475 */ 476 case org.ametys.cms.ObservationConstants.EVENT_CONTENT_COMMENT_VALIDATED : 477 parameters.put("contentTitle", new I18nizableText((String) activity.get("contentTitle"))); 478 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CONTENT_COMMENT_VALIDATED_DESC"; 479 break; 480 481 /** 482 * TASK 483 */ 484 case ObservationConstants.EVENT_TASK_CREATED : 485 if (amount == 1) 486 { 487 parameters.put("task", new I18nizableText(getTitles(activity, "tasks", "taskTitle"))); 488 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_ADDED_DESC"; 489 } 490 else 491 { 492 parameters.put("tasks", new I18nizableText(getTitles(activity, "tasks", "taskTitle"))); 493 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASKS_ADDED_DESC"; 494 } 495 break; 496 case ObservationConstants.EVENT_TASK_DELETING : 497 if (amount == 1) 498 { 499 parameters.put("task", new I18nizableText(getTitles(activity, "tasks", "taskTitle"))); 500 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_DELETED_DESC"; 501 } 502 else 503 { 504 parameters.put("tasks", new I18nizableText(getTitles(activity, "tasks", "taskTitle"))); 505 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASKS_DELETED_DESC"; 506 } 507 break; 508 case ObservationConstants.EVENT_TASK_ASSIGNED : 509 parameters.put("task", new I18nizableText((String) activity.get("taskTitle"))); 510 parameters.put("assignee", new I18nizableText((String) activity.get("assignees"))); 511 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_ASSIGNED_DESC"; 512 break; 513 case ObservationConstants.EVENT_TASK_CLOSED_STATUS_CHANGED : 514 parameters.put("task", new I18nizableText((String) activity.get("taskTitle"))); 515 516 boolean isClosed = "true".equals(activity.get("isClosed")); 517 i18nKey = isClosed ? "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_CLOSED_STATUS_CLOSE_DESC" : "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_CLOSED_STATUS_OPEN_DESC"; 518 break; 519 default: 520 break; 521 } 522 523 if (i18nKey != null) 524 { 525 I18nizableText descriptionI18n = new I18nizableText("plugin.workspaces", i18nKey, parameters); 526 description = _i18nUtils.translate(descriptionI18n, lang); 527 } 528 529 return description; 530 } 531 532 /** 533 * Aggregates a list of elements from the activity. 534 * activity = { 535 * mapKey : [ 536 * { 537 * titleKey : "Title 1", 538 * … 539 * }, 540 * { 541 * titleKey : "Title 2", 542 * … 543 * }, 544 * { 545 * titleKey : "Title 3", 546 * … 547 * } 548 * ], 549 * … 550 * } 551 * @param activity the activity to use 552 * @param mapKey the key of the list to use 553 * @param titleKey title to use from the map 554 * @return a list, separated with commas, between each titles 555 */ 556 protected String getTitles(Map<String, Object> activity, String mapKey, String titleKey) 557 { 558 @SuppressWarnings("unchecked") 559 List<Map<String, String>> items = (List<Map<String, String>>) activity.get(mapKey); 560 561 562 if (items == null) 563 { 564 return (String) activity.get(titleKey); 565 } 566 else 567 { 568 String result = null; 569 570 for (Map<String, String> item : items) 571 { 572 if (result == null) 573 { 574 result = item.get(titleKey); 575 } 576 else 577 { 578 result += ", " + item.get(titleKey); 579 } 580 } 581 582 return result; 583 } 584 } 585 586}