Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -rf494ac5c2f49f92be600b6392d9c85c291df7bb7 -r94ed30ec071e295e4a2d469f02778c25f401ca41 Binary files differ Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r3dbf966d900adefc34cdad501d3c392118451cd9 -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 3dbf966d900adefc34cdad501d3c392118451cd9) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -677,4 +677,10 @@ label.no.comments=No Comments label.newest.first=Newest First label.top.comments=Top Comments + +label.private.notifications.title =Notifications +label.private.notifications.messages =Messages +label.private.notifications.read =Read +label.private.notifications.read.hint =Mark notification as read +label.private.notifications.read.all.hint =Mark all notifications as read #======= End labels: Exported 439 labels for en AU ===== Index: lams_central/src/java/org/lamsfoundation/lams/web/NotificationAction.java =================================================================== diff -u --- lams_central/src/java/org/lamsfoundation/lams/web/NotificationAction.java (revision 0) +++ lams_central/src/java/org/lamsfoundation/lams/web/NotificationAction.java (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -0,0 +1,115 @@ +/**************************************************************** + * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ +/* $$Id$$ */ +package org.lamsfoundation.lams.web; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.actions.DispatchAction; +import org.apache.tomcat.util.json.JSONArray; +import org.apache.tomcat.util.json.JSONException; +import org.apache.tomcat.util.json.JSONObject; +import org.lamsfoundation.lams.events.Event; +import org.lamsfoundation.lams.events.IEventNotificationService; +import org.lamsfoundation.lams.events.Subscription; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; + +/** + * Processes notification sent from Tools to users. + * + * @struts:action path="/notification" validate="false" parameter="method" + */ +public class NotificationAction extends DispatchAction { + + private static IEventNotificationService eventNotificationService; + + public ActionForward getNotificationSubscriptions(ActionMapping mapping, ActionForm form, HttpServletRequest req, + HttpServletResponse res) throws JSONException, IOException { + Integer limit = WebUtil.readIntParam(req, "limit", true); + Integer offset = WebUtil.readIntParam(req, "offset", true); + List subscriptions = getEventNotificationService().getNotificationSubscriptions(null, + getUser().getUserID(), limit, offset); + JSONArray responseJSON = new JSONArray(); + Event event = null; + for (Subscription subscription : subscriptions) { + if (event == null) { + event = subscription.getEvent(); + } + JSONObject subscriptionJSON = new JSONObject(); + subscriptionJSON.put("subscriptionUid", subscription.getUid()); + subscriptionJSON.put("message", event.getMessage()); + subscriptionJSON.put("pending", subscription.getLastOperationMessage() == null); + responseJSON.put(subscriptionJSON); + } + + if (responseJSON.length() > 0) { + res.setContentType("application/json;charset=UTF-8"); + res.getWriter().print(responseJSON.toString()); + } + return null; + } + + public ActionForward markNotificationAsRead(ActionMapping mapping, ActionForm form, HttpServletRequest req, + HttpServletResponse res) { + long subscriptionUid = WebUtil.readLongParam(req, "subscriptionUid"); + // trigger means send, i.e. mark as "seen" + getEventNotificationService().triggerForSingleUser(subscriptionUid, null, null); + return null; + } + + public ActionForward getPendingNotificationCount(ActionMapping mapping, ActionForm form, HttpServletRequest req, + HttpServletResponse res) throws IOException { + long count = getEventNotificationService().getNotificationPendingCount(null, getUser().getUserID()); + res.setContentType("text/plain;charset=UTF-8"); + res.getWriter().print(count); + return null; + } + + private IEventNotificationService getEventNotificationService() { + if (NotificationAction.eventNotificationService == null) { + WebApplicationContext ctx = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + NotificationAction.eventNotificationService = (IEventNotificationService) ctx + .getBean("eventNotificationService"); + } + return NotificationAction.eventNotificationService; + } + + private UserDTO getUser() { + HttpSession ss = SessionManager.getSession(); + return (UserDTO) ss.getAttribute(AttributeNames.USER); + } +} \ No newline at end of file Index: lams_central/web/css/index.css =================================================================== diff -u -ra627849a2ed5e825df33ae4bd8372d8c9deed13b -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_central/web/css/index.css (.../index.css) (revision a627849a2ed5e825df33ae4bd8372d8c9deed13b) +++ lams_central/web/css/index.css (.../index.css) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -143,4 +143,36 @@ body > .addLessonDialog .ui-dialog-titlebar { width: 25px; right : 10px; +} + +#dialogPrivateNotifications table { +} + +#dialogPrivateNotifications table tr:first-child td { + font-weight: bold; + text-align: center; +} + +#dialogPrivateNotifications td.notificationsReadCell { + font-size: 16px; + width: 30px; + text-align: center; +} + +#dialogPrivateNotifications td.notificationsPendingCell { + font-weight: bold; +} + +#dialogPrivateNotifications td.notificationsClickableCell:hover { + cursor: pointer; + + border-color: #9be0f9; + background-color: #F0F8FF; + /* CSS3 glow effect: */ + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + -moz-box-shadow: 0 0 5px #A6E5FD; + -webkit-box-shadow: 0 0 5px #A6E5FD; + box-shadow: 0 0 5px #A6E5FD; } \ No newline at end of file Index: lams_central/web/includes/javascript/groupDisplay.js =================================================================== diff -u -r3dbf966d900adefc34cdad501d3c392118451cd9 -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_central/web/includes/javascript/groupDisplay.js (.../groupDisplay.js) (revision 3dbf966d900adefc34cdad501d3c392118451cd9) +++ lams_central/web/includes/javascript/groupDisplay.js (.../groupDisplay.js) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -15,6 +15,8 @@ $("#actionAccord").accordion({ 'heightStyle' : 'content' }); + + refreshPrivateNotificationCount(); } function loadOrgTab(orgTab, refresh) { @@ -198,7 +200,7 @@ + 'home.do?method=addLesson&organisationID=' + $(this).dialog('option', 'orgID')); - //in case of mobile devices allow iframe scrolling + // in case of mobile devices allow iframe scrolling if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) { setTimeout(function() { $('.dialogContainer').css('overflow-y','scroll'); @@ -280,8 +282,7 @@ 'open' : function() { var dialog = $(this), lessonID = dialog.dialog('option', 'lessonID'); - // if lesson ID is given, use lesson view; otherwise - // use course view + // if lesson ID is given, use lesson view; otherwise use course view if (lessonID) { // load contents after opening the dialog $('iframe', dialog).attr('src', LAMS_URL @@ -297,6 +298,127 @@ }, true); } + +function showPrivateNotificationsDialog(){ + showDialog("dialogPrivateNotifications", { + 'height' : 470, + 'width' : 600, + 'title' : LABELS.PRIVATE_NOTIFICATIONS_TITLE, + 'close' : function(){ + refreshPrivateNotificationCount(); + // completely delete the dialog + $(this).remove(); + }, + 'open' : function() { + // build the table from the scratch + var dialog = $(this), + table = $('').appendTo(dialog), + // table header + headerRow = $('').appendTo(table); + $('').attr('id', 'subscription-' + notification.subscriptionUid) + .appendTo(table), + messageCell = $(' + + + + +
').text(LABELS.PRIVATE_NOTIFICATIONS_MESSAGES).appendTo(headerRow); + // click it to mark all notifications as read + $('').text(LABELS.PRIVATE_NOTIFICATIONS_READ) + .attr('title', LABELS.PRIVATE_NOTIFICATIONS_READ_ALL_HINT) + .click(markAllPrivateNotificationsAsRead) + .appendTo(headerRow); + $('iframe', dialog).remove(); + $.ajax({ + cache : false, + url : LAMS_URL + "notification.do", + dataType : 'json', + data : { + 'method' : 'getNotificationSubscriptions', + // maybe it will change for paging; "offset" param is also available + 'limit' : 10 + }, + success : function(notifications) { + if (!notifications) { + return; + } + + // build notification rows one by one + $.each(notifications, function(){ + var notification = this, + row = $('
').appendTo(row), + readCell = $('') + .appendTo(row); + // is it a link? + if (notification.message.indexOf(' td') + // message cell + .first().removeClass('notificationsPendingCell') + // read cell + .next().html('✔').removeClass('notificationsClickableCell').attr('title', null).off('click'); + } + }); +} + +function refreshPrivateNotificationCount(){ + $.ajax({ + cache : false, + url : LAMS_URL + "notification.do", + dataType : 'text', + data : { + 'method' : 'getPendingNotificationCount' + }, + success : function(count) { + $('#notificationsPendingCount').text(count == 0 ? '' : '(' + count + ')'); + } + }); +} + function showGradebookCourseDialog(orgID){ var id = "dialoGradebookCourse" + orgID; showDialog(id, { @@ -431,12 +553,15 @@ // check if the LD was created successfully if (learningDesignID) { var frame = $('iframe', dialog); - // disable previous onload handler, set in showAddSingleActivityLessonDialog() + // disable previous onload handler, set in + // showAddSingleActivityLessonDialog() frame.off('load').load(function(){ - // disable current onload handler as closing the dialog reloads the iframe + // disable current onload handler as closing the dialog + // reloads the iframe frame.off('load'); - // call svgGenerator.jsp code to store LD SVG on the server + // call svgGenerator.jsp code to store LD SVG on the + // server var win = frame[0].contentWindow || frame[0].contentDocument; win.GeneralLib.saveLearningDesignImage(); @@ -463,7 +588,6 @@ $("#" + id).dialog('close'); } - /** * Loads contents to already open organisation groups dialog. */ @@ -486,7 +610,8 @@ } /** - * Called from within Course Groups dialog, it saves groups and loads grouping page. + * Called from within Course Groups dialog, it saves groups and loads grouping + * page. */ function saveOrgGroups() { var groupsSaved = $('#dialogOrgGroup iframe')[0].contentWindow.saveGroups(); Index: lams_central/web/main.jsp =================================================================== diff -u -r3dbf966d900adefc34cdad501d3c392118451cd9 -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_central/web/main.jsp (.../main.jsp) (revision 3dbf966d900adefc34cdad501d3c392118451cd9) +++ lams_central/web/main.jsp (.../main.jsp) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -68,6 +68,16 @@ NAVIGATE_AWAY_CONFIRM : decoderDiv.html('').text(), MONITORING_TITLE : '', + + PRIVATE_NOTIFICATIONS_TITLE : '', + + PRIVATE_NOTIFICATIONS_MESSAGES : '', + + PRIVATE_NOTIFICATIONS_READ : '', + + PRIVATE_NOTIFICATIONS_READ_HINT : '', + + PRIVATE_NOTIFICATIONS_READ_ALL_HINT : '', }, tabName = '${tab}', @@ -192,12 +202,13 @@ - -
" - onClick="javascript:loadOrgTab(null, true)"> - -
-
+
" + onClick="javascript:refreshPrivateNotificationCount();loadOrgTab(null, true)"> + +
+
+ Notifications +
@@ -248,6 +259,5 @@

