Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r092ede3b8b3828ffa688c4db18c5d535e3364b98 -r225d293907a5e2976e367ee3aa790239bad38699 Binary files differ Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILearnerProgressDAO.java =================================================================== diff -u -r14c33274b785517e5e3f6a7642dc7c6752a34411 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILearnerProgressDAO.java (.../ILearnerProgressDAO.java) (revision 14c33274b785517e5e3f6a7642dc7c6752a34411) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/ILearnerProgressDAO.java (.../ILearnerProgressDAO.java) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -201,4 +201,7 @@ * Get the last attempt ID for the given learner and lesson. */ Integer getLearnerProgressArchiveMaxAttemptID(Integer userId, Long lessonId); + + /** Get the number of learners who are in a particular activity at the moment */ + Integer getNumUsersCurrentActivity(Activity activity); } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LearnerProgressDAO.java =================================================================== diff -u -r29f0bed68ca75b5ea332c5e9d99084901ee989f9 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LearnerProgressDAO.java (.../LearnerProgressDAO.java) (revision 29f0bed68ca75b5ea332c5e9d99084901ee989f9) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/dao/hibernate/LearnerProgressDAO.java (.../LearnerProgressDAO.java) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -80,6 +80,9 @@ + "from LearnerProgress prog WHERE prog.currentActivity.activityId IN (:activityIds) " + "GROUP BY prog.currentActivity.activityId"; + private final static String COUNT_SINGLE_CURRENT_ACTIVITY = "select count(*) from LearnerProgress prog " + + "WHERE prog.currentActivity.activityId = :activityId "; + private final static String LOAD_PROGRESS_BY_LESSON = "from LearnerProgress p " + " where p.lesson.id = :lessonId order by p.user.lastName, p.user.firstName, p.user.userId"; @@ -345,7 +348,16 @@ return result; } + @SuppressWarnings("unchecked") @Override + public Integer getNumUsersCurrentActivity(Activity activity) { + Object value = getSession().createQuery(LearnerProgressDAO.COUNT_SINGLE_CURRENT_ACTIVITY) + .setLong("activityId", activity.getActivityId().longValue()).uniqueResult(); + return new Integer(((Number) value).intValue()); + } + + + @Override public Integer getLearnerProgressArchiveMaxAttemptID(Integer userId, Long lessonId) { Object value = getSession().createQuery(LearnerProgressDAO.FIND_PROGRESS_ARCHIVE_MAX_ATTEMPT) .setInteger("learnerId", userId).setLong("lessonId", lessonId).uniqueResult(); Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java =================================================================== diff -u -r1aff6aeac19473c0089c0f3ff578a183beb92555 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision 1aff6aeac19473c0089c0f3ff578a183beb92555) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/ILessonService.java (.../ILessonService.java) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -340,6 +340,9 @@ */ Integer getCountLearnersHaveAttemptedActivity(Activity activity) throws LessonServiceException; + /** Gets the count of the users who are currently in an activity */ + Integer getCountLearnersInCurrentActivity(Activity activity); + /** * Returns map of lessons in an organisation for a particular learner or staff user. * Index: lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java =================================================================== diff -u -r1aff6aeac19473c0089c0f3ff578a183beb92555 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision 1aff6aeac19473c0089c0f3ff578a183beb92555) +++ lams_common/src/java/org/lamsfoundation/lams/lesson/service/LessonService.java (.../LessonService.java) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -614,6 +614,9 @@ return learnerProgressDAO.getNumUsersAttemptedActivity(activity); } + public Integer getCountLearnersInCurrentActivity(Activity activity){ + return learnerProgressDAO.getNumUsersCurrentActivity(activity); + } @Override public Map getLessonsByOrgAndUserWithCompletedFlag(Integer userId, Integer orgId, Integer userRole) { Index: lams_learning/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r0b8d119797d69e0add835267e618765b5c1dc069 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 0b8d119797d69e0add835267e618765b5c1dc069) +++ lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -94,8 +94,6 @@ label.submit.button =Submit label.learner.progress.review.activity =Review activity label.schedule.gate.reach =You have reached the gate on -label.schedule.gate.offset.1 =The gate will only be opened -label.schedule.gate.offset.2 =after. label.days =days label.hours =hours label.minutes =minutes Index: lams_learning/conf/language/lams/ApplicationResources_en_AU.properties =================================================================== diff -u -r0b8d119797d69e0add835267e618765b5c1dc069 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_learning/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 0b8d119797d69e0add835267e618765b5c1dc069) +++ lams_learning/conf/language/lams/ApplicationResources_en_AU.properties (.../ApplicationResources_en_AU.properties) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -94,8 +94,6 @@ label.submit.button =Submit label.learner.progress.review.activity =Review activity label.schedule.gate.reach =You have reached the gate on -label.schedule.gate.offset.1 =The gate will only be opened -label.schedule.gate.offset.2 =after. label.days =days label.hours =hours label.minutes =minutes Index: lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/GateAction.java =================================================================== diff -u -rfd1c6c450376476c752e6be5cb6048a2e370bd42 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/GateAction.java (.../GateAction.java) (revision fd1c6c450376476c752e6be5cb6048a2e370bd42) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/GateAction.java (.../GateAction.java) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -197,10 +197,13 @@ Calendar startingTime = new GregorianCalendar(TimeZone.getDefault()); startingTime.setTime(reachTime); startingTime.add(Calendar.MINUTE, scheduleGate.getGateStartTimeOffset().intValue()); + gateForm.set("startingTime", startingTime.getTime()); long diff = startingTime.getTimeInMillis() - new Date().getTime(); long remainTime = diff / 1000; gateForm.set("remainTime", remainTime); + gateForm.set("endingTime", null); } else { + gateForm.set("startOffset", null); gateForm.set("reachDate", null); Calendar startingTime = new GregorianCalendar(TimeZone.getDefault()); startingTime.setTime(lesson.getStartDateTime()); Index: lams_learning/web/gate/scheduleGateContent.jsp =================================================================== diff -u -r70254a2e4bb9d1d45558a209ce1eca752b8db5f3 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_learning/web/gate/scheduleGateContent.jsp (.../scheduleGateContent.jsp) (revision 70254a2e4bb9d1d45558a209ce1eca752b8db5f3) +++ lams_learning/web/gate/scheduleGateContent.jsp (.../scheduleGateContent.jsp) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -35,12 +35,8 @@

- +   -
- - -

@@ -61,6 +57,6 @@ Index: lams_monitoring/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r621f712588dcf37f4bc18add622143483cdfc267 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_monitoring/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 621f712588dcf37f4bc18add622143483cdfc267) +++ lams_monitoring/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -422,5 +422,5 @@ button.schedule.disable.tooltip =Schedule lesson to be disabled at a future time button.disable.now =Disable now button.disable.now.tooltip =Disable the lesson immediately - +label.reschedule=Reschedule #======= End labels: Exported 401 labels for en AU ===== Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java =================================================================== diff -u -r621f712588dcf37f4bc18add622143483cdfc267 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java (.../IMonitoringService.java) (revision 621f712588dcf37f4bc18add622143483cdfc267) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java (.../IMonitoringService.java) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -367,6 +367,9 @@ */ GateActivity closeGate(Long gateId); + /** Update the schedule gate date/time */ + GateActivity scheduleGate(Long gateId, Date schedulingDatetime, Integer userId); + /** * Returns users by search type criteria. It's sorted by first and last user names. * Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java =================================================================== diff -u -r621f712588dcf37f4bc18add622143483cdfc267 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision 621f712588dcf37f4bc18add622143483cdfc267) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java (.../MonitoringService.java) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -834,6 +834,77 @@ } @Override + public GateActivity scheduleGate(Long gateId, Date schedulingDatetime, Integer userId) { + if (MonitoringService.log.isDebugEnabled()) { + MonitoringService.log.debug("Setting gate schedule for gate " + gateId + "to " + schedulingDatetime); + } + + User user = (User) baseDAO.find(User.class, userId); + TimeZone userTimeZone = TimeZone.getTimeZone(user.getTimeZone()); + Date tzSchedulingDatetime = DateUtil.convertFromTimeZoneToDefault(userTimeZone, schedulingDatetime); + + GateActivity gateActivity = (GateActivity) activityDAO.getActivityByActivityId(gateId); + if (gateActivity != null && gateActivity.isScheduleGate()) { + if (tzSchedulingDatetime.getTime() < System.currentTimeMillis()) { + // too late! Time already passed + openGate(gateId); + } else { + + ScheduleGateActivity gate = (ScheduleGateActivity) activityDAO + .getActivityByActivityId(gateActivity.getActivityId()); + + // work out new offset in minutes from lesson start time to the given date + Lesson lesson = learnerService.getLessonByActivity(gate); + Date lessonStartingTime = lesson.getStartDateTime(); + if (lessonStartingTime != null) { + // Should never be null, so just skip that case. If it was null how did the initial trigger get set up? + long offset = (tzSchedulingDatetime.getTime() - lessonStartingTime.getTime()) / 60000; + if (offset > 0) { + + String triggerName = "openGateTrigger:" + gate.getActivityId(); + Trigger openGateTrigger = null; + boolean alreadyScheduled = false; + + try { + openGateTrigger = scheduler.getTrigger(TriggerKey.triggerKey(triggerName)); + alreadyScheduled = openGateTrigger != null; + } catch (SchedulerException e) { + MonitoringService.log.error("Error while fetching Quartz trigger \"" + triggerName + "\"", + e); + } + + try { + if (alreadyScheduled) { + openGateTrigger = openGateTrigger.getTriggerBuilder().startAt(tzSchedulingDatetime) + .build(); + scheduler.rescheduleJob(openGateTrigger.getKey(), openGateTrigger); + } else { + // setup the message for scheduling job + JobDetail openScheduleGateJob = JobBuilder.newJob(OpenScheduleGateJob.class) + .withIdentity("openGate:" + gate.getActivityId()) + .withDescription(gate.getTitle() + ":" + lesson.getLessonName()) + .usingJobData("gateId", gate.getActivityId()).build(); + openGateTrigger = TriggerBuilder.newTrigger() + .withIdentity("openGateTrigger:" + gate.getActivityId()) + .startAt(tzSchedulingDatetime).build(); + // start the scheduling job + scheduler.scheduleJob(openScheduleGateJob, openGateTrigger); + } + } catch (SchedulerException e) { + MonitoringService.log.error( + "Error while setting up gate open trigger. Trigger name \"" + triggerName + "\"", + e); + } + + gate.setGateStartTimeOffset(offset); + activityDAO.update(gate); + } + } + } + } + return gateActivity; + } + public void finishLesson(long lessonId, Integer userId) { securityService.isLessonMonitor(lessonId, userId, "finish lesson", true); Lesson requestedLesson = lessonDAO.getLesson(new Long(lessonId)); Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/GateAction.java =================================================================== diff -u -rae5e9eacbfbf13097410637b6e8990dfb909177a -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/GateAction.java (.../GateAction.java) (revision ae5e9eacbfbf13097410637b6e8990dfb909177a) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/GateAction.java (.../GateAction.java) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -24,6 +24,9 @@ package org.lamsfoundation.lams.monitoring.web; import java.io.IOException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collection; import java.util.GregorianCalendar; @@ -36,6 +39,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import org.apache.commons.lang.StringUtils; import org.apache.struts.action.ActionForm; @@ -52,8 +56,10 @@ import org.lamsfoundation.lams.monitoring.service.MonitoringServiceException; import org.lamsfoundation.lams.monitoring.service.MonitoringServiceProxy; import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.action.LamsDispatchAction; +import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; /** @@ -105,7 +111,9 @@ private static final String ACTIVITY_FORM_FIELD = "activityId"; private static final String TOTAL_LEARNERS_FORM_FIELD = "totalLearners"; private static final String USER_ID = "userId"; + private static final String SCHEDULE_DATE = "scheduleDate"; + private static final DateFormat SCHEDULING_DATETIME_FORMAT = new SimpleDateFormat("MM/dd/yy HH:mm"); // --------------------------------------------------------------------- // Struts Dispatch Method // --------------------------------------------------------------------- @@ -229,9 +237,30 @@ return findViewByGateType(mapping, gateForm, gate); } + public ActionForward scheduleGate(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException, ParseException { + monitoringService = MonitoringServiceProxy.getMonitoringService(getServlet().getServletContext()); + + DynaActionForm gateForm = (DynaActionForm) form; + Long gateId = (Long) gateForm.get(GateAction.ACTIVITY_FORM_FIELD); + String dateAsString = (String) gateForm.get(GateAction.SCHEDULE_DATE); + GateActivity gate = null; + if (dateAsString != null && dateAsString.trim().length() > 0) { + gate = monitoringService.scheduleGate(gateId, SCHEDULING_DATETIME_FORMAT.parse(dateAsString), getUserId()); + } else { + gate = (GateActivity) monitoringService.getActivityById(gateId); + } + return findViewByGateType(mapping, gateForm, gate); + } // --------------------------------------------------------------------- // Helper Methods // --------------------------------------------------------------------- + private Integer getUserId() { + HttpSession ss = SessionManager.getSession(); + UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); + return user != null ? user.getUserID() : null; + } + /** * Dispatch view the according to the gate type. * @@ -255,6 +284,7 @@ gateForm.set("forbiddenLearnerList", null); gateForm.set("startingTime", null); gateForm.set("endingTime", null); + gateForm.set(GateAction.SCHEDULE_DATE, null); gateForm.set("gate", gate); @@ -268,11 +298,11 @@ // dispatch the view according to the type of the gate. if (gate.isSynchGate()) { - Integer waitingLearnerCount = lessonService.getCountLearnersHaveAttemptedActivity(gate); + Integer waitingLearnerCount = lessonService.getCountLearnersInCurrentActivity(gate); gateForm.set("waitingLearners", waitingLearnerCount); return mapping.findForward(GateAction.VIEW_SYNCH_GATE); } else if (gate.isScheduleGate()) { - Integer waitingLearnerCount = lessonService.getCountLearnersHaveAttemptedActivity(gate); + Integer waitingLearnerCount = lessonService.getCountLearnersInCurrentActivity(gate); gateForm.set("waitingLearners", waitingLearnerCount); return viewScheduleGate(mapping, gateForm, (ScheduleGateActivity) gate); } else if (gate.isPermissionGate() || gate.isSystemGate() || gate.isConditionGate()) { @@ -317,6 +347,7 @@ if (Boolean.TRUE.equals(scheduleGate.getGateActivityCompletionBased())) { gateForm.set("activityCompletionBased", true); } else { + gateForm.set("activityCompletionBased", false); learnerService = MonitoringServiceProxy.getLearnerService(getServlet().getServletContext()); Lesson lesson = learnerService.getLessonByActivity(scheduleGate); Calendar startingTime = new GregorianCalendar(TimeZone.getDefault()); Index: lams_monitoring/web/WEB-INF/struts-config.xml =================================================================== diff -u -r41771fed1bd0652923d05a84de584769dcfe0ef7 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_monitoring/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision 41771fed1bd0652923d05a84de584769dcfe0ef7) +++ lams_monitoring/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -25,6 +25,7 @@ + Index: lams_monitoring/web/gate/gateStatus.jsp =================================================================== diff -u -rff491b651076f76b819a2555afd5fb02d61fb0be -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_monitoring/web/gate/gateStatus.jsp (.../gateStatus.jsp) (revision ff491b651076f76b819a2555afd5fb02d61fb0be) +++ lams_monitoring/web/gate/gateStatus.jsp (.../gateStatus.jsp) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -3,7 +3,7 @@ -

+

Index: lams_monitoring/web/gate/scheduleGateContent.jsp =================================================================== diff -u -ra0aafa6930f1fd155293fe0955b2b6ee3d82f6b2 -r225d293907a5e2976e367ee3aa790239bad38699 --- lams_monitoring/web/gate/scheduleGateContent.jsp (.../scheduleGateContent.jsp) (revision a0aafa6930f1fd155293fe0955b2b6ee3d82f6b2) +++ lams_monitoring/web/gate/scheduleGateContent.jsp (.../scheduleGateContent.jsp) (revision 225d293907a5e2976e367ee3aa790239bad38699) @@ -26,6 +26,56 @@ <%@ taglib uri="tags-fmt" prefix="fmt" %> <%@ taglib uri="tags-lams" prefix="lams" %> + + + + + + + + + @@ -37,11 +87,27 @@

+ + + + +
+ + + + + <%-- padding keeps the inputs the same height as the buttons. No flicking when shown/hidden --%> + + +
+

+ +