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("id", fullProjectMap.get("id")); 078 neededInfos.put("category", fullProjectMap.get("category")); 079 080 result.put(name, neededInfos); 081 } 082 083 return result; 084 } 085 086 /** 087 * Transform a {@link Project} into a json map 088 * @param project the project to parse 089 * @return a json map 090 */ 091 public Map<String, Object> projectToMap(Project project) 092 { 093 return _projectsCatalogueManager.detailedProject2json(project); 094 } 095 /** 096 * Add infos to the event, so it can be displayed by the app 097 * @param event the event to parse 098 * @param project the project, as a json map (see {@link FeedHelper#projectToMap(Project)}) 099 * @param lang language to use to translate the short description 100 * @return a map to return in json 101 */ 102 public Map<String, Object> getEventInfos(Map<String, Object> event, Map<String, Object> project, String lang) 103 { 104 Map<String, Object> result = new HashMap<>(); 105 106 result.putAll(event); 107 108 result.put("project", project); 109 110 @SuppressWarnings("unchecked") 111 Map<String, String> author = new HashMap<>((Map<String, String>) event.get("author")); 112 author.put("avatarUrl", "/_plugins/workspaces/user/" + author.get("populationId") + "/" + author.get("login") + "/image_" + PostConstants.IMAGE_SIZE); 113 result.put("author", author); 114 115 result.put("short-description", getEventDescription(event, lang)); 116 117 result.put("content_id", getEventObjectId(event)); 118 result.put("content_url", getEventUrl(event)); 119 120 return result; 121 } 122 123 /** 124 * Generate a description for this event 125 * @param event the event to describe 126 * @return a String of the description 127 */ 128 @SuppressWarnings("unchecked") 129 protected String getEventObjectId(Map<String, Object> event) 130 { 131 String id = null; 132 String eventType = (String) event.get("type"); 133 134 switch (eventType) 135 { 136 /* 137 * RESOURCES 138 */ 139 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED : 140 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED : 141 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED : 142 if (event.containsKey("file")) 143 { 144 id = (String) ((Map<String, Object>) event.get("file")).get("id"); 145 } 146 break; 147 148 /* 149 * CALENDAR 150 */ 151 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED : 152 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED : 153 id = (String) event.get("eventId"); 154 break; 155 156 /* 157 * THREAD 158 */ 159 case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_CREATED : 160 case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_POST_CREATED : 161 id = (String) event.get("threadId"); 162 break; 163 164 /* 165 * MEMBER 166 */ 167 case ObservationConstants.EVENT_MEMBER_ADDED : 168 // no id available 169 break; 170 case ObservationConstants.EVENT_WALLCONTENT_ADDED : 171 id = (String) event.get("contentId"); 172 break; 173 174 /** 175 * WIKI 176 */ 177 case ObservationConstants.EVENT_MINISITE_PAGE_CREATED : 178 case ObservationConstants.EVENT_MINISITE_PAGE_UPDATED : 179 case ObservationConstants.EVENT_MINISITE_PAGE_RENAMED : 180 case ObservationConstants.EVENT_MINISITE_PAGE_DELETED : 181 id = (String) event.get("pageId"); 182 break; 183 184 /** 185 * TASK 186 */ 187 case ObservationConstants.EVENT_TASK_CREATED : 188 case ObservationConstants.EVENT_TASK_ASSIGNED : 189 case ObservationConstants.EVENT_TASK_CLOSED_STATUS_CHANGED : 190 id = (String) event.get("taskId"); 191 break; 192 default: 193 break; 194 } 195 196 return id; 197 } 198 199 200 /** 201 * Generate a description for this event 202 * @param event the event to describe 203 * @return a String of the description 204 */ 205 protected String getEventUrl(Map<String, Object> event) 206 { 207 String url = null; 208 String eventType = (String) event.get("type"); 209 210 switch (eventType) 211 { 212 /* 213 * RESOURCES 214 */ 215 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED : 216 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED : 217 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED : 218 url = (String) event.get("parentFolderUrl"); 219 break; 220 221 /* 222 * CALENDAR 223 */ 224 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED : 225 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED : 226 url = (String) event.get("eventUrl"); 227 break; 228 229 /* 230 * THREAD 231 */ 232 case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_CREATED : 233 case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_POST_CREATED : 234 url = (String) event.get("threadUrl"); 235 break; 236 237 /* 238 * MEMBER 239 */ 240 case ObservationConstants.EVENT_MEMBER_ADDED : 241 // no url available 242 break; 243 case ObservationConstants.EVENT_WALLCONTENT_ADDED : 244 // no url available 245 break; 246 247 /** 248 * WIKI 249 */ 250 case ObservationConstants.EVENT_MINISITE_PAGE_CREATED : 251 case ObservationConstants.EVENT_MINISITE_PAGE_UPDATED : 252 case ObservationConstants.EVENT_MINISITE_PAGE_RENAMED : 253 case ObservationConstants.EVENT_MINISITE_PAGE_DELETED : 254 url = (String) event.get("pageUrl"); 255 break; 256 257 /** 258 * TASK 259 */ 260 case ObservationConstants.EVENT_TASK_CREATED : 261 case ObservationConstants.EVENT_TASK_ASSIGNED : 262 case ObservationConstants.EVENT_TASK_CLOSED_STATUS_CHANGED : 263 url = (String) event.get("taskUrl"); 264 break; 265 default: 266 break; 267 } 268 if (StringUtils.isBlank(url)) 269 { 270 url = (String) event.get("projectUrl"); 271 } 272 return url; 273 } 274 275 /** 276 * Generate a description for this event 277 * @param event the event to describe 278 * @param lang the language to use 279 * @return a String of the description 280 */ 281 @SuppressWarnings("unchecked") 282 protected String getEventDescription(Map<String, Object> event, String lang) 283 { 284 String description = null; 285 286 String eventType = (String) event.get("type"); 287 288 Integer amount = (Integer) event.get("amount"); 289 String i18nKey = null; 290 Map<String, I18nizableTextParameter> parameters = new HashMap<>(); 291 parameters.put("author", new I18nizableText(((Map<String, String>) event.get("author")).get("fullname"))); 292 parameters.put("project", new I18nizableText((String) event.get("projectTitle"))); 293 parameters.put("nb", new I18nizableText(amount.toString())); 294 295 switch (eventType) 296 { 297 298 /* 299 * RESOURCES 300 */ 301 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED : 302 parameters.put("folder", new I18nizableText((String) event.get("parentFolder"))); 303 if (amount == 1) 304 { 305 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_ADDED_DESC"; 306 } 307 else 308 { 309 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_ADDED_MULTI_DESC"; 310 } 311 break; 312 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED : 313 parameters.put("folder", new I18nizableText((String) event.get("parentFolder"))); 314 if (amount == 1) 315 { 316 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_UPDATED_DESC"; 317 } 318 else 319 { 320 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_UPDATED_MULTI_DESC"; 321 } 322 break; 323 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED : 324 parameters.put("folder", new I18nizableText((String) event.get("parentFolder"))); 325 if (amount == 1) 326 { 327 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_RENAMED_DESC"; 328 } 329 else 330 { 331 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_RENAMED_MULTI_DESC"; 332 } 333 break; 334 335 /* 336 * CALENDAR 337 */ 338 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED : 339 parameters.put("calendar", new I18nizableText((String) event.get("calendarTitle"))); 340 if (amount == 1) 341 { 342 parameters.put("event", new I18nizableText(getTitles(event, "events", "eventTitle"))); 343 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_ADDED_DESC"; 344 } 345 else 346 { 347 parameters.put("events", new I18nizableText(getTitles(event, "events", "eventTitle"))); 348 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_ADDED_MULTI_DESC"; 349 } 350 break; 351 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED : 352 parameters.put("calendar", new I18nizableText((String) event.get("calendarTitle"))); 353 if (amount == 1) 354 { 355 parameters.put("event", new I18nizableText(getTitles(event, "events", "eventTitle"))); 356 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_UPDATED_DESC"; 357 } 358 else 359 { 360 parameters.put("events", new I18nizableText(getTitles(event, "events", "eventTitle"))); 361 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_UPDATED_MULTI_DESC"; 362 } 363 break; 364 365 /* 366 * THREAD 367 */ 368 case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_CREATED : 369 if (amount == 1) 370 { 371 parameters.put("thread", new I18nizableText(getTitles(event, "threads", "threadTitle"))); 372 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_CREATED_DESC"; 373 } 374 else 375 { 376 parameters.put("threads", new I18nizableText(getTitles(event, "threads", "threadTitle"))); 377 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_CREATED_MULTI_DESC"; 378 } 379 break; 380 case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_POST_CREATED : 381 parameters.put("thread", new I18nizableText(getTitles(event, "threads", "threadTitle"))); 382 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_POST_CREATED_DESC"; 383 break; 384 385 /* 386 * MEMBER 387 */ 388 case ObservationConstants.EVENT_MEMBER_ADDED : 389 if (amount == 1) 390 { 391 parameters.put("member", new I18nizableText((String) event.get("member"))); 392 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_MEMBER_ADDED_DESC"; 393 } 394 else 395 { 396 Collection<Map<String, Object>> members = (Collection<Map<String, Object>>) event.get("members"); 397 List<String> names = members.stream().map(member -> (String) member.get("name")).collect(Collectors.toList()); 398 parameters.put("members", new I18nizableText(String.join(", ", names))); 399 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_MEMBERS_ADDED_DESC"; 400 } 401 break; 402 case ObservationConstants.EVENT_WALLCONTENT_ADDED : 403 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_WALLCONTENT_ADDED_DESC"; 404 break; 405 406 /** 407 * WIKI 408 */ 409 case ObservationConstants.EVENT_MINISITE_PAGE_CREATED : 410 if (amount == 1) 411 { 412 parameters.put("page", new I18nizableText(getTitles(event, "pages", "pageTitle"))); 413 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_CREATED_DESC"; 414 } 415 else 416 { 417 parameters.put("pages", new I18nizableText(getTitles(event, "pages", "pageTitle"))); 418 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGES_CREATED_DESC"; 419 } 420 break; 421 case ObservationConstants.EVENT_MINISITE_PAGE_UPDATED : 422 if (amount == 1) 423 { 424 parameters.put("page", new I18nizableText(getTitles(event, "pages", "pageTitle"))); 425 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_UPDATED_DESC"; 426 } 427 else 428 { 429 parameters.put("pages", new I18nizableText(getTitles(event, "pages", "pageTitle"))); 430 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGES_UPDATED_DESC"; 431 } 432 break; 433 case ObservationConstants.EVENT_MINISITE_PAGE_RENAMED : 434 parameters.put("oldTitle", new I18nizableText((String) event.get("pageOldTitle"))); 435 parameters.put("title", new I18nizableText((String) event.get("pageTitle"))); 436 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_RENAMED_DESC"; 437 break; 438 case ObservationConstants.EVENT_MINISITE_PAGE_DELETED : 439 if (amount == 1) 440 { 441 parameters.put("page", new I18nizableText(getTitles(event, "pages", "pageTitle"))); 442 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGE_DELETED_DESC"; 443 } 444 else 445 { 446 parameters.put("pages", new I18nizableText(getTitles(event, "pages", "pageTitle"))); 447 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_PAGES_DELETED_DESC"; 448 } 449 break; 450 451 /** 452 * TASK 453 */ 454 case ObservationConstants.EVENT_TASK_CREATED : 455 if (amount == 1) 456 { 457 parameters.put("task", new I18nizableText(getTitles(event, "tasks", "taskTitle"))); 458 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_ADDED_DESC"; 459 } 460 else 461 { 462 parameters.put("tasks", new I18nizableText(getTitles(event, "tasks", "taskTitle"))); 463 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASKS_ADDED_DESC"; 464 } 465 break; 466 case ObservationConstants.EVENT_TASK_ASSIGNED : 467 parameters.put("task", new I18nizableText((String) event.get("taskTitle"))); 468 parameters.put("assignee", new I18nizableText((String) event.get("assignees"))); 469 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_ASSIGNED_DESC"; 470 break; 471 case ObservationConstants.EVENT_TASK_CLOSED_STATUS_CHANGED : 472 parameters.put("task", new I18nizableText((String) event.get("taskTitle"))); 473 474 boolean isClosed = "true".equals(event.get("isClosed")); 475 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"; 476 break; 477 default: 478 break; 479 } 480 481 if (i18nKey != null) 482 { 483 I18nizableText descriptionI18n = new I18nizableText("plugin.workspaces", i18nKey, parameters); 484 description = _i18nUtils.translate(descriptionI18n, lang); 485 } 486 487 return description; 488 } 489 490 /** 491 * Aggregates a list of elements from the event. 492 * event = { 493 * mapKey : [ 494 * { 495 * titleKey : "Title 1", 496 * … 497 * }, 498 * { 499 * titleKey : "Title 2", 500 * … 501 * }, 502 * { 503 * titleKey : "Title 3", 504 * … 505 * } 506 * ], 507 * … 508 * } 509 * @param event the event to use 510 * @param mapKey the key of the list to use 511 * @param titleKey title to use from the map 512 * @return a list, separated with commas, between each titles 513 */ 514 protected String getTitles(Map<String, Object> event, String mapKey, String titleKey) 515 { 516 @SuppressWarnings("unchecked") 517 List<Map<String, String>> items = (List<Map<String, String>>) event.get(mapKey); 518 519 String result = null; 520 521 for (Map<String, String> item : items) 522 { 523 if (result == null) 524 { 525 result = item.get(titleKey); 526 } 527 else 528 { 529 result += ", " + item.get(titleKey); 530 } 531 } 532 533 return result; 534 } 535 536}