- \ No newline at end of file Index: lams_common/build.xml =================================================================== diff -u -r3dbf966d900adefc34cdad501d3c392118451cd9 -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/build.xml (.../build.xml) (revision 3dbf966d900adefc34cdad501d3c392118451cd9) +++ lams_common/build.xml (.../build.xml) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -14,6 +14,7 @@ + Index: lams_common/src/java/org/lamsfoundation/lams/beanRefContext.xml =================================================================== diff -u -rd3c9d3f03c16e8f7025d7b2bfe84e68af4fc0746 -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/src/java/org/lamsfoundation/lams/beanRefContext.xml (.../beanRefContext.xml) (revision d3c9d3f03c16e8f7025d7b2bfe84e68af4fc0746) +++ lams_common/src/java/org/lamsfoundation/lams/beanRefContext.xml (.../beanRefContext.xml) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -43,7 +43,6 @@ /org/lamsfoundation/lams/toolApplicationContext.xml /org/lamsfoundation/lams/comments/commentsContext.xml /org/lamsfoundation/lams/contentrepository/applicationContext.xml - /org/lamsfoundation/lams/lesson/lessonApplicationContext.xml /org/lamsfoundation/lams/learning/learningApplicationContext.xml classpath*:org/lamsfoundation/lams/tool/**/*pplicationContext.xml Index: lams_common/src/java/org/lamsfoundation/lams/commonContext.xml =================================================================== diff -u -r3dbf966d900adefc34cdad501d3c392118451cd9 -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision 3dbf966d900adefc34cdad501d3c392118451cd9) +++ lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -106,6 +106,36 @@ + + + + + + + + + + + + + true + + + + + + + + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + + + + @@ -327,15 +357,16 @@ - PROPAGATION_REQUIRED + PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED - PROPAGATION_REQUIRED + PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED + PROPAGATION_REQUIRED @@ -443,8 +474,22 @@ - + + + + + + + + + + + + + + + Index: lams_common/src/java/org/lamsfoundation/lams/events/AbstractDeliveryMethod.java =================================================================== diff -u -r1edbb81f16cedfcc1326e4eca6e520b5b48cbddc -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/src/java/org/lamsfoundation/lams/events/AbstractDeliveryMethod.java (.../AbstractDeliveryMethod.java) (revision 1edbb81f16cedfcc1326e4eca6e520b5b48cbddc) +++ lams_common/src/java/org/lamsfoundation/lams/events/AbstractDeliveryMethod.java (.../AbstractDeliveryMethod.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -1,8 +1,12 @@ package org.lamsfoundation.lams.events; import java.security.InvalidParameterException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; -import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; /** * Provides methods to notify users of an event. @@ -12,16 +16,6 @@ */ public abstract class AbstractDeliveryMethod { /** - * Short name for the delivery method - */ - protected final String signature; - - /** - * Short description of the delivery method. - */ - protected final String description; - - /** * Unique identifier of the delivery method. */ protected final short id; @@ -31,24 +25,16 @@ */ protected long sendTimeout = Long.MAX_VALUE; + protected final Map errors = new HashMap(); + protected static final long ERROR_SILENCE_TIMEOUT = 5000; + /** * Standard constructor. * * @param id * ID of the delivery method - * @param signature - * signature of the delivery method - * @param description - * short description of the delivery method - * @throws InvalidParameterException - * if signature is blank */ - protected AbstractDeliveryMethod(short id, String signature, String description) throws InvalidParameterException { - if (StringUtils.isEmpty(signature)) { - throw new InvalidParameterException("Signature must not be blank."); - } - this.signature = signature; - this.description = description; + protected AbstractDeliveryMethod(short id) throws InvalidParameterException { this.id = id; } @@ -69,18 +55,13 @@ protected abstract String send(Integer fromUserId, Integer toUserId, String subject, String message, boolean isHtmlFormat) throws InvalidParameterException; - public String getSignature() { - return signature; - } + protected abstract Logger getLog(); - public String getDescription() { - return description; - } + protected abstract boolean lastOperationFailed(Subscription subscription); @Override public boolean equals(Object o) { - return (o instanceof AbstractDeliveryMethod) - && ((AbstractDeliveryMethod) o).signature.equalsIgnoreCase(signature); + return (o instanceof AbstractDeliveryMethod) && (((AbstractDeliveryMethod) o).id == this.id); } public short getId() { @@ -94,4 +75,29 @@ public void setSendTimeout(long sendTimeout) { this.sendTimeout = sendTimeout; } + + /** + * Checks if the error was already logged recently. If not, logs it. + */ + protected synchronized void logError(String error) { + Iterator> errorIterator = errors.entrySet().iterator(); + boolean logError = true; + long currentTime = System.currentTimeMillis(); + // same errors younger than this will be silenced + long silencePeriod = currentTime - AbstractDeliveryMethod.ERROR_SILENCE_TIMEOUT; + while (errorIterator.hasNext()) { + Entry entry = errorIterator.next(); + if (entry.getKey() < silencePeriod) { + // clear the map from garbage + errorIterator.remove(); + } else if (error.equals(entry.getValue())) { + logError = false; + // do not break, let the clean up go through the whole map + } + } + if (logError) { + errors.put(currentTime, error); + getLog().error("Error while notifying users: " + error); + } + } } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/events/DeliveryMethodMail.java =================================================================== diff -u -r7e31f6d25dc9f5c22780eb6b3c25ec19fca00e1d -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/src/java/org/lamsfoundation/lams/events/DeliveryMethodMail.java (.../DeliveryMethodMail.java) (revision 7e31f6d25dc9f5c22780eb6b3c25ec19fca00e1d) +++ lams_common/src/java/org/lamsfoundation/lams/events/DeliveryMethodMail.java (.../DeliveryMethodMail.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -2,10 +2,6 @@ import java.io.UnsupportedEncodingException; import java.security.InvalidParameterException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; import javax.mail.MessagingException; import javax.mail.internet.AddressException; @@ -28,47 +24,44 @@ public class DeliveryMethodMail extends AbstractDeliveryMethod { private static final Logger log = Logger.getLogger(DeliveryMethodMail.class); - private static final long ERROR_SILENCE_TIMEOUT = 5000; - private static DeliveryMethodMail instance = null; - private final EmailValidator emailValidator = EmailValidator.getInstance(); - private final Map errors = new HashMap(); + private static final EmailValidator emailValidator = EmailValidator.getInstance(); - private IUserManagementService userManagementService = null; + private static IUserManagementService userManagementService = null; - public static DeliveryMethodMail getInstance() { + protected static DeliveryMethodMail getInstance() { if (DeliveryMethodMail.instance == null) { DeliveryMethodMail.instance = new DeliveryMethodMail(); } return DeliveryMethodMail.instance; } private DeliveryMethodMail() { - super((short) 1, "MAIL", "Messages will be send by email"); + super((short) 1); } @Override - public String send(Integer fromUserId, Integer toUserId, String subject, String message, boolean isHtmlFormat) + protected String send(Integer fromUserId, Integer toUserId, String subject, String message, boolean isHtmlFormat) throws InvalidParameterException { try { - User toUser = (User) userManagementService.findById(User.class, toUserId); + User toUser = (User) DeliveryMethodMail.userManagementService.findById(User.class, toUserId); if (toUser == null) { return "Target user with ID " + toUserId + " was not found."; } String toEmail = toUser.getEmail(); - if (!emailValidator.isValid(toEmail)) { + if (!DeliveryMethodMail.emailValidator.isValid(toEmail)) { return "Target user's e-mail address is invalid."; } if (fromUserId == null) { Emailer.sendFromSupportEmail(subject, toEmail, message, isHtmlFormat); } else { - User fromUser = (User) userManagementService.findById(User.class, fromUserId); + User fromUser = (User) DeliveryMethodMail.userManagementService.findById(User.class, fromUserId); if (fromUser == null) { return "Source user with ID " + fromUserId + " was not found."; } String fromEmail = fromUser.getEmail(); - if (!emailValidator.isValid(fromEmail)) { + if (!DeliveryMethodMail.emailValidator.isValid(fromEmail)) { return "Source user's e-mail address is invalid."; } @@ -82,10 +75,14 @@ } } - public void setUserManagementService(IUserManagementService userManagementService) { - this.userManagementService = userManagementService; + protected boolean lastOperationFailed(Subscription subscription) { + return subscription.getLastOperationMessage() != null; } + static void setUserManagementService(IUserManagementService userManagementService) { + DeliveryMethodMail.userManagementService = userManagementService; + } + /** * Sends an email to the address provided by the admin. * @@ -113,28 +110,8 @@ } } - /** - * Checks if the error was already logged recently. If not, logs it. - */ - private synchronized void logError(String error) { - Iterator> errorIterator = errors.entrySet().iterator(); - boolean logError = true; - long currentTime = System.currentTimeMillis(); - // same errors younger than this will be silenced - long silencePeriod = currentTime - DeliveryMethodMail.ERROR_SILENCE_TIMEOUT; - while (errorIterator.hasNext()) { - Entry entry = errorIterator.next(); - if (entry.getKey() < silencePeriod) { - // clear the map from garbage - errorIterator.remove(); - } else if (error.equals(entry.getValue())) { - logError = false; - // do not break, let the clean up go through the whole map - } - } - if (logError) { - errors.put(currentTime, error); - DeliveryMethodMail.log.error("Error while sending emails: " + error); - } + @Override + protected Logger getLog() { + return DeliveryMethodMail.log; } } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/events/DeliveryMethodNotification.java =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/events/DeliveryMethodNotification.java (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/events/DeliveryMethodNotification.java (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -0,0 +1,47 @@ +package org.lamsfoundation.lams.events; + +import java.security.InvalidParameterException; + +import org.apache.log4j.Logger; + +/** + * Allows sending mail from the configured mail server. + * + * @author Marcin Cieslak + * + */ +public class DeliveryMethodNotification extends AbstractDeliveryMethod { + private static final Logger log = Logger.getLogger(DeliveryMethodNotification.class); + + public static final String LAST_OPERATION_SEEN = "seen"; + + private static DeliveryMethodNotification instance = null; + + protected static DeliveryMethodNotification getInstance() { + if (DeliveryMethodNotification.instance == null) { + DeliveryMethodNotification.instance = new DeliveryMethodNotification(); + } + return DeliveryMethodNotification.instance; + } + + private DeliveryMethodNotification() { + super((short) 2); + } + + @Override + protected String send(Integer fromUserId, Integer toUserId, String subject, String message, boolean isHtmlFormat) + throws InvalidParameterException { + return DeliveryMethodNotification.LAST_OPERATION_SEEN; + } + + @Override + protected boolean lastOperationFailed(Subscription subscription) { + return (subscription.getLastOperationMessage() != null) + && !DeliveryMethodNotification.LAST_OPERATION_SEEN.equals(subscription.getLastOperationMessage()); + } + + @Override + protected Logger getLog() { + return DeliveryMethodNotification.log; + } +} \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/events/Event.java =================================================================== diff -u -r15f56ca278fe37b325c0faf582c1245545a4100f -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/src/java/org/lamsfoundation/lams/events/Event.java (.../Event.java) (revision 15f56ca278fe37b325c0faf582c1245545a4100f) +++ lams_common/src/java/org/lamsfoundation/lams/events/Event.java (.../Event.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -154,7 +154,7 @@ /** * - * @hibernate.set cascade="all-delete-orphan" order-by="last_operation_time desc" outer-join="true" + * @hibernate.set cascade="all-delete-orphan" outer-join="true" * @hibernate.collection-key column="event_uid" * @hibernate.collection-one-to-many class="org.lamsfoundation.lams.events.Subscription" * Index: lams_common/src/java/org/lamsfoundation/lams/events/EventNotificationService.java =================================================================== diff -u -r6507b9cc6e67eed53ac0061bd401514a3d70993f -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/src/java/org/lamsfoundation/lams/events/EventNotificationService.java (.../EventNotificationService.java) (revision 6507b9cc6e67eed53ac0061bd401514a3d70993f) +++ lams_common/src/java/org/lamsfoundation/lams/events/EventNotificationService.java (.../EventNotificationService.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -20,6 +20,7 @@ import org.lamsfoundation.lams.util.Configuration; import org.lamsfoundation.lams.util.ConfigurationKeys; import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.hibernate.HibernateSessionManager; /** * Provides tools for managing events and notifing users. @@ -33,6 +34,7 @@ static { IEventNotificationService.availableDeliveryMethods.add(IEventNotificationService.DELIVERY_METHOD_MAIL); + IEventNotificationService.availableDeliveryMethods.add(IEventNotificationService.DELIVERY_METHOD_NOTIFICATION); } private EventDAO eventDAO = null; @@ -43,14 +45,37 @@ @Override public void createEvent(String scope, String name, Long eventSessionId, String defaultSubject, - String defaultMessage, boolean isHtmlFormat) throws InvalidParameterException { + String defaultMessage, boolean isHtmlFormat) { if (!eventExists(scope, name, eventSessionId)) { Event event = new Event(scope, name, eventSessionId, defaultSubject, defaultMessage, isHtmlFormat); - eventDAO.saveEvent(event); + eventDAO.insertOrUpdate(event); } } + @SuppressWarnings("unchecked") @Override + public void createLessonEvent(String scope, String name, Long toolContentId, String defaultSubject, + String defaultMessage, boolean isHtmlFormat, AbstractDeliveryMethod deliveryMethod) + throws InvalidParameterException { + Lesson lesson = getLessonByToolContentId(toolContentId); + if (!eventExists(scope, name, lesson.getLessonId())) { + Event event = new Event(scope, name, lesson.getLessonId(), defaultSubject, defaultMessage, isHtmlFormat); + Set users = null; + if (scope.equals(IEventNotificationService.LESSON_MONITORS_SCOPE)) { + users = lesson.getLessonClass().getStaffGroup().getUsers(); + } else if (scope.equals(IEventNotificationService.LESSON_LEARNERS_SCOPE)) { + users = lesson.getLessonClass().getLearners(); + } + if (users != null) { + for (User user : users) { + event.getSubscriptions().add(new Subscription(user.getUserId(), deliveryMethod)); + } + eventDAO.insert(event); + } + } + } + + @Override public boolean eventExists(String scope, String name, Long eventSessionId) throws InvalidParameterException { if (scope == null) { throw new InvalidParameterException("Scope should not be null."); @@ -157,7 +182,7 @@ IEventNotificationService.DELIVERY_METHOD_MAIL.notifyAdmin( messageService.getMessage("mail.resend.abandon.subject"), body.toString(), event.isHtmlFormat()); - eventDAO.deleteEvent(event); + eventDAO.delete(event); } } @@ -179,7 +204,7 @@ String.valueOf(System.currentTimeMillis()), null, subject, message, isHtmlFormat); subscribe(event, toUserId, deliveryMethod); event.setFailTime(new Date()); - eventDAO.saveEvent(event); + eventDAO.insertOrUpdate(event); return false; } @@ -195,6 +220,8 @@ } // create a new thread to send the messages as it can take some time new Thread(() -> { + HibernateSessionManager.bindHibernateSessionToCurrentThread(false); + Event event = null; for (Integer id : toUserIds) { String result = deliveryMethod.send(fromUserId, id, subject, message, isHtmlFormat); @@ -206,11 +233,22 @@ } if (event != null) { event.setFailTime(new Date()); - eventDAO.saveEvent(event); + eventDAO.insertOrUpdate(event); } }).start(); } + @Override + public List getNotificationSubscriptions(Long lessonId, Integer userId, Integer limit, + Integer offset) { + return eventDAO.getLessonEventSubscriptions(lessonId, userId, limit, offset); + } + + @Override + public long getNotificationPendingCount(Long lessonId, Integer userId) { + return eventDAO.getPendingNotificationCount(lessonId, userId); + } + public void setEventDAO(EventDAO eventDAO) { this.eventDAO = eventDAO; } @@ -229,7 +267,7 @@ public void setUserManagementService(IUserManagementService userManagementService) { this.userManagementService = userManagementService; - IEventNotificationService.DELIVERY_METHOD_MAIL.setUserManagementService(userManagementService); + DeliveryMethodMail.setUserManagementService(userManagementService); } /** @@ -248,16 +286,15 @@ List subscriptionList = new ArrayList(event.getSubscriptions()); for (int index = 0; index < subscriptionList.size(); index++) { Subscription subscription = subscriptionList.get(index); - if (subscription.getUserId().equals(userId) - && subscription.getDeliveryMethod().equals(deliveryMethod.getId())) { + if (subscription.getUserId().equals(userId) && subscription.getDeliveryMethod().equals(deliveryMethod)) { substriptionFound = true; break; } } if (!substriptionFound) { event.getSubscriptions().add(new Subscription(userId, deliveryMethod)); } - eventDAO.saveEvent(event); + eventDAO.update(event); } @Override @@ -291,12 +328,14 @@ // create a new thread to send the messages as it can take some time new Thread(() -> { + HibernateSessionManager.bindHibernateSessionToCurrentThread(false); + Event eventFailCopy = null; Iterator subscriptionIterator = event.getSubscriptions().iterator(); while (subscriptionIterator.hasNext()) { Subscription subscription = subscriptionIterator.next(); notifyUser(subscription, subjectToSend, messageToSend, event.isHtmlFormat()); - if (subscription.getLastOperationMessage() == null) { + if (subscription.getDeliveryMethod().lastOperationFailed(subscription)) { if (event.getFailTime() != null) { subscriptionIterator.remove(); } @@ -308,9 +347,9 @@ } } if (event.getSubscriptions().isEmpty()) { - eventDAO.deleteEvent(event); + eventDAO.delete(event); } else { - eventDAO.saveEvent(event); + eventDAO.insertOrUpdate(event); } /* @@ -321,7 +360,7 @@ eventFailCopy.setFailTime(new Date()); eventFailCopy.setSubject(subjectToSend); eventFailCopy.setMessage(messageToSend); - eventDAO.saveEvent(eventFailCopy); + eventDAO.insertOrUpdate(eventFailCopy); } }).start(); } @@ -366,6 +405,12 @@ } @Override + public void triggerLessonEvent(String scope, String name, Long toolContentId, String subject, String message) { + Lesson lesson = getLessonByToolContentId(toolContentId); + trigger(scope, name, lesson.getLessonId(), subject, message); + } + + @Override public void trigger(String scope, String name, Long eventSessionId, String title, String message) throws InvalidParameterException { if (scope == null) { @@ -381,30 +426,32 @@ trigger(event, title, message); } - /** - * See {@link IEventNotificationService#triggerForSingleUser(String, String, Long, Long)} - */ - private void triggerForSingleUser(Event event, Integer userId, String subject, String message) - throws InvalidParameterException { - final String subjectToSend = subject == null ? event.getSubject() : subject; - final String messageToSend = message == null ? event.getMessage() : message; - + private void triggerForSingleUser(Event event, Integer userId, String subject, String message) { for (Subscription subscription : event.getSubscriptions()) { if (subscription.getUserId().equals(userId)) { - notifyUser(subscription, subject, message, event.isHtmlFormat()); - if (subscription.getLastOperationMessage() != null) { - Event eventFailCopy = (Event) event.clone(); - eventFailCopy.setFailTime(new Date()); - eventFailCopy.setSubject(subjectToSend); - eventFailCopy.setMessage(messageToSend); - subscribe(eventFailCopy, subscription.getUserId(), subscription.getDeliveryMethod()); - eventDAO.saveEvent(eventFailCopy); - } + triggerForSingleUser(subscription.getUid(), subject, message); } } } @Override + public void triggerForSingleUser(Long subscriptionUid, String subject, String message) { + Subscription subscription = (Subscription) eventDAO.find(Subscription.class, subscriptionUid); + Event event = subscription.getEvent(); + String subjectToSend = subject == null ? event.getSubject() : subject; + String messageToSend = message == null ? event.getMessage() : message; + notifyUser(subscription, subject, message, event.isHtmlFormat()); + if (subscription.getDeliveryMethod().lastOperationFailed(subscription)) { + Event eventFailCopy = (Event) event.clone(); + eventFailCopy.setFailTime(new Date()); + eventFailCopy.setSubject(subjectToSend); + eventFailCopy.setMessage(messageToSend); + subscribe(eventFailCopy, subscription.getUserId(), subscription.getDeliveryMethod()); + eventDAO.insertOrUpdate(eventFailCopy); + } + } + + @Override public void triggerForSingleUser(String scope, String name, Long eventSessionId, Integer userId) throws InvalidParameterException { if (scope == null) { @@ -484,9 +531,9 @@ } } if (event.getSubscriptions().isEmpty()) { - eventDAO.deleteEvent(event); + eventDAO.delete(event); } else { - eventDAO.saveEvent(event); + eventDAO.insertOrUpdate(event); } } @@ -509,9 +556,9 @@ } } if (event.getSubscriptions().isEmpty()) { - eventDAO.deleteEvent(event); + eventDAO.delete(event); } else { - eventDAO.saveEvent(event); + eventDAO.insertOrUpdate(event); } } @@ -555,4 +602,10 @@ } unsubscribe(event, userId, deliveryMethod); } + + private Lesson getLessonByToolContentId(Long toolContentId) { + ToolActivity activity = (ToolActivity) eventDAO + .findByProperty(ToolActivity.class, "toolContentId", toolContentId).get(0); + return (Lesson) activity.getLearningDesign().getLessons().iterator().next(); + } } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/events/IEventNotificationService.java =================================================================== diff -u -r6507b9cc6e67eed53ac0061bd401514a3d70993f -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/src/java/org/lamsfoundation/lams/events/IEventNotificationService.java (.../IEventNotificationService.java) (revision 6507b9cc6e67eed53ac0061bd401514a3d70993f) +++ lams_common/src/java/org/lamsfoundation/lams/events/IEventNotificationService.java (.../IEventNotificationService.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -2,6 +2,7 @@ import java.security.InvalidParameterException; import java.util.HashSet; +import java.util.List; import java.util.Set; /** @@ -15,9 +16,19 @@ /** * Scope for the events that are common for the whole LAMS environment. */ - static final String CORE_EVENTS_SCOPE = "CORE"; + static final String CORE_SCOPE = "CORE"; /** + * Scope for the events that are meant for given lesson staff. + */ + static final String LESSON_MONITORS_SCOPE = "LESSON_MONITORS"; + + /** + * Scope for the events that are meant for given lesson learners. + */ + static final String LESSON_LEARNERS_SCOPE = "LESSON_LEARNERS"; + + /** * Scope for events that were created after {@link #sendMessage(Long, AbstractDeliveryMethod, String, String)} * failed. */ @@ -34,6 +45,8 @@ */ static final DeliveryMethodMail DELIVERY_METHOD_MAIL = DeliveryMethodMail.getInstance(); + static final DeliveryMethodNotification DELIVERY_METHOD_NOTIFICATION = DeliveryMethodNotification.getInstance(); + static final Set availableDeliveryMethods = new HashSet(2); /** @@ -51,13 +64,13 @@ * body of the message send to users; it can be altered when triggering the event * @param isHtmlFormat * whether the message is of HTML content-type or plain text - * @return true if the event did not exist and was correctly created - * @throws InvalidParameterException - * if scope was null or name was blank */ void createEvent(String scope, String name, Long eventSessionId, String defaultSubject, String defaultMessage, - boolean isHtmlFormat) throws InvalidParameterException; + boolean isHtmlFormat); + void createLessonEvent(String scope, String name, Long toolSessionId, String defaultSubject, String defaultMessage, + boolean isHtmlFormat, AbstractDeliveryMethod deliveryMethod); + /** * Checks if event with the given parameters exists in the database. * @@ -80,6 +93,10 @@ */ Set getAvailableDeliveryMethods(); + List getNotificationSubscriptions(Long lessonId, Integer userId, Integer limit, Integer offset); + + long getNotificationPendingCount(Long lessonId, Integer userId); + /** * Checks if an user is subscribed to the given event. * @@ -206,6 +223,8 @@ void trigger(String scope, String name, Long eventSessionId, Object[] parameterValues) throws InvalidParameterException; + void triggerLessonEvent(String scope, String name, Long toolContentId, String subject, String message); + /** * Triggers the event with given subject and message. Each subscribed user is notified. Default message and subject * are overridden. @@ -226,6 +245,8 @@ void trigger(String scope, String name, Long eventSessionId, String subject, String message) throws InvalidParameterException; + void triggerForSingleUser(Long subscriptionUid, String subject, String message); + /** * Notifies only a single user of the event using the default subject and message. Does not set the event as * "triggered". Index: lams_common/src/java/org/lamsfoundation/lams/events/dao/EventDAO.java =================================================================== diff -u -r6e4ed3724bd76354c2ee43c88979385c4a162a0e -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/src/java/org/lamsfoundation/lams/events/dao/EventDAO.java (.../EventDAO.java) (revision 6e4ed3724bd76354c2ee43c88979385c4a162a0e) +++ lams_common/src/java/org/lamsfoundation/lams/events/dao/EventDAO.java (.../EventDAO.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -2,26 +2,29 @@ import java.util.List; +import org.lamsfoundation.lams.dao.IBaseDAO; import org.lamsfoundation.lams.events.Event; +import org.lamsfoundation.lams.events.Subscription; -public interface EventDAO { - /** - * Gets an instance of the event. - * @param scope - * @param name - * @param eventSessionId - * @return - */ - Event getEvent(String scope, String name, Long sessionId); +public interface EventDAO extends IBaseDAO { + /** + * Gets an instance of the event. + * + * @param scope + * @param name + * @param eventSessionId + * @return + */ + Event getEvent(String scope, String name, Long sessionId); - /** - * Gets events with messages that need to be resend. - * Either they failed to be send or they should be repeated. - * @return list of events - */ - List getEventsToResend(); + /** + * Gets events with messages that need to be resend. Either they failed to be send or they should be repeated. + * + * @return list of events + */ + List getEventsToResend(); - void deleteEvent(Event event); + List getLessonEventSubscriptions(Long lessonId, Integer userId, Integer limit, Integer offset); - void saveEvent(Event event); + long getPendingNotificationCount(Long lessonId, Integer userId); } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/events/dao/hibernate/EventDAOHibernate.java =================================================================== diff -u -r6507b9cc6e67eed53ac0061bd401514a3d70993f -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_common/src/java/org/lamsfoundation/lams/events/dao/hibernate/EventDAOHibernate.java (.../EventDAOHibernate.java) (revision 6507b9cc6e67eed53ac0061bd401514a3d70993f) +++ lams_common/src/java/org/lamsfoundation/lams/events/dao/hibernate/EventDAOHibernate.java (.../EventDAOHibernate.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -3,8 +3,11 @@ import java.security.InvalidParameterException; import java.util.List; +import org.hibernate.Query; import org.lamsfoundation.lams.dao.hibernate.LAMSBaseDAO; +import org.lamsfoundation.lams.events.DeliveryMethodNotification; import org.lamsfoundation.lams.events.Event; +import org.lamsfoundation.lams.events.Subscription; import org.lamsfoundation.lams.events.dao.EventDAO; import org.springframework.stereotype.Repository; @@ -17,6 +20,14 @@ private static final String GET_EVENTS_TO_RESEND_QUERY = "SELECT DISTINCT e FROM " + Event.class.getName() + " AS e WHERE e.failTime IS NOT NULL"; + private static final String GET_LESSON_EVENT_SUBSCRIPTIONS = "FROM " + Subscription.class.getName() + + " AS s WHERE s.userId = ? AND s.event.scope LIKE 'LESSON_%'"; + + private static final String COUNT_PENDING_NOTIFICATIONS = "SELECT COUNT(*) FROM " + Subscription.class.getName() + + " AS s WHERE (s.lastOperationMessage IS NULL OR s.lastOperationMessage != '" + + DeliveryMethodNotification.LAST_OPERATION_SEEN + "') AND s.userId = ? AND s.event.scope LIKE 'LESSON_%'"; + + @Override @SuppressWarnings("unchecked") public Event getEvent(String scope, String name, Long sessionId) throws InvalidParameterException { List events = (List) doFind(EventDAOHibernate.GET_EVENT_QUERY, @@ -30,16 +41,46 @@ return events.get(0); } + @Override @SuppressWarnings("unchecked") public List getEventsToResend() { return (List) doFind(EventDAOHibernate.GET_EVENTS_TO_RESEND_QUERY); } - public void deleteEvent(Event event) { - getSession().delete(event); + @Override + @SuppressWarnings("unchecked") + public List getLessonEventSubscriptions(Long lessonId, Integer userId, Integer limit, + Integer offset) { + String query = EventDAOHibernate.GET_LESSON_EVENT_SUBSCRIPTIONS; + if (lessonId != null) { + query += " AND s.event.eventSessionId = ?"; + } + query += " ORDER BY ISNULL(s.lastOperationMessage) DESC, uid ASC"; + Query queryObject = getSession().createQuery(query); + queryObject.setInteger(0, userId); + if (lessonId != null) { + queryObject.setLong(1, lessonId); + } + if (limit != null) { + queryObject.setMaxResults(limit); + } + if (offset != null) { + queryObject.setFirstResult(offset); + } + return queryObject.list(); } - public void saveEvent(Event event) { - getSession().saveOrUpdate(event); + @Override + public long getPendingNotificationCount(Long lessonId, Integer userId) { + String query = EventDAOHibernate.COUNT_PENDING_NOTIFICATIONS; + if (lessonId != null) { + query += " AND s.event.eventSessionId = ?"; + } + Query queryObject = getSession().createQuery(query); + queryObject.setInteger(0, userId); + if (lessonId != null) { + queryObject.setLong(1, lessonId); + } + return (Long) queryObject.uniqueResult(); } } \ No newline at end of file Fisheye: Tag 94ed30ec071e295e4a2d469f02778c25f401ca41 refers to a dead (removed) revision in file `lams_common/src/java/org/lamsfoundation/lams/lesson/lessonApplicationContext.xml'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_tool_larsrc/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r71012b6f2ac523d8faaef475332dbad1338c448d -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_tool_larsrc/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 71012b6f2ac523d8faaef475332dbad1338c448d) +++ lams_tool_larsrc/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -155,9 +155,11 @@ monitor.summary.th.advancedSettings =Advanced settings monitor.summary.td.addNotebook =Add a notebook at end of Shared Resources monitor.summary.td.notebookInstructions =Notebook instructions -label.authoring.advanced.notify.onassigmentsubmit =Notify instructors when a learner submits a resource +label.authoring.advanced.notify.onassigmentsubmit =Email instructors when a learner submits a resource +label.authoring.advanced.notify.onfileupload =Notify instructors when a learner uploads a file event.assigment.submit.subject =LAMS: A learner submitted an assignment in a Shared Resources tool event.assigment.submit.body =The learner {0} submitted an assignment in a Shared Resources tool.\n\nThis message was sent automatically, following the tool''s advanced settings. +event.file.upload ={0} uploaded a file \"{1}\" error.planner.no.resource.save =There has to be at least one resource to save. error.planner.url.blank =In resource {0} URL can not be blank. error.planner.file.blank =In resource {0} file can not be blank. Index: lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/dbupdates/patch20160421.sql =================================================================== diff -u --- lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/dbupdates/patch20160421.sql (revision 0) +++ lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/dbupdates/patch20160421.sql (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -0,0 +1,15 @@ +-- Turn off autocommit, so nothing is committed if there is an error +SET AUTOCOMMIT = 0; +SET FOREIGN_KEY_CHECKS=0; +----------------------Put all sql statements below here------------------------- + +-- LDEV-3760 Add notification on file upload + +ALTER TABLE tl_larsrc11_resource ADD COLUMN file_upload_notify tinyint DEFAULT 0; + +----------------------Put all sql statements above here------------------------- + +-- If there were no errors, commit and restore autocommit to on +COMMIT; +SET AUTOCOMMIT = 1; +SET FOREIGN_KEY_CHECKS=1; \ No newline at end of file Index: lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/model/Resource.java =================================================================== diff -u -r08265d215705dc3f7e56e5cb4793bd28045a778b -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/model/Resource.java (.../Resource.java) (revision 08265d215705dc3f7e56e5cb4793bd28045a778b) +++ lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/model/Resource.java (.../Resource.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -23,19 +23,14 @@ /* $Id$ */ package org.lamsfoundation.lams.tool.rsrc.model; -import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.Iterator; -import java.util.List; import java.util.Set; -import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.log4j.Logger; -import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; -import org.lamsfoundation.lams.tool.rsrc.util.ResourceToolContentHandler; /** * Resource @@ -77,6 +72,8 @@ private boolean notifyTeachersOnAssigmentSumbit; + private boolean notifyTeachersOnFileUpload; + // general infomation private Date created; @@ -444,7 +441,6 @@ /** * @hibernate.property column="assigment_submit_notify" - * @return */ public boolean isNotifyTeachersOnAssigmentSumbit() { return notifyTeachersOnAssigmentSumbit; @@ -453,4 +449,15 @@ public void setNotifyTeachersOnAssigmentSumbit(boolean notifyTeachersOnAssigmentSumbit) { this.notifyTeachersOnAssigmentSumbit = notifyTeachersOnAssigmentSumbit; } -} + + /** + * @hibernate.property column="file_upload_notify" + */ + public boolean isNotifyTeachersOnFileUpload() { + return notifyTeachersOnFileUpload; + } + + public void setNotifyTeachersOnFileUpload(boolean notifyTeachersOnFileUpload) { + this.notifyTeachersOnFileUpload = notifyTeachersOnFileUpload; + } +} \ No newline at end of file Index: lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/rsrcApplicationContext.xml =================================================================== diff -u -ra6641bf9262a01d07740a517643f8fe187ec5b1f -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/rsrcApplicationContext.xml (.../rsrcApplicationContext.xml) (revision a6641bf9262a01d07740a517643f8fe187ec5b1f) +++ lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/rsrcApplicationContext.xml (.../rsrcApplicationContext.xml) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -119,7 +119,7 @@ PROPAGATION_REQUIRED,-java.lang.Exception PROPAGATION_REQUIRED,-java.lang.Exception PROPAGATION_REQUIRED,-java.lang.Exception - PROPAGATION_REQUIRED,-java.lang.Exception + PROPAGATION_REQUIRED,-java.lang.Exception PROPAGATION_REQUIRED,-java.lang.Exception PROPAGATION_REQUIRED,-java.lang.Exception PROPAGATION_REQUIRED,-java.lang.Exception Index: lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/service/IResourceService.java =================================================================== diff -u -r5e63656a12c02f7476564e278b43ff4ce86ac930 -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/service/IResourceService.java (.../IResourceService.java) (revision 5e63656a12c02f7476564e278b43ff4ce86ac930) +++ lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/service/IResourceService.java (.../IResourceService.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -258,6 +258,9 @@ void notifyTeachersOnAssigmentSumbit(Long sessionId, ResourceUser resourceUser); + void notifyTeachersOnFileUpload(Long toolContentId, Long toolSessionId, String sessionMapId, String userName, + Long itemUid, String fileName); + /** * Returns whether activity is grouped and therefore it is expected more than one tool session. * Index: lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/service/ResourceServiceImpl.java =================================================================== diff -u -r71012b6f2ac523d8faaef475332dbad1338c448d -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/service/ResourceServiceImpl.java (.../ResourceServiceImpl.java) (revision 71012b6f2ac523d8faaef475332dbad1338c448d) +++ lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/service/ResourceServiceImpl.java (.../ResourceServiceImpl.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -68,6 +68,7 @@ import org.lamsfoundation.lams.notebook.service.ICoreNotebookService; import org.lamsfoundation.lams.rest.RestTags; import org.lamsfoundation.lams.rest.ToolRestManager; +import org.lamsfoundation.lams.tool.ToolAccessMode; import org.lamsfoundation.lams.tool.ToolContentManager; import org.lamsfoundation.lams.tool.ToolOutput; import org.lamsfoundation.lams.tool.ToolOutputDefinition; @@ -85,6 +86,7 @@ import org.lamsfoundation.lams.tool.rsrc.dto.ResourceItemDTO; import org.lamsfoundation.lams.tool.rsrc.dto.SessionDTO; import org.lamsfoundation.lams.tool.rsrc.dto.VisitLogDTO; +import org.lamsfoundation.lams.tool.rsrc.ims.ImscpApplicationException; import org.lamsfoundation.lams.tool.rsrc.ims.SimpleContentPackageConverter; import org.lamsfoundation.lams.tool.rsrc.model.Resource; import org.lamsfoundation.lams.tool.rsrc.model.ResourceItem; @@ -100,9 +102,11 @@ import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.util.audit.IAuditService; import org.lamsfoundation.lams.util.zipfile.ZipFileUtil; import org.lamsfoundation.lams.util.zipfile.ZipFileUtilException; +import org.lamsfoundation.lams.web.util.AttributeNames; /** * @author Dapeng.Ni @@ -563,6 +567,23 @@ eventNotificationService.notifyLessonMonitors(sessionId, message, false); } + @Override + public void notifyTeachersOnFileUpload(Long toolContentId, Long toolSessionId, String sessionMapId, String userName, + Long itemUid, String fileName) { + String eventName = new StringBuilder("resources_file_upload_").append(toolContentId).append("_") + .append(System.currentTimeMillis()).toString(); + String url = new StringBuilder("") + .append(getLocalisedMessage("event.file.upload", new Object[] { userName, fileName })).append("") + .toString(); + eventNotificationService.createLessonEvent(IEventNotificationService.LESSON_MONITORS_SCOPE, eventName, + toolContentId, null, url, true, IEventNotificationService.DELIVERY_METHOD_NOTIFICATION); + } + // ***************************************************************************** // private methods // ***************************************************************************** @@ -1144,6 +1165,8 @@ resource.setMiniViewResourceNumber(JsonUtil.opt(toolContentJSON, "minViewResourceNumber", 0)); resource.setNotifyTeachersOnAssigmentSumbit( JsonUtil.opt(toolContentJSON, "notifyTeachersOnAssigmentSubmit", Boolean.FALSE)); + resource.setNotifyTeachersOnAssigmentSumbit( + JsonUtil.opt(toolContentJSON, "notifyTeachersOnFileUpload", Boolean.FALSE)); resource.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); resource.setReflectInstructions(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, (String) null)); resource.setRunAuto(JsonUtil.opt(toolContentJSON, "runAuto", Boolean.FALSE)); Index: lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/web/action/LearningAction.java =================================================================== diff -u -r199c9d26d57c7372cfb86f92018ab4c6fb9588dd -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/web/action/LearningAction.java (.../LearningAction.java) (revision 199c9d26d57c7372cfb86f92018ab4c6fb9588dd) +++ lams_tool_larsrc/src/java/org/lamsfoundation/lams/tool/rsrc/web/action/LearningAction.java (.../LearningAction.java) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -48,8 +48,6 @@ import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; -import org.lamsfoundation.lams.events.DeliveryMethodMail; -import org.lamsfoundation.lams.events.IEventNotificationService; import org.lamsfoundation.lams.learning.web.bean.ActivityPositionDTO; import org.lamsfoundation.lams.learning.web.util.LearningWebUtil; import org.lamsfoundation.lams.notebook.model.NotebookEntry; @@ -66,7 +64,6 @@ import org.lamsfoundation.lams.tool.rsrc.util.ResourceItemComparator; import org.lamsfoundation.lams.tool.rsrc.web.form.ReflectionForm; import org.lamsfoundation.lams.tool.rsrc.web.form.ResourceItemForm; -import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.util.FileUtil; import org.lamsfoundation.lams.util.FileValidatorUtil; @@ -86,6 +83,8 @@ private static Logger log = Logger.getLogger(LearningAction.class); + private static IResourceService resourceService; + @Override public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { @@ -162,7 +161,7 @@ // get back the resource and item list and display them on page IResourceService service = getResourceService(); ResourceUser resourceUser = null; - if (mode != null && mode.isTeacher()) { + if ((mode != null) && mode.isTeacher()) { // monitoring mode - user is specified in URL // resourceUser may be null if the user was force completed. resourceUser = getSpecifiedUser(service, sessionId, @@ -177,14 +176,14 @@ resource = service.getResourceBySessionId(sessionId); // check whehter finish lock is on/off - boolean lock = resource.getLockWhenFinished() && resourceUser != null && resourceUser.isSessionFinished(); + boolean lock = resource.getLockWhenFinished() && (resourceUser != null) && resourceUser.isSessionFinished(); // check whether there is only one resource item and run auto flag is true or not. boolean runAuto = false; int itemsNumber = 0; if (resource.getResourceItems() != null) { itemsNumber = resource.getResourceItems().size(); - if (resource.isRunAuto() && itemsNumber == 1) { + if (resource.isRunAuto() && (itemsNumber == 1)) { ResourceItem item = (ResourceItem) resource.getResourceItems().iterator().next(); // only visible item can be run auto. if (!item.isHide()) { @@ -209,7 +208,8 @@ sessionMap.put(ResourceConstants.ATTR_RESOURCE_INSTRUCTION, resource.getInstructions()); sessionMap.put(ResourceConstants.ATTR_FINISH_LOCK, lock); sessionMap.put(ResourceConstants.ATTR_LOCK_ON_FINISH, resource.getLockWhenFinished()); - sessionMap.put(ResourceConstants.ATTR_USER_FINISHED, resourceUser != null && resourceUser.isSessionFinished()); + sessionMap.put(ResourceConstants.ATTR_USER_FINISHED, + (resourceUser != null) && resourceUser.isSessionFinished()); sessionMap.put(AttributeNames.PARAM_TOOL_SESSION_ID, sessionId); sessionMap.put(AttributeNames.ATTR_MODE, mode); @@ -360,7 +360,7 @@ return mapping.findForward(ResourceConstants.ERROR); } item.setOpenUrlNewWindow(itemForm.isOpenUrlNewWindow()); - + } else if (type == ResourceConstants.RESOURCE_TYPE_URL) { item.setUrl(itemForm.getUrl()); item.setOpenUrlNewWindow(itemForm.isOpenUrlNewWindow()); @@ -392,7 +392,13 @@ if (resource.isNotifyTeachersOnAssigmentSumbit()) { service.notifyTeachersOnAssigmentSumbit(sessionId, resourceUser); } - + + if (resource.isNotifyTeachersOnFileUpload() && (type == ResourceConstants.RESOURCE_TYPE_FILE)) { + service.notifyTeachersOnFileUpload(resource.getContentId(), sessionId, sessionMapID, + resourceUser.getFirstName() + " " + resourceUser.getLastName(), item.getUid(), + itemForm.getFile().getFileName()); + } + return mapping.findForward(ResourceConstants.SUCCESS); } @@ -490,8 +496,8 @@ // if current user view less than reqired view count number, then just return error message. if (miniViewFlag > 0) { ActionErrors errors = new ActionErrors(); - errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("lable.learning.minimum.view.number.less", - miniViewFlag)); + errors.add(ActionMessages.GLOBAL_MESSAGE, + new ActionMessage("lable.learning.minimum.view.number.less", miniViewFlag)); this.addErrors(request, errors); return false; } @@ -500,9 +506,12 @@ } private IResourceService getResourceService() { - WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServlet() - .getServletContext()); - return (IResourceService) wac.getBean(ResourceConstants.RESOURCE_SERVICE); + if (LearningAction.resourceService == null) { + WebApplicationContext wac = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + LearningAction.resourceService = (IResourceService) wac.getBean(ResourceConstants.RESOURCE_SERVICE); + } + return LearningAction.resourceService; } /** @@ -616,11 +625,11 @@ // if(StringUtils.isBlank(itemForm.getDescription())) // errors.add(ActionMessages.GLOBAL_MESSAGE,new ActionMessage(ResourceConstants.ERROR_MSG_DESC_BLANK)); // } - if (itemForm.getItemType() == ResourceConstants.RESOURCE_TYPE_WEBSITE - || itemForm.getItemType() == ResourceConstants.RESOURCE_TYPE_LEARNING_OBJECT - || itemForm.getItemType() == ResourceConstants.RESOURCE_TYPE_FILE) { + if ((itemForm.getItemType() == ResourceConstants.RESOURCE_TYPE_WEBSITE) + || (itemForm.getItemType() == ResourceConstants.RESOURCE_TYPE_LEARNING_OBJECT) + || (itemForm.getItemType() == ResourceConstants.RESOURCE_TYPE_FILE)) { - if (itemForm.getFile() != null && FileUtil.isExecutableFile(itemForm.getFile().getFileName())) { + if ((itemForm.getFile() != null) && FileUtil.isExecutableFile(itemForm.getFile().getFileName())) { ActionMessage msg = new ActionMessage("error.attachment.executable"); errors.add(ActionMessages.GLOBAL_MESSAGE, msg); } @@ -630,7 +639,7 @@ // for edit validate: file already exist if (!itemForm.isHasFile() - && (itemForm.getFile() == null || StringUtils.isEmpty(itemForm.getFile().getFileName()))) { + && ((itemForm.getFile() == null) || StringUtils.isEmpty(itemForm.getFile().getFileName()))) { errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(ResourceConstants.ERROR_MSG_FILE_BLANK)); } } @@ -666,5 +675,4 @@ } } } - -} +} \ No newline at end of file Index: lams_tool_larsrc/web/pages/authoring/advance.jsp =================================================================== diff -u -r05ab55ef4acdc0c374af7405c58fb0e0fe8eb6b7 -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_tool_larsrc/web/pages/authoring/advance.jsp (.../advance.jsp) (revision 05ab55ef4acdc0c374af7405c58fb0e0fe8eb6b7) +++ lams_tool_larsrc/web/pages/authoring/advance.jsp (.../advance.jsp) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -73,6 +73,15 @@

+ + + +

+ +

Index: lams_tool_larsrc/web/pages/monitoring/advanceoptions.jsp =================================================================== diff -u -r73d41a9e127d790407deda8286fa5aa8182d8a1d -r94ed30ec071e295e4a2d469f02778c25f401ca41 --- lams_tool_larsrc/web/pages/monitoring/advanceoptions.jsp (.../advanceoptions.jsp) (revision 73d41a9e127d790407deda8286fa5aa8182d8a1d) +++ lams_tool_larsrc/web/pages/monitoring/advanceoptions.jsp (.../advanceoptions.jsp) (revision 94ed30ec071e295e4a2d469f02778c25f401ca41) @@ -107,6 +107,22 @@

+ + + + + + + + + + +