From 7f3bb5cfa29fce797997b35f95101a327470c4e0 Mon Sep 17 00:00:00 2001 From: Myles Carey Date: Fri, 7 Jul 2023 08:12:22 -0700 Subject: [PATCH] SAK-49082: DateManager: Additional nullable date support, clear date button, fixes for SAK-46023, SAK-46212, SAK-48788, SAK-48789 --- .../sass/modules/tool/siteinfo/_siteinfo.scss | 39 +++ .../datemanager/api/DateManagerService.java | 3 + .../impl/DateManagerServiceImpl.java | 224 +++++++++++++----- .../datemanager/tool/MainController.java | 4 + .../resources/static/js/initDatePicker.js | 50 +++- .../WEB-INF/templates/tool_fragment.html | 62 +++-- 6 files changed, 298 insertions(+), 84 deletions(-) diff --git a/library/src/skins/default/src/sass/modules/tool/siteinfo/_siteinfo.scss b/library/src/skins/default/src/sass/modules/tool/siteinfo/_siteinfo.scss index ffff3b433f6e..9e57110afc1a 100644 --- a/library/src/skins/default/src/sass/modules/tool/siteinfo/_siteinfo.scss +++ b/library/src/skins/default/src/sass/modules/tool/siteinfo/_siteinfo.scss @@ -76,6 +76,16 @@ margin-bottom: 0; table-layout: fixed; + .field-required { + &:after { + content: "*"; + color: var(--errorBanner-color); + position: relative; + top: 3px; + left: 3px; + } + } + td { &.ajax-error { background-color: var(--errorBanner-bgcolor); @@ -94,6 +104,35 @@ border-bottom-right-radius: 0; } + .hasDatepicker { + padding-right: 22%; + overflow: hidden; + text-overflow: ellipsis; + } + + .ui-datepicker-trigger { + position: absolute; + top: 0; + right: 8px; + } + + .ui-datepicker-clear-date { + position: relative; + top: 16%; + right: 22px; + cursor: text; + text-decoration: none; + } + + .ui-datapicker-clear-date-icon { + cursor: pointer; + } + + .ui-datepicker-clear-date > i[disabled] { + cursor: not-allowed; + color:#757575; + } + .day-of-week { text-transform: capitalize; } diff --git a/site-manage/datemanager/api/src/java/org/sakaiproject/datemanager/api/DateManagerService.java b/site-manage/datemanager/api/src/java/org/sakaiproject/datemanager/api/DateManagerService.java index 13ce1a23ba81..e4d2e004893e 100644 --- a/site-manage/datemanager/api/src/java/org/sakaiproject/datemanager/api/DateManagerService.java +++ b/site-manage/datemanager/api/src/java/org/sakaiproject/datemanager/api/DateManagerService.java @@ -60,11 +60,13 @@ public interface DateManagerService { public JSONArray getResourcesForContext(String siteId); public DateManagerValidation validateResources(String siteId, JSONArray resources) throws Exception; public void updateResources(DateManagerValidation resourceValidation) throws Exception; + public void clearUpdateResourceLocks(DateManagerValidation resourceValidation) throws Exception; // Calendar methods public JSONArray getCalendarEventsForContext(String siteId); public DateManagerValidation validateCalendarEvents(String siteId, JSONArray calendarEvents) throws Exception; public void updateCalendarEvents(DateManagerValidation calendarValidation) throws Exception; + public void clearUpdateCalendarLocks(DateManagerValidation calendarValidation) throws Exception; // Forum methods public JSONArray getForumsForContext(String siteId); @@ -75,6 +77,7 @@ public interface DateManagerService { public JSONArray getAnnouncementsForContext(String siteId); public DateManagerValidation validateAnnouncements(String siteId, JSONArray announcements) throws Exception; public void updateAnnouncements(DateManagerValidation announcementValidation) throws Exception; + public void clearUpdateAnnouncementLocks(DateManagerValidation announcementValidation) throws Exception; // Lessons methods public JSONArray getLessonsForContext(String siteId); diff --git a/site-manage/datemanager/impl/src/java/org/sakaiproject/datemanager/impl/DateManagerServiceImpl.java b/site-manage/datemanager/impl/src/java/org/sakaiproject/datemanager/impl/DateManagerServiceImpl.java index b1b6aac1dea7..a838e84279ad 100644 --- a/site-manage/datemanager/impl/src/java/org/sakaiproject/datemanager/impl/DateManagerServiceImpl.java +++ b/site-manage/datemanager/impl/src/java/org/sakaiproject/datemanager/impl/DateManagerServiceImpl.java @@ -317,11 +317,23 @@ public DateManagerValidation validateAssignments(String siteId, JSONArray assign continue; } - Instant openDate = userTimeService.parseISODateInUserTimezone((String)jsonAssignment.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME)).toInstant(); - Instant dueDate = userTimeService.parseISODateInUserTimezone((String)jsonAssignment.get(DateManagerConstants.JSON_DUEDATE_PARAM_NAME)).toInstant(); - Instant acceptUntil = userTimeService.parseISODateInUserTimezone((String)jsonAssignment.get(DateManagerConstants.JSON_ACCEPTUNTIL_PARAM_NAME)).toInstant(); - boolean errored = false; + String openDateRaw = (String) jsonAssignment.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME); + String dueDateRaw = (String) jsonAssignment.get(DateManagerConstants.JSON_DUEDATE_PARAM_NAME); + String acceptUntilRaw = (String) jsonAssignment.get(DateManagerConstants.JSON_ACCEPTUNTIL_PARAM_NAME); + Instant openDate = null; + Instant dueDate = null; + Instant acceptUntil = null; + + if (StringUtils.isNotBlank(openDateRaw)) { + openDate = userTimeService.parseISODateInUserTimezone(openDateRaw).toInstant(); + } + if (StringUtils.isNotBlank(dueDateRaw)) { + dueDate = userTimeService.parseISODateInUserTimezone(dueDateRaw).toInstant(); + } + if (StringUtils.isNotBlank(acceptUntilRaw)) { + acceptUntil = userTimeService.parseISODateInUserTimezone(acceptUntilRaw).toInstant(); + } if (openDate == null) { errored = errors.add(new DateManagerError(DateManagerConstants.JSON_OPENDATE_PARAM_NAME, rb.getString("error.open.date.not.found"), "assignments", toolTitle, idx)); @@ -559,18 +571,6 @@ public DateManagerValidation validateAssessments(String siteId, JSONArray assess log.debug("Open {} ; Due {} ; Until {} ; Feedback Start {} ; Feedback End {}", jsonAssessment.get(DateManagerConstants.JSON_OPENDATELABEL_PARAM_NAME), jsonAssessment.get(DateManagerConstants.JSON_DUEDATELABEL_PARAM_NAME), jsonAssessment.get("accept_until_label"), jsonAssessment.get(DateManagerConstants.JSON_FEEDBACKSTARTLABEL_PARAM_NAME), jsonAssessment.get(DateManagerConstants.JSON_FEEDBACKENDLABEL_PARAM_NAME)); - if(StringUtils.isBlank((String)jsonAssessment.get(DateManagerConstants.JSON_DUEDATELABEL_PARAM_NAME))) { - dueDate = null; - } - if(StringUtils.isBlank((String)jsonAssessment.get("accept_until_label"))) { - acceptUntil = null; - } - if(StringUtils.isBlank((String)jsonAssessment.get(DateManagerConstants.JSON_FEEDBACKSTARTLABEL_PARAM_NAME))) { - feedbackStart = null; - } - if(StringUtils.isBlank((String)jsonAssessment.get(DateManagerConstants.JSON_FEEDBACKENDLABEL_PARAM_NAME))) { - feedbackEnd = null; - } DateManagerUpdate update = new DateManagerUpdate(assessment, openDate, dueDate, acceptUntil); update.setFeedbackStartDate(feedbackStart); @@ -624,9 +624,9 @@ public void updateAssessments(DateManagerValidation assessmentsValidation) throw } if (AssessmentFeedbackIfc.FEEDBACK_BY_DATE.equals(assessment.getAssessmentFeedback().getFeedbackDelivery())) { control.setFeedbackDate(Date.from(update.feedbackStartDate)); - if (update.feedbackEndDate != null) { - control.setFeedbackEndDate(Date.from(update.feedbackEndDate)); - } + Date feedbackEndDateTemp = + update.feedbackEndDate != null ? Date.from(update.feedbackEndDate) : null; + control.setFeedbackEndDate(feedbackEndDateTemp); } assessment.setAssessmentAccessControl(control); assessmentServiceQueries.saveOrUpdate(assessment); @@ -819,10 +819,27 @@ public DateManagerValidation validateSignupMeetings(String siteId, JSONArray sig continue; } - Instant openDate = userTimeService.parseISODateInUserTimezone((String)jsonMeeting.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME)).toInstant(); - Instant dueDate = userTimeService.parseISODateInUserTimezone((String)jsonMeeting.get(DateManagerConstants.JSON_DUEDATE_PARAM_NAME)).toInstant(); - Instant signupBegins = userTimeService.parseISODateInUserTimezone((String)jsonMeeting.get(DateManagerConstants.JSON_SIGNUPBEGINS_PARAM_NAME)).toInstant(); - Instant signupDeadline = userTimeService.parseISODateInUserTimezone((String)jsonMeeting.get(DateManagerConstants.JSON_SIGNUPDEADLINE_PARAM_NAME)).toInstant(); + String openDateRaw = (String) jsonMeeting.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME); + String dueDateRaw = (String) jsonMeeting.get(DateManagerConstants.JSON_DUEDATE_PARAM_NAME); + String signupBeginsRaw = (String) jsonMeeting.get(DateManagerConstants.JSON_SIGNUPBEGINS_PARAM_NAME); + String signupDeadlineRaw = (String) jsonMeeting.get(DateManagerConstants.JSON_SIGNUPDEADLINE_PARAM_NAME); + Instant openDate = null; + Instant dueDate = null; + Instant signupBegins = null; + Instant signupDeadline = null; + + if (StringUtils.isNotBlank(openDateRaw)) { + openDate = userTimeService.parseISODateInUserTimezone(openDateRaw).toInstant(); + } + if (StringUtils.isNotBlank(dueDateRaw)) { + dueDate = userTimeService.parseISODateInUserTimezone(dueDateRaw).toInstant(); + } + if (StringUtils.isNotBlank(signupBeginsRaw)) { + signupBegins = userTimeService.parseISODateInUserTimezone(signupBeginsRaw).toInstant(); + } + if (StringUtils.isNotBlank(signupDeadlineRaw)) { + signupDeadline = userTimeService.parseISODateInUserTimezone(signupDeadlineRaw).toInstant(); + } boolean errored = false; if (openDate == null) { errored = errors.add(new DateManagerError(DateManagerConstants.JSON_OPENDATE_PARAM_NAME, rb.getString("error.open.date.not.found"), "signupMeetings", toolTitle, idx)); @@ -849,19 +866,19 @@ public DateManagerValidation validateSignupMeetings(String siteId, JSONArray sig DateManagerUpdate update = new DateManagerUpdate(meeting, openDate, dueDate, null, null, null); update.setSignupBegins(signupBegins); update.setSignupDeadline(signupDeadline); - if (!update.openDate.isBefore(update.dueDate)) { + if (update.openDate != null && update.dueDate != null && !update.openDate.isBefore(update.dueDate)) { errors.add(new DateManagerError(DateManagerConstants.JSON_OPENDATE_PARAM_NAME, rb.getString("error.open.date.before.due.date"), "signupMeetings", toolTitle, idx)); continue; } - if (update.signupBegins.isAfter(update.openDate)) { + if (update.signupBegins != null && update.openDate != null && update.signupBegins.isAfter(update.openDate)) { errors.add(new DateManagerError(DateManagerConstants.JSON_SIGNUPBEGINS_PARAM_NAME, rb.getString("error.signup.begins.after.open.date"), "signupMeetings", toolTitle, idx)); continue; } - if (update.signupDeadline.isAfter(update.dueDate)) { + if (update.signupDeadline != null && update.dueDate != null && update.signupDeadline.isAfter(update.dueDate)) { errors.add(new DateManagerError(DateManagerConstants.JSON_SIGNUPDEADLINE_PARAM_NAME, rb.getString("error.signup.deadline.after.due.date"), "signupMeetings", toolTitle, idx)); continue; } - if (update.signupBegins.isAfter(update.signupDeadline)) { + if (update.signupBegins != null && update.signupDeadline != null && update.signupBegins.isAfter(update.signupDeadline)) { errors.add(new DateManagerError(DateManagerConstants.JSON_SIGNUPBEGINS_PARAM_NAME, rb.getString("error.signup.begins.after.signup.deadline"), "signupMeetings", toolTitle, idx)); continue; } @@ -956,13 +973,6 @@ public DateManagerValidation validateResources(String siteId, JSONArray resource dueDate = userTimeService.parseISODateInUserTimezone(dueDateRaw).toInstant(); } - log.debug("Open {} ; Due {}", jsonResource.get(DateManagerConstants.JSON_OPENDATELABEL_PARAM_NAME), jsonResource.get(DateManagerConstants.JSON_DUEDATELABEL_PARAM_NAME)); - if(StringUtils.isBlank((String)jsonResource.get(DateManagerConstants.JSON_OPENDATELABEL_PARAM_NAME))) { - openDate = null; - } - if(StringUtils.isBlank((String)jsonResource.get(DateManagerConstants.JSON_DUEDATELABEL_PARAM_NAME))) { - dueDate = null; - } if (openDate != null && dueDate != null && !openDate.isBefore(dueDate)) { errors.add(new DateManagerError(DateManagerConstants.JSON_OPENDATE_PARAM_NAME, rb.getString("error.open.date.before.due.date"), "resources", toolTitle, idx)); continue; @@ -1012,6 +1022,22 @@ public DateManagerValidation validateResources(String siteId, JSONArray resource return resourcesValidate; } + /** + * {@inheritDoc} + */ + @Override + public void clearUpdateResourceLocks(DateManagerValidation resourceValidation) throws Exception { + try { + for (DateManagerUpdate update : (List)(Object) resourceValidation.getUpdates()) { + if (update.object instanceof ContentResourceEdit) { + contentHostingService.cancelResource((ContentResourceEdit) update.getObject()); + } + } + } catch (Exception e) { + log.error("Exception thrown: {}", e.getMessage()); + } + } + /** * {@inheritDoc} */ @@ -1108,17 +1134,25 @@ public DateManagerValidation validateCalendarEvents(String siteId, JSONArray cal errors.add(new DateManagerError("calendar", rb.getFormattedMessage("error.item.not.found", new Object[]{rb.getString("tool.calendar.item.name")}), "calendarEvents", toolTitle, idx)); continue; } - - Instant openDate = userTimeService.parseISODateInUserTimezone((String)jsonEvent.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME)).toInstant(); - Instant dueDate = userTimeService.parseISODateInUserTimezone((String)jsonEvent.get(DateManagerConstants.JSON_DUEDATE_PARAM_NAME)).toInstant(); + String openDateRaw = (String) jsonEvent.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME); + String dueDateRaw = (String) jsonEvent.get(DateManagerConstants.JSON_DUEDATE_PARAM_NAME); + Instant openDate = null; + Instant dueDate = null; boolean errored = false; + + if (StringUtils.isNotBlank(openDateRaw)) { + openDate = userTimeService.parseISODateInUserTimezone(openDateRaw).toInstant(); + } + if (StringUtils.isNotBlank(dueDateRaw)) { + dueDate = userTimeService.parseISODateInUserTimezone(dueDateRaw).toInstant(); + } if (openDate == null) { errored = errors.add(new DateManagerError(DateManagerConstants.JSON_OPENDATE_PARAM_NAME, rb.getString("error.open.date.not.found"), "calendarEvents", toolTitle, idx)); } - else if (dueDate == null) { + if (dueDate == null) { errored = errors.add(new DateManagerError(DateManagerConstants.JSON_DUEDATE_PARAM_NAME, rb.getString("error.due.date.not.found"), "calendarEvents", toolTitle, idx)); } - else if (dueDate.isBefore(openDate)) { + if (openDate != null && dueDate != null && dueDate.isBefore(openDate)) { errored = errors.add(new DateManagerError(DateManagerConstants.JSON_OPENDATE_PARAM_NAME, rb.getString("error.open.date.before.end.date"), "calendarEvents", toolTitle, idx)); } if (errored) { @@ -1154,6 +1188,24 @@ else if (dueDate.isBefore(openDate)) { return calendarValidate; } + /** + * {@inheritDoc} + */ + @Override + public void clearUpdateCalendarLocks(DateManagerValidation calendarValidate) throws Exception { + Calendar c = getCalendar(); + if (c != null) { + try { + for (DateManagerUpdate update : (List)(Object) calendarValidate.getUpdates()) { + CalendarEventEdit edit = (CalendarEventEdit) update.object; + c.cancelEvent(edit); + } + } catch (Exception e) { + log.error("Exception thrown: {}", e.getMessage()); + } + } + } + /** * {@inheritDoc} */ @@ -1260,10 +1312,12 @@ public DateManagerValidation validateForums(String siteId, JSONArray forums) thr Instant openDate = null; Instant dueDate = null; - if (openDateRaw != null && !openDateRaw.isEmpty()) + if (StringUtils.isNotBlank(openDateRaw)) { openDate = userTimeService.parseISODateInUserTimezone(openDateRaw).toInstant(); - if (dueDateRaw != null && !dueDateRaw.isEmpty()) + } + if (StringUtils.isNotBlank(dueDateRaw)) { dueDate = userTimeService.parseISODateInUserTimezone(dueDateRaw).toInstant(); + } String entityType = (String)jsonForum.get(DateManagerConstants.JSON_EXTRAINFO_PARAM_NAME); DateManagerUpdate update; @@ -1315,8 +1369,19 @@ public void updateForums(DateManagerValidation forumValidation) throws Exception if(forum.getAvailabilityRestricted()) { Date openDateTemp = update.openDate != null ? Date.from(update.openDate) : null; Date closeDateTemp = update.dueDate != null ? Date.from(update.dueDate) : null; + if (update.openDate == null && update.dueDate == null) { + forum.setAvailabilityRestricted(false); + } forum.setOpenDate(openDateTemp); forum.setCloseDate(closeDateTemp); + } else { + Date openDateTemp = update.openDate != null ? Date.from(update.openDate) : null; + Date closeDateTemp = update.dueDate != null ? Date.from(update.dueDate) : null; + if (update.openDate != null || update.dueDate != null) { + forum.setAvailabilityRestricted(true); + forum.setOpenDate(openDateTemp); + forum.setCloseDate(closeDateTemp); + } } forumManager.saveDiscussionForum(forum); } else { @@ -1326,6 +1391,17 @@ public void updateForums(DateManagerValidation forumValidation) throws Exception Date closeDateTemp = update.dueDate != null ? Date.from(update.dueDate) : null; topic.setOpenDate(openDateTemp); topic.setCloseDate(closeDateTemp); + if (update.openDate == null && update.dueDate == null) { + topic.setAvailabilityRestricted(false); + } + } else { + Date openDateTemp = update.openDate != null ? Date.from(update.openDate) : null; + Date closeDateTemp = update.dueDate != null ? Date.from(update.dueDate) : null; + if (update.openDate != null || update.dueDate != null) { + topic.setAvailabilityRestricted(true); + topic.setOpenDate(openDateTemp); + topic.setCloseDate(closeDateTemp); + } } forumManager.saveDiscussionForumTopic(topic); } @@ -1395,24 +1471,23 @@ public DateManagerValidation validateAnnouncements(String siteId, JSONArray anno continue; } - Instant openDate = userTimeService.parseISODateInUserTimezone((String)jsonAnnouncement.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME)).toInstant(); - Instant dueDate = userTimeService.parseISODateInUserTimezone((String)jsonAnnouncement.get(DateManagerConstants.JSON_DUEDATE_PARAM_NAME)).toInstant(); + String openDateRaw = (String) jsonAnnouncement.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME); + String dueDateRaw = (String) jsonAnnouncement.get(DateManagerConstants.JSON_DUEDATE_PARAM_NAME); + Instant openDate = null; + Instant dueDate = null; + if (StringUtils.isNotBlank(openDateRaw)) { + openDate = userTimeService.parseISODateInUserTimezone(openDateRaw).toInstant(); + } + + if (StringUtils.isNotBlank(dueDateRaw)) { + dueDate = userTimeService.parseISODateInUserTimezone(dueDateRaw).toInstant(); + } boolean errored = false; - if (openDate == null) { - errored = errors.add(new DateManagerError(DateManagerConstants.JSON_OPENDATE_PARAM_NAME, rb.getString("error.open.date.not.found"), "announcements", toolTitle, idx)); - } - if (dueDate == null) { - errored = errors.add(new DateManagerError(DateManagerConstants.JSON_DUEDATE_PARAM_NAME, rb.getString("error.due.date.not.found"), "announcements", toolTitle, idx)); - } + if (errored) { continue; } - if(StringUtils.isBlank((String)jsonAnnouncement.get(DateManagerConstants.JSON_OPENDATELABEL_PARAM_NAME))) { - openDate = null; - } - if(StringUtils.isBlank((String)jsonAnnouncement.get(DateManagerConstants.JSON_DUEDATELABEL_PARAM_NAME))) { - dueDate = null; - } + if (openDate != null && dueDate != null && !openDate.isBefore(dueDate)) { errors.add(new DateManagerError(DateManagerConstants.JSON_OPENDATE_PARAM_NAME, rb.getString("error.open.date.before.due.date"), "announcements", toolTitle, idx)); continue; @@ -1441,6 +1516,20 @@ public DateManagerValidation validateAnnouncements(String siteId, JSONArray anno return announcementValidate; } + /** + * {@inheritDoc} + */ + @Override + public void clearUpdateAnnouncementLocks(DateManagerValidation announcementValidate) throws Exception { + try { + for (DateManagerUpdate update : (List)(Object) announcementValidate.getUpdates()) { + announcementService.cancelMessage((AnnouncementMessageEdit) update.getObject()); + } + } catch (Exception e) { + log.error("Exception thrown: {}", e.getMessage()); + } + } + /** * {@inheritDoc} */ @@ -1451,8 +1540,16 @@ public void updateAnnouncements(DateManagerValidation announcementValidate) { AnnouncementChannel aChannel = announcementService.getAnnouncementChannel(anncRef); for (DateManagerUpdate update : (List)(Object) announcementValidate.getUpdates()) { AnnouncementMessageEdit msg = (AnnouncementMessageEdit) update.object; - msg.getPropertiesEdit().addProperty(AnnouncementService.RELEASE_DATE, timeService.newTime(Date.from(update.openDate).getTime()).toString()); - msg.getPropertiesEdit().addProperty(AnnouncementService.RETRACT_DATE, timeService.newTime(Date.from(update.dueDate).getTime()).toString()); + if (update.openDate != null) { + msg.getPropertiesEdit().addProperty(AnnouncementService.RELEASE_DATE, timeService.newTime(Date.from(update.openDate).getTime()).toString()); + } else { + msg.getPropertiesEdit().removeProperty(AnnouncementService.RELEASE_DATE); + } + if (update.dueDate != null) { + msg.getPropertiesEdit().addProperty(AnnouncementService.RETRACT_DATE, timeService.newTime(Date.from(update.dueDate).getTime()).toString()); + } else { + msg.getPropertiesEdit().removeProperty(AnnouncementService.RETRACT_DATE); + } aChannel.commitMessage(msg, NotificationService.NOTI_IGNORE); } } catch (Exception e) { @@ -1519,17 +1616,17 @@ public DateManagerValidation validateLessons(String siteId, JSONArray lessons) t try { + String openDateRaw = (String) jsonItem.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME); + Instant openDate = null; Long itemId = (Long)jsonItem.get(DateManagerConstants.JSON_ID_PARAM_NAME); if (itemId == null) { errors.add(new DateManagerError("page", rb.getFormattedMessage("error.item.not.found", new Object[]{rb.getString("tool.lessons.item.name")}), "lessons", toolTitle, idx)); continue; } - Instant openDate = userTimeService.parseISODateInUserTimezone((String)jsonItem.get(DateManagerConstants.JSON_OPENDATE_PARAM_NAME)).toInstant(); - if (openDate == null) { - errors.add(new DateManagerError(DateManagerConstants.JSON_DUEDATE_PARAM_NAME, rb.getString("error.release.date.not.found"), "lessons", toolTitle, idx)); - continue; - } + if (StringUtils.isNotBlank(openDateRaw)) { + openDate = userTimeService.parseISODateInUserTimezone(openDateRaw).toInstant(); + } SimplePage page = simplePageToolDao.getPage(itemId); if (page == null) { @@ -1557,7 +1654,8 @@ public DateManagerValidation validateLessons(String siteId, JSONArray lessons) t public void updateLessons(DateManagerValidation lessonsValidation) throws Exception { for (DateManagerUpdate update : (List)(Object) lessonsValidation.getUpdates()) { SimplePage page = (SimplePage) update.object; - page.setReleaseDate(Date.from(update.openDate)); + Date openDateTemp = update.openDate != null ? Date.from(update.openDate) : null; + page.setReleaseDate(openDateTemp); log.debug("Saving changes on lessons : {}", simplePageToolDao.quickUpdate(page)); } } diff --git a/site-manage/datemanager/tool/src/main/java/org/sakaiproject/datemanager/tool/MainController.java b/site-manage/datemanager/tool/src/main/java/org/sakaiproject/datemanager/tool/MainController.java index 7f9582a3aa4e..41118d80ba17 100644 --- a/site-manage/datemanager/tool/src/main/java/org/sakaiproject/datemanager/tool/MainController.java +++ b/site-manage/datemanager/tool/src/main/java/org/sakaiproject/datemanager/tool/MainController.java @@ -205,6 +205,10 @@ public String showIndex(@RequestParam(required=false) String code, Model model, } jsonResponse = String.format("{\"status\": \"ERROR\", \"errors\": %s}", errorReport.toJSONString()); + // Unlock any locks initiated by Resources, Calendar, and Announcements tools + dateManagerService.clearUpdateResourceLocks(resourcesValidate); + dateManagerService.clearUpdateCalendarLocks(calendarValidate); + dateManagerService.clearUpdateAnnouncementLocks(announcementValidate); } } catch (Exception e) { diff --git a/site-manage/datemanager/tool/src/main/resources/static/js/initDatePicker.js b/site-manage/datemanager/tool/src/main/resources/static/js/initDatePicker.js index d879a68504d6..8f455b32eeda 100644 --- a/site-manage/datemanager/tool/src/main/resources/static/js/initDatePicker.js +++ b/site-manage/datemanager/tool/src/main/resources/static/js/initDatePicker.js @@ -67,24 +67,60 @@ DTMN.attachDatePicker = function (selector, updates, notModified) { var dataTool = $hidden.data('tool'); var dataField = $hidden.data('field'); var dataIdx = $hidden.data('idx'); + var $clearBtn = $(elt).siblings('a'); + + if (dataTool === 'assessments' || dataTool === 'gradebookItems' || dataTool === 'resources' || dataTool === 'forums' || dataTool === 'lessons' + || dataTool === 'announcements' || dataTool === 'assignments' || dataTool === 'signupMeetings' || dataTool === 'calendarEvents') { + $clearBtn.addClass('ui-datepicker-clear-date'); + $clearBtn.show(); + } else { + $clearBtn.hide(); + } + $td.attr('id', 'cell_' + dataTool + '_' + dataField + '_' + dataIdx); + $clearBtn.on('click', function() { + if ($(this).nextAll('input').attr('data-null-date') === 'false') { + // clear date on datepicker + $(this).parent().children('.form-control.datepicker.hasDatepicker').val(''); + // clear date on hidden element + $(this).nextAll('input').val(''); + // force event for hidden element so that clear btn will follow same update logic as backspace/delete in datapicker + $(this).nextAll('input').trigger('change'); + } + }); + $hidden.on('change', function () { const idx = $(this).data('idx'); const field = $(this).data('field'); const tool = $(this).data('tool'); + const fieldVal = $(this).val(); + const dataDateWasNull = $(this).attr('data-null-date'); + const elemDateTime = $(this).siblings('input.datepicker').val(); updates[tool][idx][field] = $(this).val().split('+')[0]; updates[tool][idx][field + '_label'] = $(this).siblings('input.datepicker').val(); + + // set title for date input field + $(this).parent().find('.datepicker').attr('title', elemDateTime); + // Show day of the week in case there is a date selected if ($(this).parent().find('.datepicker').val() !== '') { updates[tool][idx][field + '_day_of_week'] = moment(updates[tool][idx][field]).locale(sakai.locale.userLocale).format('dddd'); $(this).parent().find('.day-of-week').text(updates[tool][idx][field + '_day_of_week']); + // Clear day of the week if date has been cleared + } else { + $(this).parent().find('.day-of-week').text(''); } - if (notModified.includes(tool + idx + field)) { + if (notModified.includes(tool + idx + field) || dataDateWasNull === 'true') { updates[tool][idx].idx = idx; updates[tool + 'Upd'][idx] = updates[tool][idx]; + if (dataDateWasNull === 'true' && fieldVal != '') { + $(this).attr('data-null-date', false); + } else if (dataDateWasNull === 'false' && fieldVal == '') { + $(this).attr('data-null-date', true); + } $('#submit-form-button').prop('disabled', false); } notModified.push(tool + idx + field); @@ -106,9 +142,9 @@ DTMN.attachDatePicker = function (selector, updates, notModified) { iso8601: 'hidden_datepicker_' + DTMN.nextIndex, } }; - // Allow null dates where appropriate - if (dataTool === 'gradebookItems' || dataTool === 'resources' || dataTool === 'forums' || dataTool === 'lessons' || dataTool === 'announcements' || - (dataTool === 'assessments' && (dataField === 'accept_until' || dataField === 'due_date' || dataField === 'feedback_end' || dataField === 'feedback_start'))) { + // Allow null dates during editing then enforce rules for required fields serverside + if (dataTool === 'assessments' || dataTool === 'gradebookItems' || dataTool === 'resources' || dataTool === 'forums' || dataTool === 'lessons' + || dataTool === 'announcements' || dataTool === 'assignments' || dataTool === 'signupMeetings' || dataTool === 'calendarEvents') { datepickerOpts.allowEmptyDate = true; } @@ -120,22 +156,28 @@ DTMN.attachDatePicker = function (selector, updates, notModified) { if ($hidden.val() !== '') datepickerOpts.val = $hidden.val(); localDatePicker(datepickerOpts); + //reposition the clear button between the datepicker and datepicker trigger button + $(elt).after($clearBtn); + // Disable accept_until date input if no late submissions (assessments) allowed if (dataTool === 'assessments' && dataField === 'accept_until') { var disabled = !updates[dataTool][dataIdx].late_handling; $(elt).prop('disabled', disabled); $td.find('.ui-datepicker-trigger').prop('disabled', disabled); + $td.find('.ui-datepicker-clear-date > i').attr('disabled',disabled); } // Disable feedback start and end date inputs if feedback on date not used (assessments) if (dataTool === 'assessments' && (dataField === 'feedback_start' || dataField === 'feedback_end')) { var disabled = !updates[dataTool][dataIdx].feedback_by_date; $(elt).prop('disabled', disabled); $td.find('.ui-datepicker-trigger').prop('disabled', disabled); + $td.find('.ui-datepicker-clear-date > i').attr('disabled',disabled); } if (dataTool === 'forums' && (dataField === 'open_date' || dataField === 'due_date')) { var disabled = !updates[dataTool][dataIdx].restricted; $(elt).prop('disabled', disabled); $td.find('.ui-datepicker-trigger').prop('disabled', disabled); + $td.find('.ui-datepicker-clear-date > i').attr('disabled',disabled); } }); }; diff --git a/site-manage/datemanager/tool/src/main/webapp/WEB-INF/templates/tool_fragment.html b/site-manage/datemanager/tool/src/main/webapp/WEB-INF/templates/tool_fragment.html index ba9f843f985c..45c4c92ad2ee 100644 --- a/site-manage/datemanager/tool/src/main/webapp/WEB-INF/templates/tool_fragment.html +++ b/site-manage/datemanager/tool/src/main/webapp/WEB-INF/templates/tool_fragment.html @@ -7,39 +7,39 @@ Title - Open Date - Available Date - Start Date + Open Date + Available Date + Start Date Show From Date - Start Date + Start Date Open Date Start Date Hide Until Date - Due Date + Due Date Due Date - End Date + End Date Due Date Show Until Date - End Date + End Date Close Date End Date - Accept Until Date + Accept Until Date Late Submission Deadline Show Feedback On - Sign-up Begins Date + Sign-up Begins Date Show Feedback Until - Sign-up Ends Date + Sign-up Ends Date @@ -58,7 +58,11 @@
- + + + +
@@ -69,7 +73,11 @@
- + + + +
@@ -86,7 +94,11 @@
- + + + +
@@ -96,7 +108,11 @@
- + + + +
@@ -104,7 +120,11 @@
- + + + +
@@ -116,7 +136,11 @@
- + + + +
@@ -124,7 +148,11 @@
- + + + +