Index: lams_common/src/java/org/lamsfoundation/lams/events/Event.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/events/Event.java,v diff -u -r1.5.2.4 -r1.5.2.5 --- lams_common/src/java/org/lamsfoundation/lams/events/Event.java 5 May 2016 08:10:57 -0000 1.5.2.4 +++ lams_common/src/java/org/lamsfoundation/lams/events/Event.java 1 Jun 2017 07:30:57 -0000 1.5.2.5 @@ -68,7 +68,7 @@ } /** - * Standard constructor used by EventNotificationService. + * Basic constructor used by EventNotificationService. * * @param scope * scope of the event @@ -99,9 +99,42 @@ this.htmlFormat = isHtmlContentType; } + /** + * Constructor used by EventNotificationService when the event is for resending (after an initial send now failure) + * + * @param scope + * scope of the event + * @param name + * name of the event + * @param eventSessionId + * session ID of the event + * @param defaultSubject + * subject of the message to send + * @param defaultMessage + * body of the message to send + * @param failTime + * @throws InvalidParameterException + * if scope is null or name is blank + */ + public Event(String scope, String name, Long sessionId, String subject, String message, boolean isHtmlContentType, Date failTime) throws InvalidParameterException { + if (scope == null) { + throw new InvalidParameterException("Event scope can not be null."); + } + if (StringUtils.isBlank(name)) { + throw new InvalidParameterException("Event name can not be blank."); + } + this.scope = scope; + this.name = name; + this.eventSessionId = sessionId; + this.subject = subject; + this.message = message; + this.htmlFormat = isHtmlContentType; + this.failTime = failTime; + } + @Override public Object clone() { - return new Event(scope, name, eventSessionId, subject, message, htmlFormat); + return new Event(scope, name, eventSessionId, subject, message, htmlFormat, failTime); } /** Index: lams_common/src/java/org/lamsfoundation/lams/events/EventNotificationService.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/events/EventNotificationService.java,v diff -u -r1.7.2.15 -r1.7.2.16 --- lams_common/src/java/org/lamsfoundation/lams/events/EventNotificationService.java 28 Mar 2017 12:05:25 -0000 1.7.2.15 +++ lams_common/src/java/org/lamsfoundation/lams/events/EventNotificationService.java 1 Jun 2017 07:30:57 -0000 1.7.2.16 @@ -5,6 +5,7 @@ import java.util.Date; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; @@ -114,6 +115,23 @@ } @Override + public void notifyLessonMonitors(Long lessonId, String subject, String message, boolean isHtmlFormat) { + Map monitoringUsers = lessonService.getUsersWithLessonParticipation(lessonId, "MONITOR", null, null, null, true); + if (monitoringUsers.isEmpty()) { + return; + } + + ArrayList monitoringUsersIds = new ArrayList(); + for ( Map.Entry entry : monitoringUsers.entrySet() ) { + if ( entry.getValue() ) + monitoringUsersIds.add(entry.getKey().getUserId()); + } + + sendMessage(null, monitoringUsersIds.toArray(new Integer[monitoringUsersIds.size()]), IEventNotificationService.DELIVERY_METHOD_MAIL, subject, message, + isHtmlFormat); + } + + @Override public void notifyLessonMonitors(Long sessionId, String message, boolean isHtmlFormat) { List monitoringUsers = lessonService.getMonitorsByToolSessionId(sessionId); if (monitoringUsers.isEmpty()) { @@ -159,6 +177,7 @@ * whether the message is of HTML content-type or plain text */ public void notifyUser(Subscription subscription, String subject, String message, boolean isHtmlFormat) { + log.debug("EventNotificationService notifyUser "+this.toString()); subscription.setLastOperationMessage( subscription.getDeliveryMethod().send(null, subscription.getUserId(), subject, message, isHtmlFormat)); } @@ -200,9 +219,8 @@ EventNotificationService.log.error("Error occured while sending message: " + result); Event event = new Event(IEventNotificationService.SINGLE_MESSAGE_SCOPE, - String.valueOf(System.currentTimeMillis()), null, subject, message, isHtmlFormat); + String.valueOf(System.currentTimeMillis()), null, subject, message, isHtmlFormat, new Date()); subscribe(event, toUserId, deliveryMethod); - event.setFailTime(new Date()); eventDAO.insertOrUpdate(event); return false; } @@ -221,20 +239,16 @@ new Thread(() -> { try { HibernateSessionManager.openSession(); - - Event event = null; for (Integer id : toUserIds) { String result = deliveryMethod.send(fromUserId, id, subject, message, isHtmlFormat); if (result != null) { - event = new Event(IEventNotificationService.SINGLE_MESSAGE_SCOPE, - String.valueOf(System.currentTimeMillis()), null, subject, message, isHtmlFormat); + Event event = new Event(IEventNotificationService.SINGLE_MESSAGE_SCOPE, + String.valueOf(System.currentTimeMillis()), null, subject, message, + isHtmlFormat, new Date()); subscribe(event, id, deliveryMethod); + log.debug("Set up new event "+event.getUid()+":"+event.getName()+" number of subscriptions "+event.getSubscriptions().size()); } } - if (event != null) { - event.setFailTime(new Date()); - eventDAO.insertOrUpdate(event); - } } finally { HibernateSessionManager.closeSession(); } @@ -341,7 +355,7 @@ while (subscriptionIterator.hasNext()) { Subscription subscription = subscriptionIterator.next(); notifyUser(subscription, subjectToSend, messageToSend, event.isHtmlFormat()); - if (subscription.getDeliveryMethod().lastOperationFailed(subscription)) { + if (! subscription.getDeliveryMethod().lastOperationFailed(subscription)) { if (event.getFailTime() != null) { subscriptionIterator.remove(); } @@ -353,6 +367,7 @@ } } if (event.getSubscriptions().isEmpty()) { + log.debug("Deleting event "+event.getUid()+" "+event.getFailTime()); eventDAO.delete(event); } else { eventDAO.insertOrUpdate(event); Index: lams_common/src/java/org/lamsfoundation/lams/events/IEventNotificationService.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/events/IEventNotificationService.java,v diff -u -r1.4.2.7 -r1.4.2.8 --- lams_common/src/java/org/lamsfoundation/lams/events/IEventNotificationService.java 5 May 2016 08:10:57 -0000 1.4.2.7 +++ lams_common/src/java/org/lamsfoundation/lams/events/IEventNotificationService.java 1 Jun 2017 07:30:57 -0000 1.4.2.8 @@ -127,6 +127,19 @@ */ void notifyLessonMonitors(Long sessionId, String message, boolean isHtmlFormat); + /** + * Notify lesson monitors with the specified message and subject + * + * @param lessonId + * tool session to which monitors belong + * @param subject + * subject to be sent + * @param message + * message to be sent + * @isHtmlFormat whether email is required to of HTML format + */ + void notifyLessonMonitors(Long lessonId, String subject, String message, boolean isHtmlFormat); + void resendMessages(); /** Index: lams_common/src/java/org/lamsfoundation/lams/util/hibernate/HibernateSessionManager.java =================================================================== RCS file: /usr/local/cvsroot/lams_common/src/java/org/lamsfoundation/lams/util/hibernate/Attic/HibernateSessionManager.java,v diff -u -r1.1.2.4 -r1.1.2.5 --- lams_common/src/java/org/lamsfoundation/lams/util/hibernate/HibernateSessionManager.java 8 Jan 2017 15:48:01 -0000 1.1.2.4 +++ lams_common/src/java/org/lamsfoundation/lams/util/hibernate/HibernateSessionManager.java 1 Jun 2017 07:30:57 -0000 1.1.2.5 @@ -1,5 +1,6 @@ package org.lamsfoundation.lams.util.hibernate; +import org.apache.log4j.Logger; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.context.internal.ManagedSessionContext; @@ -17,6 +18,7 @@ public class HibernateSessionManager { private static SessionFactory sessionFactory; + // private static Logger log = Logger.getLogger(HibernateSessionManager.class); /** * Makes sure that an open Hibernate session is bound to current thread. */ @@ -31,19 +33,25 @@ TransactionSynchronizationManager.unbindResourceIfPossible(sessionFactory); session = sessionFactory.getCurrentSession(); } +// log.debug("Opened new session "+session.toString()); +// } else { +// log.debug("Bound to open session "+session.toString()); +// } // binding to Context is not enough // an open session needs to be also manually bound to current thread SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); if (sessionHolder == null) { sessionHolder = new SessionHolder(session); TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder); +// log.debug("Linked to transaction "+session.getTransaction()); } } public static void closeSession() { Session session = HibernateSessionManager.getSessionFactory().getCurrentSession(); if (session.isOpen()) { +// log.debug("Closing session transaction "+session.getTransaction()); session.close(); } } Index: lams_monitoring/conf/language/lams/ApplicationResources.properties =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/conf/language/lams/ApplicationResources.properties,v diff -u -r1.66.2.33 -r1.66.2.34 --- lams_monitoring/conf/language/lams/ApplicationResources.properties 10 May 2017 07:14:23 -0000 1.66.2.33 +++ lams_monitoring/conf/language/lams/ApplicationResources.properties 1 Jun 2017 07:31:30 -0000 1.66.2.34 @@ -375,5 +375,33 @@ tour.gradebook.show.dates.content=Show/Hide some of the date columns in the grids to make it easier to read. tour.gradebook.marks.chart=Marks Chart tour.histogram.help.content=Click on a bar in the graph and then use your mouse wheel to zoom in and out of the graph. Once you zoom in, the grey selection in the bottom graph can be dragged left or right to show a different set of marks. - +lesson.progress.email=Progress Email +progress.email.send=Send Email Now +progress.email.configure=Automatic Email Settings +progress.email.subject=Lesson Progress: {0} +progress.email.sent.success=[0] email(s) sent. +export.dateheader =Exported on: +progress.email.send.now.question=Send the current user progress by email to yourself only now? +progress.email.send.failed=Some problems occurred while sending emails. Please, contact your system administrator. +progress.email.select.date.first=Please select a date first. +progress.email.enter.two.dates.first=Please add your first two dates and then a list can be generated. +progress.email.would.you.like.to.generate=Would you like to generate a list of dates based on your first two dates? You can then select from the list. +progress.email.how.many.dates.to.generate=How many dates would you like generated? +progress.email.will.be.sent.on=Emails will be sent on: +progress.email.add.date=Add Date +progress.email.generate.date.list=Generate Date List +progress.email.select.date=Select Date: +progress.email.title=Email Progress Report +progress.email.heading.number.learners=# of Learners +progress.email.heading.overall.progress=Overall learner's progress +label.gate.title=Gate +label.unknown=Unknown +progress.email.sent.automatically=Email sent by automatically by LAMS on scheduled request +label.activity=Activity +label.status=Status +tour.progress.email.send.title=Send Learner Progress Email +tour.progress.email.send.content=Send an email with a summary of the learner progress to yourself immediately. +tour.progress.email.configure.title=Configure Learner Progress Email Sending +tour.progress.email.confure.content=Set up the dates to automatically send emails with a summary of learner progress to all monitors for this lesson. +error.date.in.past=Selected date is in the past. #======= End labels: Exported 352 labels for en AU ===== Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/monitoringApplicationContext.xml =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/monitoringApplicationContext.xml,v diff -u -r1.36.2.14 -r1.36.2.15 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/monitoringApplicationContext.xml 19 Dec 2016 16:08:07 -0000 1.36.2.14 +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/monitoringApplicationContext.xml 1 Jun 2017 07:31:31 -0000 1.36.2.15 @@ -78,6 +78,8 @@ PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + Fisheye: Tag 1.1 refers to a dead (removed) revision in file `lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/dto/EmailProgressActivityDTO.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/quartz/job/EmailProgressMessageJob.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/quartz/job/EmailScheduleMessageJob.java =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/quartz/job/EmailScheduleMessageJob.java,v diff -u -r1.4.2.4 -r1.4.2.5 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/quartz/job/EmailScheduleMessageJob.java 30 Jan 2017 04:13:24 -0000 1.4.2.4 +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/quartz/job/EmailScheduleMessageJob.java 1 Jun 2017 07:31:31 -0000 1.4.2.5 @@ -33,9 +33,6 @@ import org.lamsfoundation.lams.web.util.AttributeNames; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; -import org.quartz.SchedulerContext; -import org.quartz.SchedulerException; -import org.springframework.context.ApplicationContext; /** * Email messages at the specified date. List of recipients is being constructed real time based on specified search @@ -83,16 +80,4 @@ } } - private IEventNotificationService getEventNotificationService(JobExecutionContext context) - throws JobExecutionException { - try { - final String CONTEXT_NAME = "context.central"; - - SchedulerContext sc = context.getScheduler().getContext(); - ApplicationContext cxt = (ApplicationContext) sc.get(CONTEXT_NAME); - return (IEventNotificationService) cxt.getBean("eventNotificationService"); - } catch (SchedulerException e) { - throw new JobExecutionException("Failed look up the Scheduler" + e.toString()); - } - } } \ No newline at end of file Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/quartz/job/MonitoringJob.java =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/quartz/job/MonitoringJob.java,v diff -u -r1.5.8.2 -r1.5.8.3 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/quartz/job/MonitoringJob.java 11 May 2016 07:14:45 -0000 1.5.8.2 +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/quartz/job/MonitoringJob.java 1 Jun 2017 07:31:31 -0000 1.5.8.3 @@ -24,6 +24,7 @@ package org.lamsfoundation.lams.monitoring.quartz.job; +import org.lamsfoundation.lams.events.IEventNotificationService; import org.lamsfoundation.lams.monitoring.service.IMonitoringService; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; @@ -33,23 +34,31 @@ import org.springframework.scheduling.quartz.QuartzJobBean; /** - * All Quartz Job Bean super classes in monitoring. It provides a simple helper method to get monitoringService. - * + * All Quartz Job Bean super classes in monitoring. It provides a simple helper methods to get monitoringService, eventNotificationService. * @author Steve.Ni - * - * @version $Revision$ */ public abstract class MonitoringJob extends QuartzJobBean { private static final String CONTEXT_NAME = "context.central"; - private static final String SERVICE_NAME = "monitoringService"; + private static final String MONITORING_SERVICE_NAME = "monitoringService"; + private static final String EVENT_SERVICE_NAME = "eventNotificationService"; - protected IMonitoringService getMonitoringService(JobExecutionContext context) throws JobExecutionException { + protected Object getService(JobExecutionContext context, String serviceName) throws JobExecutionException { try { SchedulerContext sc = context.getScheduler().getContext(); ApplicationContext cxt = (ApplicationContext) sc.get(MonitoringJob.CONTEXT_NAME); - return (IMonitoringService) cxt.getBean(MonitoringJob.SERVICE_NAME); + return cxt.getBean(serviceName); } catch (SchedulerException e) { - throw new JobExecutionException("Failed look up the Scheduler" + e.toString()); + throw new JobExecutionException("Failed look up the " + serviceName + " " + e.toString()); } } + + protected IMonitoringService getMonitoringService(JobExecutionContext context) throws JobExecutionException { + return (IMonitoringService) getService(context, MonitoringJob.MONITORING_SERVICE_NAME); + } + + protected IEventNotificationService getEventNotificationService(JobExecutionContext context) + throws JobExecutionException { + return (IEventNotificationService) getService(context, MonitoringJob.EVENT_SERVICE_NAME); + } + } Fisheye: Tag 1.1 refers to a dead (removed) revision in file `lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/EmailProgressActivitiesProcessor.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java,v diff -u -r1.110.2.20 -r1.110.2.21 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java 23 Mar 2017 18:58:19 -0000 1.110.2.20 +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/IMonitoringService.java 1 Jun 2017 07:31:31 -0000 1.110.2.21 @@ -651,6 +651,10 @@ void removeLearnerContent(Long lessonId, Integer learnerId); + + /** Generate an email containing the progress details for individual activities in a lesson. + * @return String[] {subject, email body} */ + String[] generateLessonProgressEmail(Long lessonId, Integer userId); /** * Get list of users who completed the given lesson. Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java,v diff -u -r1.195.2.42 -r1.195.2.43 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java 23 Mar 2017 18:58:19 -0000 1.195.2.42 +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/service/MonitoringService.java 1 Jun 2017 07:31:31 -0000 1.195.2.43 @@ -35,6 +35,7 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.SortedSet; @@ -84,6 +85,7 @@ import org.lamsfoundation.lams.logevent.service.ILogEventService; import org.lamsfoundation.lams.monitoring.MonitoringConstants; import org.lamsfoundation.lams.monitoring.dto.ContributeActivityDTO; +import org.lamsfoundation.lams.monitoring.dto.EmailProgressActivityDTO; import org.lamsfoundation.lams.monitoring.quartz.job.CloseScheduleGateJob; import org.lamsfoundation.lams.monitoring.quartz.job.FinishScheduleLessonJob; import org.lamsfoundation.lams.monitoring.quartz.job.OpenScheduleGateJob; @@ -106,6 +108,7 @@ import org.lamsfoundation.lams.usermanagement.util.LastNameAlphabeticComparator; import org.lamsfoundation.lams.util.DateUtil; import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.NumberUtil; import org.lamsfoundation.lams.util.audit.AuditService; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; @@ -2255,7 +2258,121 @@ } } + @SuppressWarnings("unchecked") + private EmailProgressActivitiesProcessor getEmailProgressActivitiesProcessor(Long lessonId) { + + // TODO custom SQL to get the ids, number of users & marks in one go + Lesson lesson = lessonService.getLesson(lessonId); + LearningDesign ld = lesson.getLearningDesign(); + Long[] activityIds = new Long[ld.getActivities().size()]; + int i=0; + Iterator activityIterator = (Iterator) ld.getActivities().iterator(); + while ( activityIterator.hasNext() ) { + Activity activity = activityIterator.next(); + activityIds[i] = activity.getActivityId(); + i++; + } + Map numberOfUsersInActivity = getCountLearnersCurrentActivities(activityIds); + + EmailProgressActivitiesProcessor processor = new EmailProgressActivitiesProcessor(ld, activityDAO, numberOfUsersInActivity); + processor.parseLearningDesign(); + return processor; + } + @Override + public String[] generateLessonProgressEmail(Long lessonId, Integer userId) { + + Lesson lesson = lessonService.getLesson(lessonId); + EmailProgressActivitiesProcessor activityProcessor = getEmailProgressActivitiesProcessor(lessonId); + Integer completedLearnersCount = getCountLearnersCompletedLesson(lessonId); + Integer startedLearnersCount = lessonService.getCountActiveLessonLearners(lessonId) - completedLearnersCount; + Integer possibleLearnersCount = lessonService.getCountLessonLearners(lessonId, null); + Integer notStarted = possibleLearnersCount - completedLearnersCount - startedLearnersCount; + + StringBuilder progress = new StringBuilder(); + progress.append("

Lesson ").append(lesson.getLessonName()).append("

") + .append(getMessageService().getMessage("label.started")).append(" ") + .append(lesson.getStartDateTime()).append("

") + .append(getMessageService().getMessage("label.grouping.learners")).append("

") + .append("") + .append("") + .append("") + .append("") + .append("
").append(getMessageService().getMessage("label.status")).append("") + .append(getMessageService().getMessage("progress.email.heading.number.learners")) + .append("%
").append(getMessageService().getMessage("label.not.started")).append("") + .append(notStarted).append("") + .append(asPercentage(notStarted, possibleLearnersCount)).append("%
").append(getMessageService().getMessage("lesson.chart.started")).append("") + .append(startedLearnersCount).append("") + .append(asPercentage(startedLearnersCount, possibleLearnersCount)).append("%
").append(getMessageService().getMessage("lesson.chart.completed")).append("") + .append(completedLearnersCount).append("") + .append(asPercentage(completedLearnersCount, possibleLearnersCount)).append("%
").append(possibleLearnersCount).append("") + .append("100%
") + .append("

").append(getMessageService().getMessage("progress.email.heading.overall.progress")).append("

") + .append("") + .append("").append(""); + + int numLearnersProcessed = notStarted; + + Vector activities = activityProcessor.getActivityList(); + for (EmailProgressActivityDTO dto : activities) { + Activity activity = dto.getActivity(); + if (!activity.isFloatingActivity()) { + progress.append(""); + } else { + progress.append(dto.getNumberOfLearners()).append(""); + numLearnersProcessed += dto.getNumberOfLearners(); + } + } + } + numLearnersProcessed += completedLearnersCount; + progress.append("").append("").append("").append("").append("
").append(getMessageService().getMessage("label.activity")).append("") + .append(getMessageService().getMessage("progress.email.heading.number.learners")) + .append("%
") + .append(getMessageService().getMessage("label.not.started")).append("").append(notStarted) + .append("").append(asPercentage(notStarted, possibleLearnersCount)) + .append("%
"); + for (int i = 0; i < dto.getDepth(); i++) { + progress.append("• "); + } + String title = activity.getTitle(); // null for gates + if (title == null) { + title = activity.isGateActivity() ? getMessageService().getMessage("label.gate.title") : + getMessageService().getMessage("label.unknown"); + } + + if (activity.isBranchingActivity() || activity.isOptionsActivity()) { + progress.append("").append(title).append(""); + } else { + progress.append("").append(title).append(""); + } + // output the headings for branching/options but only output numbers if there are learners stuck in the complex activity. + if ((activity.isBranchingActivity() || activity.isOptionsActivity() || activity.isSequenceActivity()) + && (dto.getNumberOfLearners() == null || dto.getNumberOfLearners() == 0)) { + progress.append("
") + .append(asPercentage(dto.getNumberOfLearners(), possibleLearnersCount)) + .append("%
Finished").append(completedLearnersCount) + .append("").append(asPercentage(completedLearnersCount, possibleLearnersCount)) + .append("%
").append(numLearnersProcessed) + .append("").append(asPercentage(numLearnersProcessed, possibleLearnersCount)) + .append("%
").append("

 

").append("

 

") + .append("

") + .append(getMessageService().getMessage("progress.email.sent.automatically")) + .append("

"); + + String subject = getMessageService().getMessage("progress.email.subject", + new Object[] { lesson.getLessonName() }); + + return new String[] { subject, progress.toString() }; + + } + + private String asPercentage(Integer numerator, Integer denominator ) { + double raw = numerator.doubleValue() / denominator * 100; + return NumberUtil.formatLocalisedNumber(raw, (Locale)null, 2); + } + + @Override public Long cloneLesson(Long lessonId, Integer creatorId, Boolean addAllStaff, Boolean addAllLearners, String[] staffIds, String[] learnerIds, Organisation group) throws MonitoringServiceException { Lesson newLesson = null; @@ -2378,4 +2495,5 @@ return resetReadOnly; } + } \ No newline at end of file Fisheye: Tag 1.1 refers to a dead (removed) revision in file `lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/EmailProgressAction.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_monitoring/web/monitor.jsp =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/web/monitor.jsp,v diff -u -r1.27.2.60 -r1.27.2.61 --- lams_monitoring/web/monitor.jsp 16 May 2017 20:56:05 -0000 1.27.2.60 +++ lams_monitoring/web/monitor.jsp 1 Jun 2017 07:31:31 -0000 1.27.2.61 @@ -178,8 +178,26 @@ EMAIL_TITLE : '', - TOUR_DISABLED_ELEMENT : '' - } + TOUR_DISABLED_ELEMENT : '', + + PROGRESS_EMAIL_SUCCESS : '', + + PROGRESS_EMAIL_SEND_NOW_QUESTION : '', + + PROGRESS_EMAIL_SEND_FAILED : '', + + PROGRESS_SELECT_DATE_FIRST : '', + + PROGRESS_ENTER_TWO_DATES_FIRST : '', + + PROGRESS_EMAIL_GENERATE_ONE : '', + + PROGRESS_EMAIL_GENERATE_TWO : '', + + PROGRESS_EMAIL_TITLE : '', + + ERROR_DATE_IN_PAST : '' + } $(document).ready(function(){ initLessonTab(); @@ -409,6 +427,24 @@ + + +
:
+
+
+ + +
+
+
@@ -772,6 +808,46 @@
+
+
+
+
+ + + + + + + +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
Index: lams_monitoring/web/monitorTour.jsp =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/web/Attic/monitorTour.jsp,v diff -u -r1.1.2.5 -r1.1.2.6 --- lams_monitoring/web/monitorTour.jsp 10 May 2017 07:14:23 -0000 1.1.2.5 +++ lams_monitoring/web/monitorTour.jsp 1 Jun 2017 07:31:31 -0000 1.1.2.6 @@ -66,6 +66,16 @@ onShow: revealIM, onHide: hideIM },{ + element: "#sendProgressEmail", + title: "", + content: "", + placement: "bottom" + },{ + element: "#configureProgressEmail", + title: "", + content: "", + placement: "bottom" + },{ element: "#chartDiv", title: "", content: "", Index: lams_monitoring/web/WEB-INF/struts-config.xml =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/web/WEB-INF/Attic/struts-config.xml,v diff -u -r1.2.2.4 -r1.2.2.5 --- lams_monitoring/web/WEB-INF/struts-config.xml 1 Feb 2017 09:20:13 -0000 1.2.2.4 +++ lams_monitoring/web/WEB-INF/struts-config.xml 1 Jun 2017 07:31:31 -0000 1.2.2.5 @@ -214,6 +214,15 @@ redirect="false" /> + + + Index: lams_monitoring/web/includes/javascript/monitorLesson.js =================================================================== RCS file: /usr/local/cvsroot/lams_monitoring/web/includes/javascript/monitorLesson.js,v diff -u -r1.44.2.72 -r1.44.2.73 --- lams_monitoring/web/includes/javascript/monitorLesson.js 16 May 2017 20:56:05 -0000 1.44.2.72 +++ lams_monitoring/web/includes/javascript/monitorLesson.js 1 Jun 2017 07:31:31 -0000 1.44.2.73 @@ -148,9 +148,25 @@ } }); + var emailProgressDialog = showDialog('emailProgressDialog',{ + 'autoOpen' : false, + 'height' : 700, + 'width' : 510, + 'title' : LABELS.PROGRESS_EMAIL_TITLE, + 'resizable' : true, + 'open' : function(){ + autoRefreshBlocked = true; + }, + 'close' : function(){ + autoRefreshBlocked = false; + } + }, false); + $('.modal-body', emailProgressDialog).empty().append($('#emailProgressDialogContents').show()); + //initialize datetimepicker + $("#emaildatePicker").datetimepicker(); + } - /** * Shows all learners in the lesson class. */ @@ -498,6 +514,196 @@ } } +/** + * Set up when the progress emails should be sent to monitors + */ +function configureProgressEmail(){ + fillEmailProgress(); + $('#emailProgressDialog').modal('show'); +} + +/** + * Adds/removes date to the set of progress report emailing dates + */ +function editEmailProgressDate(dateCheckbox){ + var dateid = dateCheckbox.parent().attr('dateid'), + add = dateCheckbox.is(':checked'); + + $.ajax({ + url : LAMS_URL + 'monitoring/emailProgress.do', + type : 'POST', + cache : false, + data : { + 'method' : 'updateEmailProgressDate', + 'lessonID' : lessonId, + 'id' : dateid, + 'add' : add + }, + success : function( dateObj ) { + dateCheckbox.parent().attr('dateid', dateObj.id); + dateCheckbox.parent().attr('datems', dateObj.ms); + dateCheckbox.parent().children().last().html(dateObj.date); + } + }); +} + +/** + * Fills the dates from the server for the email progress + */ +function fillEmailProgress() { + var dialog = $('#emailProgressDialog'), + table = $('#emailProgressDialogTable', dialog), + list = $('.dialogList', table).empty(), + dates = null; + ajaxProperties = dialog.data('ajaxProperties'), + dates = null; + + if (!ajaxProperties) { + // initialise ajax config + ajaxProperties = { + dataType : 'json', + url : LAMS_URL + 'monitoring/emailProgress.do', + cache : false, + async : false, + data : { + 'method' : 'getEmailProgressDates', + 'lessonID' : lessonId + }}; + dialog.data('ajaxProperties', ajaxProperties); + } + + ajaxProperties.success = function(response) { + dates = response.dates; + } + + $.ajax(ajaxProperties); + + $.each(dates, function(dateIndex, date) { + addCheckbox(date, list, true); + }); + + colorDialogList(table); +} + +function addCheckbox(dateObj, list, checked) { + // check for an existing matching date + var alreadyExists = false; + var existingDivs = $("div", list); + $.each(existingDivs, function(divIndex, div) { + if ( div.getAttribute('dateid') == dateObj.id ) { + alreadyExists = true; + return false; + } + }); + if ( alreadyExists ) + return; + + // does not exist so add to list + var checkbox = $('').attr({ + 'type' : 'checkbox' + }).change(function(){ + editEmailProgressDate($(this)); + }), + + dateString = $('').html(dateObj.date), + + dateDiv = $('
').attr({ + 'dateid' : dateObj.id, + 'datems' : dateObj.ms + }) + .addClass('dialogListItem') + .append(dateString) + .prepend(checkbox) + .appendTo(list); + + checkbox.prop('checked', checked); + return checkbox; +} + +function sendProgressEmail() { + if ( confirm(LABELS.PROGRESS_EMAIL_SEND_NOW_QUESTION) ) { + $.ajax({ + dataType : 'json', + url : LAMS_URL + 'monitoring/emailProgress.do', + cache : false, + data : { + 'method' : 'sendLessonProgressEmail', + 'lessonID' : lessonId + }, + success : function(response) { + if ( response.error || ! response.sent > 0 ) + alert(LABELS.PROGRESS_EMAIL_SEND_FAILED+"\n"+(response.error ? response.error : "")); + else + alert(LABELS.PROGRESS_EMAIL_SUCCESS.replace('[0]',response.sent)); + } + }); + } +} + +function addEmailProgressDate() { + var table = $('#emailProgressDialogTable', '#emailProgressDialog'), + list = $('.dialogList', table), + newDateMS = $('#emaildatePicker').datetimepicker('getDate'); + + if ( newDateMS != null ) { + if ( newDateMS.getTime() < Date.now() ) { + alert(LABELS.ERROR_DATE_IN_PAST); + } else { + var dateObj = { id: newDateMS.getTime(), date: getEmailDateString(newDateMS)}, + checkbox = addCheckbox(dateObj, list, true); + editEmailProgressDate(checkbox); // update back end + addEmailProgressSeries(false, table); + } + } else { + alert(LABELS.PROGRESS_SELECT_DATE_FIRST); + } +} + + + +function getEmailDateString(date) { + return date.toLocaleDateString('en', {year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: false }); +} + +function addEmailProgressSeries(forceQuestion, table) { + if ( ! table ) { + table = $('#emailProgressDialogTable', '#emailProgressDialog'); + } + var list = $('.dialogList', table), + items = $('.dialogListItem', list); + + if ( forceQuestion && items.length < 2 ) { + alert(LABELS.PROGRESS_ENTER_TWO_DATES_FIRST); + } else if ( items.length == 2 || forceQuestion ) { + var numDates = prompt(LABELS.PROGRESS_EMAIL_GENERATE_ONE+"\n\n"+LABELS.PROGRESS_EMAIL_GENERATE_TWO); + if ( numDates > 0 ) { + var dates=[]; + var maxDate = 0; + items.each( function() { + var nextDate = $(this).attr('dateid'); + dates.push($(this).attr('dateid')); + if ( maxDate < nextDate ) + maxDate = nextDate; + }); + if ( dates[1] < dates[0] ) { + var swap = dates[1]; + dates[1] = dates[0]; + dates[0] = swap; + } + var diff = dates[1] - dates[0]; + if ( diff > 0 ) { + var genDateMS = maxDate; + for (var i = 0; i < numDates; i++) { + genDateMS = +genDateMS + +diff; + var genDateObj = { id: genDateMS, date: getEmailDateString(new Date(genDateMS))}; + var checkbox = addCheckbox(genDateObj, list, false); + } + } + } + } + colorDialogList(table); +} + //********** SEQUENCE TAB FUNCTIONS ********** /**