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 activity, so it can be displayed by the app 097 * @param activity the json representing the activity 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> getActivityInfos(Map<String, Object> activity, Map<String, Object> project, String lang) 103 { 104 Map<String, Object> result = new HashMap<>(); 105 106 result.putAll(activity); 107 108 result.put("project", project); 109 110 @SuppressWarnings("unchecked") 111 Map<String, String> author = new HashMap<>((Map<String, String>) activity.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", getActivityDescription(activity, lang)); 116 117 result.put("content_id", getActivityObjectId(activity)); 118 result.put("content_url", getActivityUrl(activity)); 119 120 return result; 121 } 122 123 /** 124 * Generate a description for this activity 125 * @param activity the activity to describe 126 * @return a String of the description 127 */ 128 @SuppressWarnings("unchecked") 129 protected String getActivityObjectId(Map<String, Object> activity) 130 { 131 String id = null; 132 String eventType = (String) activity.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 (activity.containsKey("file")) 143 { 144 id = (String) ((Map<String, Object>) activity.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) activity.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) activity.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) activity.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) activity.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) activity.get("taskId"); 191 break; 192 default: 193 break; 194 } 195 196 return id; 197 } 198 199 200 /** 201 * Generate a description for this activity 202 * @param activity the activity to describe 203 * @return a String of the description 204 */ 205 protected String getActivityUrl(Map<String, Object> activity) 206 { 207 String url = null; 208 String eventType = (String) activity.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) activity.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) activity.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) activity.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) activity.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) activity.get("taskUrl"); 264 break; 265 default: 266 break; 267 } 268 if (StringUtils.isBlank(url)) 269 { 270 url = (String) activity.get("projectUrl"); 271 } 272 return url; 273 } 274 275 /** 276 * Generate a description for this activity 277 * @param activity the activity to describe 278 * @param lang the language to use 279 * @return a String of the description 280 */ 281 @SuppressWarnings("unchecked") 282 protected String getActivityDescription(Map<String, Object> activity, String lang) 283 { 284 String description = null; 285 286 String eventType = (String) activity.get("type"); 287 288 Integer amount = (Integer) activity.get("amount"); 289 if (amount == null) 290 { 291 amount = 1; 292 } 293 294 String i18nKey = null; 295 Map<String, I18nizableTextParameter> parameters = new HashMap<>(); 296 parameters.put("author", new I18nizableText(((Map<String, String>) activity.get("author")).get("fullname"))); 297 parameters.put("project", new I18nizableText((String) activity.get("projectTitle"))); 298 parameters.put("nb", new I18nizableText(amount.toString())); 299 300 switch (eventType) 301 { 302 303 /* 304 * RESOURCES 305 */ 306 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_CREATED : 307 parameters.put("folder", new I18nizableText((String) activity.get("parentFolder"))); 308 if (amount == 1) 309 { 310 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_ADDED_DESC"; 311 } 312 else 313 { 314 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_ADDED_MULTI_DESC"; 315 } 316 break; 317 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_UPDATED : 318 parameters.put("folder", new I18nizableText((String) activity.get("parentFolder"))); 319 if (amount == 1) 320 { 321 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_UPDATED_DESC"; 322 } 323 else 324 { 325 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_UPDATED_MULTI_DESC"; 326 } 327 break; 328 case org.ametys.plugins.explorer.ObservationConstants.EVENT_RESOURCE_RENAMED : 329 parameters.put("folder", new I18nizableText((String) activity.get("parentFolder"))); 330 if (amount == 1) 331 { 332 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_RENAMED_DESC"; 333 } 334 else 335 { 336 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_DOCUMENT_RENAMED_MULTI_DESC"; 337 } 338 break; 339 340 /* 341 * CALENDAR 342 */ 343 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_CREATED : 344 parameters.put("calendar", new I18nizableText((String) activity.get("calendarTitle"))); 345 if (amount == 1) 346 { 347 parameters.put("event", new I18nizableText(getTitles(activity, "events", "eventTitle"))); 348 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_ADDED_DESC"; 349 } 350 else 351 { 352 parameters.put("events", new I18nizableText(getTitles(activity, "events", "eventTitle"))); 353 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_ADDED_MULTI_DESC"; 354 } 355 break; 356 case org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_EVENT_UPDATED : 357 parameters.put("calendar", new I18nizableText((String) activity.get("calendarTitle"))); 358 if (amount == 1) 359 { 360 parameters.put("event", new I18nizableText(getTitles(activity, "events", "eventTitle"))); 361 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_UPDATED_DESC"; 362 } 363 else 364 { 365 parameters.put("events", new I18nizableText(getTitles(activity, "events", "eventTitle"))); 366 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_CALENDAR_UPDATED_MULTI_DESC"; 367 } 368 break; 369 370 /* 371 * THREAD 372 */ 373 case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_CREATED : 374 if (amount == 1) 375 { 376 parameters.put("thread", new I18nizableText(getTitles(activity, "threads", "threadTitle"))); 377 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_CREATED_DESC"; 378 } 379 else 380 { 381 parameters.put("threads", new I18nizableText(getTitles(activity, "threads", "threadTitle"))); 382 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_CREATED_MULTI_DESC"; 383 } 384 break; 385 case org.ametys.plugins.explorer.ObservationConstants.EVENT_THREAD_POST_CREATED : 386 parameters.put("thread", new I18nizableText(getTitles(activity, "threads", "threadTitle"))); 387 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_THREAD_POST_CREATED_DESC"; 388 break; 389 390 /* 391 * MEMBER 392 */ 393 case ObservationConstants.EVENT_MEMBER_ADDED : 394 if (amount == 1) 395 { 396 parameters.put("member", new I18nizableText((String) activity.get("member"))); 397 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_MEMBER_ADDED_DESC"; 398 } 399 else 400 { 401 Collection<Map<String, Object>> members = (Collection<Map<String, Object>>) activity.get("members"); 402 List<String> names = members.stream().map(member -> (String) member.get("name")).collect(Collectors.toList()); 403 parameters.put("members", new I18nizableText(String.join(", ", names))); 404 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_MEMBERS_ADDED_DESC"; 405 } 406 break; 407 case ObservationConstants.EVENT_WALLCONTENT_ADDED : 408 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_WALLCONTENT_ADDED_DESC"; 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 * TASK 458 */ 459 case ObservationConstants.EVENT_TASK_CREATED : 460 if (amount == 1) 461 { 462 parameters.put("task", new I18nizableText(getTitles(activity, "tasks", "taskTitle"))); 463 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_ADDED_DESC"; 464 } 465 else 466 { 467 parameters.put("tasks", new I18nizableText(getTitles(activity, "tasks", "taskTitle"))); 468 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASKS_ADDED_DESC"; 469 } 470 break; 471 case ObservationConstants.EVENT_TASK_ASSIGNED : 472 parameters.put("task", new I18nizableText((String) activity.get("taskTitle"))); 473 parameters.put("assignee", new I18nizableText((String) activity.get("assignees"))); 474 i18nKey = "PLUGINS_WORKSPACES_PROJECT_SERVICE_ACTIVITY_STREAM_EVENT_TASK_ASSIGNED_DESC"; 475 break; 476 case ObservationConstants.EVENT_TASK_CLOSED_STATUS_CHANGED : 477 parameters.put("task", new I18nizableText((String) activity.get("taskTitle"))); 478 479 boolean isClosed = "true".equals(activity.get("isClosed")); 480 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"; 481 break; 482 default: 483 break; 484 } 485 486 if (i18nKey != null) 487 { 488 I18nizableText descriptionI18n = new I18nizableText("plugin.workspaces", i18nKey, parameters); 489 description = _i18nUtils.translate(descriptionI18n, lang); 490 } 491 492 return description; 493 } 494 495 /** 496 * Aggregates a list of elements from the activity. 497 * activity = { 498 * mapKey : [ 499 * { 500 * titleKey : "Title 1", 501 * … 502 * }, 503 * { 504 * titleKey : "Title 2", 505 * … 506 * }, 507 * { 508 * titleKey : "Title 3", 509 * … 510 * } 511 * ], 512 * … 513 * } 514 * @param activity the activity to use 515 * @param mapKey the key of the list to use 516 * @param titleKey title to use from the map 517 * @return a list, separated with commas, between each titles 518 */ 519 protected String getTitles(Map<String, Object> activity, String mapKey, String titleKey) 520 { 521 @SuppressWarnings("unchecked") 522 List<Map<String, String>> items = (List<Map<String, String>>) activity.get(mapKey); 523 524 525 if (items == null) 526 { 527 return (String) activity.get(titleKey); 528 } 529 else 530 { 531 String result = null; 532 533 for (Map<String, String> item : items) 534 { 535 if (result == null) 536 { 537 result = item.get(titleKey); 538 } 539 else 540 { 541 result += ", " + item.get(titleKey); 542 } 543 } 544 545 return result; 546 } 547 } 548 549}