001/* 002 * Copyright 2015 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.workspaces.calendars; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.LinkedList; 021import java.util.List; 022import java.util.Map; 023import java.util.Objects; 024import java.util.UUID; 025 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.commons.lang.BooleanUtils; 029import org.apache.commons.lang3.StringUtils; 030import org.apache.jackrabbit.util.Text; 031 032import org.ametys.core.observation.Event; 033import org.ametys.core.right.RightManager.RightResult; 034import org.ametys.core.ui.Callable; 035import org.ametys.core.user.UserIdentity; 036import org.ametys.plugins.explorer.ModifiableExplorerNode; 037import org.ametys.plugins.explorer.ObservationConstants; 038import org.ametys.plugins.explorer.resources.jcr.JCRResourcesCollection; 039import org.ametys.plugins.repository.AmetysObjectIterable; 040import org.ametys.plugins.repository.AmetysObjectIterator; 041import org.ametys.plugins.repository.ModifiableTraversableAmetysObject; 042import org.ametys.plugins.repository.jcr.DefaultTraversableAmetysObject; 043import org.ametys.plugins.repository.query.QueryHelper; 044import org.ametys.plugins.repository.query.expression.Expression; 045import org.ametys.plugins.repository.query.expression.Expression.Operator; 046import org.ametys.plugins.repository.query.expression.StringExpression; 047import org.ametys.plugins.workspaces.calendars.Calendar.CalendarVisibility; 048import org.ametys.plugins.workspaces.calendars.events.CalendarEvent; 049import org.ametys.plugins.workspaces.calendars.events.CalendarEventJSONHelper; 050import org.ametys.plugins.workspaces.calendars.jcr.JCRCalendar; 051import org.ametys.plugins.workspaces.calendars.jcr.JCRCalendarFactory; 052import org.ametys.plugins.workspaces.calendars.task.TaskCalendar; 053import org.ametys.plugins.workspaces.project.ProjectConstants; 054import org.ametys.plugins.workspaces.project.objects.Project; 055import org.ametys.plugins.workspaces.tasks.TasksWorkspaceModule; 056import org.ametys.plugins.workspaces.tasks.WorkspaceTaskDAO; 057 058/** 059 * Calendar DAO 060 */ 061public class CalendarDAO extends AbstractCalendarDAO 062{ 063 /** Avalon Role */ 064 public static final String ROLE = CalendarDAO.class.getName(); 065 066 /** The tasks list JSON helper */ 067 protected CalendarEventJSONHelper _calendarEventJSONHelper; 068 069 /** The task DAO */ 070 protected WorkspaceTaskDAO _taskDAO; 071 072 @Override 073 public void service(ServiceManager manager) throws ServiceException 074 { 075 super.service(manager); 076 _calendarEventJSONHelper = (CalendarEventJSONHelper) manager.lookup(CalendarEventJSONHelper.ROLE); 077 _taskDAO = (WorkspaceTaskDAO) manager.lookup(WorkspaceTaskDAO.ROLE); 078 } 079 080 /** 081 * Get calendar info 082 * @param calendar The calendar 083 * @param recursive True to get data for sub calendars 084 * @param includeEvents True to also include child events 085 * @param useICSFormat true to use ICS Format for dates 086 * @return the calendar data in a map 087 */ 088 public Map<String, Object> getCalendarData(Calendar calendar, boolean recursive, boolean includeEvents, boolean useICSFormat) 089 { 090 Map<String, Object> result = new HashMap<>(); 091 092 result.put("id", calendar.getId()); 093 result.put("title", Text.unescapeIllegalJcrChars(calendar.getName())); 094 result.put("description", calendar.getDescription()); 095 result.put("templateDesc", calendar.getTemplateDescription()); 096 result.put("color", calendar.getColor()); 097 result.put("visibility", calendar.getVisibility().name().toLowerCase()); 098 result.put("public", calendar.getVisibility() == CalendarVisibility.PUBLIC); 099 100 if (calendar instanceof WorkflowAwareCalendar calendarWA) 101 { 102 result.put("workflowName", calendarWA.getWorkflowName()); 103 } 104 105 result.put("isTaskCalendar", calendar instanceof TaskCalendar); 106 result.put("isTaskCalendarDisabled", calendar instanceof TaskCalendar cal && cal.isDisabled()); 107 108 if (recursive) 109 { 110 List<Map<String, Object>> calendarList = new LinkedList<>(); 111 result.put("calendars", calendarList); 112 for (Calendar child : calendar.getChildCalendars()) 113 { 114 calendarList.add(getCalendarData(child, recursive, includeEvents, useICSFormat)); 115 } 116 } 117 118 if (includeEvents) 119 { 120 List<Map<String, Object>> eventList = new LinkedList<>(); 121 result.put("events", eventList); 122 123 for (CalendarEvent event : calendar.getAllEvents()) 124 { 125 eventList.add(_calendarEventJSONHelper.eventAsJson(event, false, useICSFormat)); 126 } 127 } 128 129 result.put("rights", _extractCalendarRightData(calendar)); 130 result.put("token", getCalendarIcsToken(calendar, true)); 131 132 133 return result; 134 } 135 136 /** 137 * Get calendar info 138 * @param calendar The calendar 139 * @return the calendar data in a map 140 */ 141 public Map<String, Object> getCalendarProperties(Calendar calendar) 142 { 143 return getCalendarData(calendar, false, false, false); 144 } 145 /** 146 * Add a calendar 147 * @param inputName The desired name for the calendar 148 * @param color The calendar color 149 * @param isPublic true if the calendar is public 150 * @return The result map with id, parentId and name keys 151 */ 152 @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION) 153 public Map<String, Object> addCalendar(String inputName, String color, boolean isPublic) 154 { 155 String rootId = _getCalendarRoot(true).getId(); 156 return addCalendar(rootId, inputName, StringUtils.EMPTY, StringUtils.EMPTY, color, isPublic ? CalendarVisibility.PUBLIC.name() : CalendarVisibility.PRIVATE.name(), "calendar-default", false); 157 } 158 159 /** 160 * Add a calendar 161 * @param id The identifier of the parent in which the calendar will be added 162 * @param inputName The desired name for the calendar 163 * @param description The calendar description 164 * @param templateDesc The calendar template description 165 * @param color The calendar color 166 * @param visibility The calendar visibility 167 * @param workflowName The calendar workflow name 168 * @param renameIfExists True to rename if existing 169 * @return The result map with id, parentId and name keys 170 */ 171 public Map<String, Object> addCalendar(String id, String inputName, String description, String templateDesc, String color, String visibility, String workflowName, Boolean renameIfExists) 172 { 173 return addCalendar(_resolver.resolveById(id), inputName, description, templateDesc, color, visibility, workflowName, renameIfExists, true, true); 174 } 175 176 /** 177 * Add a calendar 178 * @param parent The parent in which the calendar will be added 179 * @param inputName The desired name for the calendar 180 * @param description The calendar description 181 * @param templateDesc The calendar template description 182 * @param color The calendar color 183 * @param visibility The calendar visibility 184 * @param workflowName The calendar workflow name 185 * @param renameIfExists True to rename if existing 186 * @param checkRights true to check if the current user have enough rights to create the calendar 187 * @param notify True to notify the calendar creation 188 * @return The result map with id, parentId and name keys 189 */ 190 public Map<String, Object> addCalendar(ModifiableTraversableAmetysObject parent, String inputName, String description, String templateDesc, String color, String visibility, String workflowName, Boolean renameIfExists, Boolean checkRights, boolean notify) 191 { 192 String originalName = Text.escapeIllegalJcrChars(inputName); 193 194 // Check user right 195 if (checkRights) 196 { 197 _checkUserRights(parent, RIGHTS_CALENDAR_ADD); 198 } 199 200 if (BooleanUtils.isNotTrue(renameIfExists) && parent.hasChild(originalName)) 201 { 202 getLogger().warn("Cannot create the calendar with name '" + originalName + "', an object with same name already exists."); 203 return Map.of("message", "already-exist"); 204 } 205 206 if (!_explorerResourcesDAO.checkLock(parent)) 207 { 208 getLogger().warn("User '" + _currentUserProvider.getUser() + "' try to modify the object '" + parent.getName() + "' but it is locked by another user"); 209 return Map.of("message", "locked"); 210 } 211 212 int index = 2; 213 String name = originalName; 214 while (parent.hasChild(name)) 215 { 216 name = originalName + " (" + index + ")"; 217 index++; 218 } 219 220 JCRCalendar calendar = parent.createChild(name, JCRCalendarFactory.CALENDAR_NODETYPE); 221 calendar.setWorkflowName(workflowName); 222 calendar.setDescription(description); 223 calendar.setTemplateDescription(templateDesc); 224 calendar.setColor(color); 225 calendar.setVisibility(StringUtils.isNotEmpty(visibility) ? CalendarVisibility.valueOf(visibility.toUpperCase()) : CalendarVisibility.PRIVATE); 226 parent.saveChanges(); 227 228 // Notify listeners 229 Map<String, Object> eventParams = new HashMap<>(); 230 eventParams.put(ObservationConstants.ARGS_ID, calendar.getId()); 231 eventParams.put(ObservationConstants.ARGS_PARENT_ID, parent.getId()); 232 eventParams.put(ObservationConstants.ARGS_NAME, name); 233 eventParams.put(ObservationConstants.ARGS_PATH, calendar.getPath()); 234 235 if (notify) 236 { 237 _observationManager.notify(new Event(org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_CREATED, _currentUserProvider.getUser(), eventParams)); 238 } 239 240 return getCalendarProperties(calendar); 241 } 242 243 /** 244 * Edit a calendar 245 * @param id The identifier of the calendar 246 * @param inputName The new name 247 * @param templateDesc The new calendar template description 248 * @param color The calendar color 249 * @param isPublic true if the calendar is public 250 * @return The result map with id and name keys 251 */ 252 @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION) 253 public Map<String, Object> editCalendar(String id, String inputName, String templateDesc, String color, boolean isPublic) 254 { 255 CalendarVisibility visibility = isPublic ? CalendarVisibility.PUBLIC : CalendarVisibility.PRIVATE; 256 257 assert id != null; 258 String rename = Text.escapeIllegalJcrChars(inputName); 259 260 JCRCalendar calendar = _resolver.resolveById(id); 261 262 _checkUserRights(calendar, RIGHTS_CALENDAR_EDIT); 263 264 String name = calendar.getName(); 265 ModifiableTraversableAmetysObject parent = calendar.getParent(); 266 267 if (!StringUtils.equals(rename, name) && parent.hasChild(rename)) 268 { 269 getLogger().warn("Cannot edit the calendar with the new name '" + inputName + "', an object with same name already exists."); 270 return Map.of("message", "already-exist"); 271 } 272 273 if (!_explorerResourcesDAO.checkLock(calendar)) 274 { 275 getLogger().warn("User '" + _currentUserProvider.getUser() + "' try to modify calendar '" + calendar.getName() + "' but it is locked by another user"); 276 return Map.of("message", "locked"); 277 } 278 279 if (!StringUtils.equals(name, rename)) 280 { 281 int index = 2; 282 name = Text.escapeIllegalJcrChars(rename); 283 while (parent.hasChild(name)) 284 { 285 name = rename + " (" + index + ")"; 286 index++; 287 } 288 calendar.rename(name); 289 } 290 291 calendar.setTemplateDescription(templateDesc); 292 calendar.setColor(color); 293 calendar.setVisibility(visibility); 294 295 parent.saveChanges(); 296 297 // Notify listeners 298 Map<String, Object> eventParams = new HashMap<>(); 299 eventParams.put(ObservationConstants.ARGS_ID, calendar.getId()); 300 eventParams.put(ObservationConstants.ARGS_PARENT_ID, parent.getId()); 301 eventParams.put(ObservationConstants.ARGS_NAME, name); 302 eventParams.put(ObservationConstants.ARGS_PATH, calendar.getPath()); 303 304 _observationManager.notify(new Event(org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_UPDATED, _currentUserProvider.getUser(), eventParams)); 305 306 return getCalendarProperties(calendar); 307 } 308 309 /** 310 * Edit the task calendar 311 * @param inputName the input name 312 * @param color the color 313 * @param isPublic <code>true</code> if the calendar is public 314 * @param disabled <code>true</code> if the calendar is disabled 315 * @return the calendar properties 316 * @throws IllegalAccessException if a right error occurred 317 */ 318 @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION) 319 public Map<String, Object> editTaskCalendar(String inputName, String color, boolean isPublic, boolean disabled) throws IllegalAccessException 320 { 321 Project project = _workspaceHelper.getProjectFromRequest(); 322 TaskCalendar taskCalendar = getTaskCalendar(project, false); 323 324 // Check user right 325 _checkUserRights(_getCalendarRoot(project, false), RIGHTS_CALENDAR_EDIT); 326 327 if (taskCalendar != null) 328 { 329 taskCalendar.rename(inputName); 330 taskCalendar.setColor(color); 331 taskCalendar.setVisibility(isPublic ? CalendarVisibility.PUBLIC : CalendarVisibility.PRIVATE); 332 taskCalendar.disable(disabled); 333 } 334 return getCalendarProperties(taskCalendar); 335 } 336 337 /** 338 * Delete a calendar 339 * @param id The id of the calendar 340 * @return The result map with id, parent id and message keys 341 */ 342 @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION) 343 public Map<String, Object> deleteCalendar(String id) 344 { 345 Map<String, Object> result = new HashMap<>(); 346 347 assert id != null; 348 349 JCRCalendar calendar = _resolver.resolveById(id); 350 351 _checkUserRights(calendar, RIGHTS_CALENDAR_DELETE); 352 353 if (!_explorerResourcesDAO.checkLock(calendar)) 354 { 355 getLogger().warn("User '" + _currentUserProvider.getUser() + "' try to delete calendar'" + calendar.getName() + "' but it is locked by another user"); 356 result.put("message", "locked"); 357 return result; 358 } 359 360 ModifiableExplorerNode parent = calendar.getParent(); 361 String parentId = parent.getId(); 362 String name = calendar.getName(); 363 String path = calendar.getPath(); 364 365 calendar.remove(); 366 parent.saveChanges(); 367 368 // Notify listeners 369 Map<String, Object> eventParams = new HashMap<>(); 370 eventParams.put(ObservationConstants.ARGS_ID, id); 371 eventParams.put(ObservationConstants.ARGS_PARENT_ID, parentId); 372 eventParams.put(ObservationConstants.ARGS_NAME, name); 373 eventParams.put(ObservationConstants.ARGS_PATH, path); 374 375 _observationManager.notify(new Event(org.ametys.plugins.workspaces.calendars.ObservationConstants.EVENT_CALENDAR_DELETED, _currentUserProvider.getUser(), eventParams)); 376 377 result.put("id", id); 378 result.put("parentId", parentId); 379 380 return result; 381 } 382 383 /** 384 * Get or create the calendar ICS token 385 * @param calendar The calendar 386 * @param createIfNotExisting Create the token if none exists for the given calendar 387 * @return The token 388 */ 389 public String getCalendarIcsToken(Calendar calendar, boolean createIfNotExisting) 390 { 391 String token = calendar.getIcsUrlToken(); 392 393 if (createIfNotExisting && token == null && calendar instanceof JCRCalendar) 394 { 395 token = UUID.randomUUID().toString(); 396 ((JCRCalendar) calendar).setIcsUrlToken(token); 397 ((JCRCalendar) calendar).saveChanges(); 398 } 399 400 return token; 401 } 402 403 /** 404 * Retrieve the calendar for the matching ICS token 405 * @param token The ICS token 406 * @return The calendar, or null if not found 407 */ 408 public Calendar getCalendarFromIcsToken(String token) 409 { 410 if (StringUtils.isEmpty(token)) 411 { 412 return null; 413 } 414 415 Expression expr = new StringExpression(JCRCalendar.CALENDAR_ICS_TOKEN, Operator.EQ, token); 416 String calendarsQuery = QueryHelper.getXPathQuery(null, JCRCalendarFactory.CALENDAR_NODETYPE, expr); 417 AmetysObjectIterable<JCRCalendar> calendars = _resolver.query(calendarsQuery); 418 AmetysObjectIterator<JCRCalendar> calendarsIterator = calendars.iterator(); 419 420 if (calendarsIterator.getSize() > 0) 421 { 422 return calendarsIterator.next(); 423 } 424 425 // Don't find a token in default calendars, so check in the task calendars 426 return _projectManager.getProjects() 427 .stream() 428 .map(p -> this.getTaskCalendar(p, true)) 429 .filter(Objects::nonNull) 430 .filter(c -> c.getIcsUrlToken().equals(token)) 431 .findFirst() 432 .orElse(null); 433 } 434 435 /** 436 * Internal method to extract the data concerning the right of the current user for a calendar 437 * @param calendar The calendar 438 * @return The map of right data. Keys are the rights id, and values indicates whether the current user has the right or not. 439 */ 440 protected Map<String, Object> _extractCalendarRightData(Calendar calendar) 441 { 442 Map<String, Object> rightsData = new HashMap<>(); 443 444 UserIdentity user = _currentUserProvider.getUser(); 445 boolean isTaskCalendar = calendar instanceof TaskCalendar; 446 447 // Add 448 rightsData.put("add-event", !isTaskCalendar && _rightManager.hasRight(user, RIGHTS_EVENT_ADD, calendar) == RightResult.RIGHT_ALLOW); 449 450 // edit - delete 451 rightsData.put("edit", !isTaskCalendar && _rightManager.hasRight(user, RIGHTS_CALENDAR_EDIT, calendar) == RightResult.RIGHT_ALLOW); 452 rightsData.put("delete", !isTaskCalendar && _rightManager.hasRight(user, RIGHTS_CALENDAR_DELETE, calendar) == RightResult.RIGHT_ALLOW); 453 454 return rightsData; 455 } 456 457 /** 458 * Get the data of every available calendar for the current project 459 * @return the list of calendars 460 */ 461 @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION) 462 public List<Map<String, Object>> getCalendars() 463 { 464 Project project = _workspaceHelper.getProjectFromRequest(); 465 466 _checkReadAccess(project, CalendarWorkspaceModule.CALENDAR_MODULE_ID); 467 468 List<Map<String, Object>> calendarsData = new ArrayList<>(); 469 CalendarWorkspaceModule calendarModule = (CalendarWorkspaceModule) _workspaceModuleEP.getModule(CalendarWorkspaceModule.CALENDAR_MODULE_ID); 470 471 for (Calendar calendar : calendarModule.getCalendars(project, true)) 472 { 473 if (calendarModule.canView(calendar)) 474 { 475 calendarsData.add(this.getCalendarProperties(calendar)); 476 } 477 } 478 479 return calendarsData; 480 } 481 482 /** 483 * Get the colors of calendars 484 * @return colors 485 */ 486 @Callable (rights = Callable.NO_CHECK_REQUIRED) 487 public Map<String, CalendarColorsComponent.CalendarColor> getColors() 488 { 489 return _calendarColors.getColors(); 490 } 491 492 /** 493 * Get user rights on root calendar of current project 494 * @return the user rights 495 */ 496 @Callable (rights = Callable.NO_CHECK_REQUIRED) 497 public Map<String, Object> getUserRights() 498 { 499 Map<String, Object> results = new HashMap<>(); 500 ModifiableTraversableAmetysObject calendarRoot = _getCalendarRoot(false); 501 502 UserIdentity user = _currentUserProvider.getUser(); 503 results.put("canCreateCalendar", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_CALENDAR_ADD, calendarRoot) == RightResult.RIGHT_ALLOW); 504 results.put("canEditCalendar", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_CALENDAR_EDIT, calendarRoot) == RightResult.RIGHT_ALLOW); 505 results.put("canRemoveCalendar", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_CALENDAR_DELETE, calendarRoot) == RightResult.RIGHT_ALLOW); 506 results.put("canCreateEvent", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_EVENT_ADD, calendarRoot) == RightResult.RIGHT_ALLOW); 507 results.put("canEditEvent", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_EVENT_EDIT, calendarRoot) == RightResult.RIGHT_ALLOW); 508 results.put("canRemoveAnyEvent", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_EVENT_DELETE, calendarRoot) == RightResult.RIGHT_ALLOW); 509 results.put("canRemoveSelfEvent", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_EVENT_DELETE_OWN, calendarRoot) == RightResult.RIGHT_ALLOW); 510 results.put("canCreateTags", calendarRoot != null && _rightManager.hasRight(user, ProjectConstants.RIGHT_PROJECT_ADD_TAG, calendarRoot) == RightResult.RIGHT_ALLOW); 511 results.put("canHandleResource", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_HANDLE_RESOURCE, calendarRoot) == RightResult.RIGHT_ALLOW); 512 results.put("canBookResource", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_BOOK_RESOURCE, calendarRoot) == RightResult.RIGHT_ALLOW); 513 results.put("sharePrivateCalendar", calendarRoot != null && _rightManager.hasRight(user, RIGHTS_EVENT_EDIT, calendarRoot) == RightResult.RIGHT_ALLOW); 514 515 return results; 516 } 517 518 /** 519 * Get the calendar root 520 * @param createIfNotExist true to create root if not exist yet 521 * @return the calendar root 522 */ 523 protected ModifiableTraversableAmetysObject _getCalendarRoot(boolean createIfNotExist) 524 { 525 return _getCalendarRoot(_workspaceHelper.getProjectFromRequest(), createIfNotExist); 526 } 527 528 /** 529 * Get the calendar root form the project 530 * @param project the project 531 * @param createIfNotExist true to create root if not exist yet 532 * @return the calendar root 533 */ 534 protected ModifiableTraversableAmetysObject _getCalendarRoot(Project project, boolean createIfNotExist) 535 { 536 CalendarWorkspaceModule calendarModule = (CalendarWorkspaceModule) _workspaceModuleEP.getModule(CalendarWorkspaceModule.CALENDAR_MODULE_ID); 537 return calendarModule.getCalendarsRoot(project, createIfNotExist); 538 } 539 540 /** 541 * Get the data of calendar used to store resources 542 * @return the calendar used to store resources 543 */ 544 @Callable (rights = Callable.CHECKED_BY_IMPLEMENTATION) 545 public Map<String, Object> getResourceCalendar() 546 { 547 Project project = _workspaceHelper.getProjectFromRequest(); 548 _checkReadAccess(project, CalendarWorkspaceModule.CALENDAR_MODULE_ID); 549 550 CalendarWorkspaceModule calendarModule = (CalendarWorkspaceModule) _workspaceModuleEP.getModule(CalendarWorkspaceModule.CALENDAR_MODULE_ID); 551 Calendar calendar = calendarModule.getResourceCalendar(project); 552 553 return this.getCalendarProperties(calendar); 554 } 555 556 /** 557 * Get the task calendar 558 * @param project the project 559 * @param onlyIfEnabled <code>true</code> to return the task calendar only if it is enabled 560 * @return the task calendar 561 */ 562 public TaskCalendar getTaskCalendar(Project project, boolean onlyIfEnabled) 563 { 564 if (_projectManager.isModuleActivated(project, TasksWorkspaceModule.TASK_MODULE_ID)) 565 { 566 JCRResourcesCollection root = (JCRResourcesCollection) _getCalendarRoot(project, false); 567 TaskCalendar calendar = new TaskCalendar(project, root, _taskDAO); 568 return !onlyIfEnabled || !calendar.isDisabled() ? calendar : null; 569 } 570 571 return null; 572 } 573 574 /** 575 * <code>true</code> if the current user has read access on the task calendar 576 * @param project the project 577 * @return <code>true</code> if the current user has read access on the task calendar 578 */ 579 public boolean hasTaskCalendarReadAccess(Project project) 580 { 581 TasksWorkspaceModule taskModule = (TasksWorkspaceModule) _workspaceModuleEP.getModule(TasksWorkspaceModule.TASK_MODULE_ID); 582 DefaultTraversableAmetysObject tasksRoot = taskModule.getTasksRoot(project, true); 583 return _rightManager.currentUserHasReadAccess(tasksRoot); 584 } 585}