Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r34bc1c178bd5ada01543d5b4637487322d3ff565 -r3cccb9ba98efd5722b7365ffec582e2889143166 Binary files differ Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r2584207dba753ac8e61c06022694b202597775d9 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 2584207dba753ac8e61c06022694b202597775d9) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -93,6 +93,8 @@ index.kumalive =Kumalive index.kumalive.tooltip =Enter a live lesson index.kumalive.enter.learner =Enter as a learner +index.kumalive.report =Reports +index.kumalive.rubric =Rubrics management title.import.result =Import tool content result title.import =Import tool content title.import.instruction =Please choose LAMS sequence to import. Index: lams_central/conf/scss/_bootstrap-variables.scss =================================================================== diff -u -r375a15822889954a22d95bd07cd97a1c6e4c3d97 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_central/conf/scss/_bootstrap-variables.scss (.../_bootstrap-variables.scss) (revision 375a15822889954a22d95bd07cd97a1c6e4c3d97) +++ lams_central/conf/scss/_bootstrap-variables.scss (.../_bootstrap-variables.scss) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -289,7 +289,7 @@ // Small screen / tablet //** Deprecated `$screen-sm` as of v3.0.1 // $screen-sm: 768px -$screen-sm-min: 768px +$screen-sm-min: 768px; //** Deprecated `$screen-tablet` as of v3.0.1 // $screen-tablet: $screen-sm-min Index: lams_central/web/groupHeader.jsp =================================================================== diff -u -r3a30c9806be555d7cc8bff332abd27521cca4145 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_central/web/groupHeader.jsp (.../groupHeader.jsp) (revision 3a30c9806be555d7cc8bff332abd27521cca4145) +++ lams_central/web/groupHeader.jsp (.../groupHeader.jsp) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -65,6 +65,12 @@
  • +
  • + +
  • +
  • + +
  • Index: lams_central/web/includes/javascript/main.js =================================================================== diff -u -r3a30c9806be555d7cc8bff332abd27521cca4145 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_central/web/includes/javascript/main.js (.../main.js) (revision 3a30c9806be555d7cc8bff332abd27521cca4145) +++ lams_central/web/includes/javascript/main.js (.../main.js) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -534,6 +534,23 @@ }, true); } +function showKumaliveRubricsDialog(orgID){ + var id = "dialogKumaliveRubrics" + orgID; + showDialog(id, { + 'data' : { + 'orgID' : orgID + }, + 'height': Math.max(380, Math.min(650, $(window).height() - 30)), + 'width' : Math.max(380, Math.min(610, $(window).width() - 60)), + 'title' : LABELS.KUMALIVE_RUBRICS_TITLE, + 'open' : function() { + var orgID = $(this).data('orgID'); + // load contents after opening the dialog + $('iframe', this).attr('src', LAMS_URL + '/learning/kumalive.do?method=getRubrics&organisationID=' + orgID); + } + }, false); +} + function closeAddSingleActivityLessonDialog(action) { var id = 'dialogAddSingleActivityLesson', dialog = $('#' + id), Index: lams_central/web/includes/javascript/openUrls.js =================================================================== diff -u -r3a30c9806be555d7cc8bff332abd27521cca4145 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_central/web/includes/javascript/openUrls.js (.../openUrls.js) (revision 3a30c9806be555d7cc8bff332abd27521cca4145) +++ lams_central/web/includes/javascript/openUrls.js (.../openUrls.js) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -117,7 +117,7 @@ } function openKumalive(orgID, role) { - var kumaliveUrl = LAMS_URL + '/learning/kumalive.jsp?organisationID=' + orgID + '&role=' + role + var kumaliveUrl = LAMS_URL + '/learning/kumalive/kumalive.jsp?organisationID=' + orgID + '&role=' + role if (isMac) { kumaliveWin = window.open(kumaliveUrl,'kumaliveWindow','width=' + learner_width + ',height=' + learner_height + ',resizable,scrollbars=yes,status=yes'); Index: lams_central/web/main.jsp =================================================================== diff -u -r34bc1c178bd5ada01543d5b4637487322d3ff565 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_central/web/main.jsp (.../main.jsp) (revision 34bc1c178bd5ada01543d5b4637487322d3ff565) +++ lams_central/web/main.jsp (.../main.jsp) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -72,6 +72,8 @@ AUTHORING_TITLE : '', MONITORING_TITLE : '', + + KUMALIVE_RUBRICS_TITLE : '', PRIVATE_NOTIFICATIONS_TITLE : '', Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20170710.sql =================================================================== diff -u -r51a524d6c602ed95664f40f78dafa44dceac7bbb -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20170710.sql (.../patch20170710.sql) (revision 51a524d6c602ed95664f40f78dafa44dceac7bbb) +++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20170710.sql (.../patch20170710.sql) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -18,19 +18,31 @@ REFERENCES lams_user (user_id) ON DELETE SET NULL ON UPDATE CASCADE ); +CREATE TABLE lams_kumalive_rubric ( + rubric_id BIGINT(20) NOT NULL AUTO_INCREMENT + , organisation_id BIGINT(20) NOT NULL + , kumalive_id BIGINT(20) + , order_id TINYINT NOT NULL + , name VARCHAR(250) + , PRIMARY KEY (rubric_id) + , CONSTRAINT FK_lams_kumalive_rubric_1 FOREIGN KEY (organisation_id) + REFERENCES lams_organisation (organisation_id) ON DELETE CASCADE ON UPDATE CASCADE + , CONSTRAINT FK_lams_kumalive_rubric_2 FOREIGN KEY (kumalive_id) + REFERENCES lams_kumalive (kumalive_id) ON DELETE CASCADE ON UPDATE CASCADE +); + CREATE TABLE lams_kumalive_score ( score_id BIGINT(20) NOT NULL AUTO_INCREMENT - , kumalive_id BIGINT(20) NOT NULL + , rubric_id BIGINT(20) NOT NULL , user_id BIGINT(20) , score TINYINT , PRIMARY KEY (score_id) - , CONSTRAINT FK_lams_kumalive_score_1 FOREIGN KEY (kumalive_id) - REFERENCES lams_kumalive (kumalive_id) ON DELETE CASCADE ON UPDATE CASCADE + , CONSTRAINT FK_lams_kumalive_score_1 FOREIGN KEY (rubric_id) + REFERENCES lams_kumalive_rubric (rubric_id) ON DELETE CASCADE ON UPDATE CASCADE , CONSTRAINT FK_lams_kumalive_score_2 FOREIGN KEY (user_id) REFERENCES lams_user (user_id) ON DELETE CASCADE ON UPDATE CASCADE ); - -- If there were no errors, commit and restore autocommit to on SET FOREIGN_KEY_CHECKS=0; COMMIT; Index: lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/Kumalive.hbm.xml =================================================================== diff -u -r51a524d6c602ed95664f40f78dafa44dceac7bbb -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/Kumalive.hbm.xml (.../Kumalive.hbm.xml) (revision 51a524d6c602ed95664f40f78dafa44dceac7bbb) +++ lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/Kumalive.hbm.xml (.../Kumalive.hbm.xml) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -4,8 +4,7 @@ "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" > - + @@ -16,13 +15,19 @@ + class="org.lamsfoundation.lams.usermanagement.Organisation" not-null="true"> + + + + + + \ No newline at end of file Index: lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/KumaliveRubric.hbm.xml =================================================================== diff -u --- lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/KumaliveRubric.hbm.xml (revision 0) +++ lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/KumaliveRubric.hbm.xml (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/KumaliveScore.hbm.xml =================================================================== diff -u --- lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/KumaliveScore.hbm.xml (revision 0) +++ lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/KumaliveScore.hbm.xml (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file Index: lams_learning/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r2584207dba753ac8e61c06022694b202597775d9 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 2584207dba753ac8e61c06022694b202597775d9) +++ lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -108,6 +108,11 @@ label.group.confirm.header =Confirm group selection label.group.confirm.button =Confirm label.group.confirm.areyoujoining =Are you joining +label.kumalive.rubric.name =Enter rubric name +label.kumalive.rubric.up =Move rubric up +label.kumalive.rubric.down =Move rubric down +label.kumalive.rubric.delete =Delete rubric +label.kumalive.rubric.choose =Rubrics to use label.kumalive.title =Kumalive: label.kumalive.wait.start =Wait for a teacher to start Kumalive label.kumalive.name.enter =Enter a name for a new Kumalive @@ -121,7 +126,6 @@ label.kumalive.learners =Learners label.kumalive.teacher =Teacher label.kumalive.finish.speak =Finish speaking -label.kumalive.mark =Mark learner: label.kumalive.mark.great =Great! label.kumalive.mark.ok =Just OK label.kumalive.mark.bad =Not so good Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/KumaliveAction.java =================================================================== diff -u --- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/KumaliveAction.java (revision 0) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/KumaliveAction.java (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -0,0 +1,102 @@ +package org.lamsfoundation.lams.learning.kumalive; + +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.log4j.Logger; +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.lamsfoundation.lams.learning.kumalive.model.KumaliveRubric; +import org.lamsfoundation.lams.learning.kumalive.service.IKumaliveService; +import org.lamsfoundation.lams.security.ISecurityService; +import org.lamsfoundation.lams.usermanagement.Role; +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; + +/** + * @author Marcin Cieslak + */ +public class KumaliveAction extends DispatchAction { + + private static Logger log = Logger.getLogger(KumaliveAction.class); + + private static IKumaliveService kumaliveService; + private static ISecurityService securityService; + + public ActionForward getRubrics(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + UserDTO userDTO = getUserDTO(); + Integer userId = userDTO.getUserID(); + Integer organisationId = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID, false); + if (!KumaliveAction.getSecurityService().hasOrgRole(organisationId, userId, + new String[] { Role.GROUP_MANAGER, Role.MONITOR }, "kumalive get rubrics", false)) { + String warning = "User " + userId + " is not a monitor of organisation " + organisationId; + log.warn(warning); + response.sendError(HttpServletResponse.SC_FORBIDDEN, warning); + return null; + } + + List rubrics = KumaliveAction.getKumaliveService().getRubrics(organisationId); + JSONArray rubricsJSON = new JSONArray(); + for (KumaliveRubric rubric : rubrics) { + rubricsJSON.put(rubric.getName()); + } + request.setAttribute("rubrics", rubricsJSON); + + return mapping.findForward("displayRubrics"); + } + + public ActionForward saveRubrics(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException, JSONException { + UserDTO userDTO = getUserDTO(); + Integer userId = userDTO.getUserID(); + Integer organisationId = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID, false); + if (!KumaliveAction.getSecurityService().hasOrgRole(organisationId, userId, + new String[] { Role.GROUP_MANAGER, Role.MONITOR }, "kumalive get rubrics", false)) { + String warning = "User " + userId + " is not a monitor of organisation " + organisationId; + log.warn(warning); + response.sendError(HttpServletResponse.SC_FORBIDDEN, warning); + return null; + } + + JSONArray rubricsJSON = new JSONArray(WebUtil.readStrParam(request, "rubrics")); + KumaliveAction.getKumaliveService().saveRubrics(organisationId, rubricsJSON); + + return null; + } + + private UserDTO getUserDTO() { + HttpSession ss = SessionManager.getSession(); + return (UserDTO) ss.getAttribute(AttributeNames.USER); + } + + private static IKumaliveService getKumaliveService() { + if (kumaliveService == null) { + WebApplicationContext ctx = WebApplicationContextUtils + .getWebApplicationContext(SessionManager.getServletContext()); + kumaliveService = (IKumaliveService) ctx.getBean("kumaliveService"); + } + return kumaliveService; + } + + private static ISecurityService getSecurityService() { + if (securityService == null) { + WebApplicationContext ctx = WebApplicationContextUtils + .getRequiredWebApplicationContext(SessionManager.getServletContext()); + securityService = (ISecurityService) ctx.getBean("securityService"); + } + return securityService; + } +} \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/KumaliveWebsocketServer.java =================================================================== diff -u -r51a524d6c602ed95664f40f78dafa44dceac7bbb -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/KumaliveWebsocketServer.java (.../KumaliveWebsocketServer.java) (revision 51a524d6c602ed95664f40f78dafa44dceac7bbb) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/KumaliveWebsocketServer.java (.../KumaliveWebsocketServer.java) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -22,7 +22,8 @@ import org.apache.tomcat.util.json.JSONException; import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.learning.kumalive.model.Kumalive; -import org.lamsfoundation.lams.learning.service.ILearnerService; +import org.lamsfoundation.lams.learning.kumalive.model.KumaliveRubric; +import org.lamsfoundation.lams.learning.kumalive.service.IKumaliveService; import org.lamsfoundation.lams.security.ISecurityService; import org.lamsfoundation.lams.usermanagement.Role; import org.lamsfoundation.lams.usermanagement.User; @@ -34,7 +35,7 @@ import org.springframework.web.context.support.WebApplicationContextUtils; /** - * Processes messages for Kumalive + * Processes messages for Kumalive. * * @author Marcin Cieslak */ @@ -63,17 +64,24 @@ private final List raisedHand = new CopyOnWriteArrayList<>(); private Integer speaker; private final Map learners = new ConcurrentHashMap<>(); + private final JSONArray rubrics = new JSONArray(); - private KumaliveDTO(Kumalive kumalive) { + private KumaliveDTO(Kumalive kumalive) throws JSONException { this.id = kumalive.getKumaliveId(); this.name = kumalive.getName(); this.createdBy = kumalive.getCreatedBy().getUserDTO(); + for (KumaliveRubric rubric : kumalive.getRubrics()) { + JSONObject rubricJSON = new JSONObject(); + rubricJSON.put("id", rubric.getRubricId()); + rubricJSON.put("name", rubric.getName()); + rubrics.put(rubricJSON); + } } } - private static Logger log = Logger.getLogger(KumaliveWebsocketServer.class); + private static Logger logger = Logger.getLogger(KumaliveWebsocketServer.class); - private static ILearnerService learnerService; + private static IKumaliveService kumaliveService; private static ISecurityService securityService; private static IUserManagementService userManagementService; // mapping org ID -> Kumalive @@ -84,11 +92,11 @@ Integer organisationId = Integer .valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_ORGANISATION_ID).get(0)); Integer userId = getUser(websocket).getUserId(); - if (!getSecurityService().hasOrgRole(organisationId, userId, + if (!KumaliveWebsocketServer.getSecurityService().hasOrgRole(organisationId, userId, new String[] { Role.GROUP_MANAGER, Role.MONITOR, Role.LEARNER }, "register on kumalive", false)) { // prevent unauthorised user from accessing Kumalive String warning = "User " + userId + " is not a monitor nor a learner of organisation " + organisationId; - log.warn(warning); + logger.warn(warning); websocket.close(new CloseReason(CloseCodes.CANNOT_ACCEPT, warning)); } } @@ -102,7 +110,7 @@ Integer organisationId = Integer .valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_ORGANISATION_ID).get(0)); - KumaliveDTO kumalive = KumaliveWebsocketServer.kumalives.get(organisationId); + KumaliveDTO kumalive = kumalives.get(organisationId); if (kumalive == null) { return; } @@ -172,16 +180,18 @@ boolean isTeacher = false; if (kumaliveDTO == null) { String name = requestJSON.optString("name"); + JSONArray rubricsJSON = requestJSON.optJSONArray("rubrics"); String role = websocket.getRequestParameterMap().get(AttributeNames.PARAM_ROLE).get(0); User user = getUser(websocket); Integer userId = user.getUserId(); - isTeacher = !Role.LEARNER.equalsIgnoreCase(role) - && (getUserManagementService().isUserInRole(userId, organisationId, Role.GROUP_MANAGER) - || getUserManagementService().isUserInRole(userId, organisationId, Role.MONITOR)); + isTeacher = !Role.LEARNER.equalsIgnoreCase(role) && (KumaliveWebsocketServer.getUserManagementService() + .isUserInRole(userId, organisationId, Role.GROUP_MANAGER) + || KumaliveWebsocketServer.getUserManagementService().isUserInRole(userId, organisationId, + Role.MONITOR)); // if it kumalive does not exists and the user is not a teacher or he did not provide a name yet, // kumalive will not get created - Kumalive kumalive = KumaliveWebsocketServer.getLearnerService().startKumalive(organisationId, userId, name, - isTeacher && StringUtils.isNotBlank(name)); + Kumalive kumalive = KumaliveWebsocketServer.getKumaliveService().startKumalive(organisationId, userId, name, + rubricsJSON, isTeacher && StringUtils.isNotBlank(name)); if (kumalive != null) { kumaliveDTO = new KumaliveDTO(kumalive); kumalives.put(organisationId, kumaliveDTO); @@ -190,8 +200,22 @@ // tell teacher to provide a name for Kumalive and create it // or tell learner to join - websocket.getBasicRemote() - .sendText("{ \"type\" : \"" + (kumaliveDTO == null && isTeacher ? "create" : "join") + "\" }"); + JSONObject responseJSON = new JSONObject(); + if (kumaliveDTO == null && isTeacher) { + responseJSON.put("type", "create"); + List rubrics = KumaliveWebsocketServer.getKumaliveService().getRubrics(organisationId); + if (!rubrics.isEmpty()) { + JSONArray rubricsJSON = new JSONArray(); + for (KumaliveRubric rubric : rubrics) { + rubricsJSON.put(rubric.getName()); + } + responseJSON.put("rubrics", rubricsJSON); + } + + websocket.getBasicRemote().sendText(responseJSON.toString()); + } else { + websocket.getBasicRemote().sendText("{ \"type\" : \"join\" }"); + } } /** @@ -209,8 +233,10 @@ User user = getUser(websocket); Integer userId = user.getUserId(); String login = user.getLogin(); - boolean isTeacher = getUserManagementService().isUserInRole(userId, organisationId, Role.GROUP_MANAGER) - || getUserManagementService().isUserInRole(userId, organisationId, Role.MONITOR); + boolean isTeacher = KumaliveWebsocketServer.getUserManagementService().isUserInRole(userId, organisationId, + Role.GROUP_MANAGER) + || KumaliveWebsocketServer.getUserManagementService().isUserInRole(userId, organisationId, + Role.MONITOR); String role = websocket.getRequestParameterMap().get(AttributeNames.PARAM_ROLE).get(0); KumaliveUser learner = kumalive.learners.get(login); @@ -225,23 +251,35 @@ learner = new KumaliveUser(user, websocket, isTeacher, roleTeacher); kumalive.learners.put(login, learner); + sendInit(kumalive, learner); sendRefresh(kumalive); } - /** - * Send full Kumalive state to all learners and teachers - */ - private void sendRefresh(KumaliveDTO kumalive) throws JSONException, IOException { + private void sendInit(KumaliveDTO kumalive, KumaliveUser user) throws JSONException, IOException { JSONObject responseJSON = new JSONObject(); - responseJSON.put("type", "refresh"); + responseJSON.put("type", "init"); // Kumalive title responseJSON.put("name", kumalive.name); - + responseJSON.put("isTeacher", user.isTeacher); + responseJSON.put("roleTeacher", user.roleTeacher); // teacher details responseJSON.put("teacherId", kumalive.createdBy.getUserID()); responseJSON.put("teacherName", kumalive.createdBy.getFirstName() + " " + kumalive.createdBy.getLastName()); responseJSON.put("teacherPortraitUuid", kumalive.createdBy.getPortraitUuid()); + // rubric details + responseJSON.put("rubrics", kumalive.rubrics); + + user.websocket.getBasicRemote().sendText(responseJSON.toString()); + } + + /** + * Send full Kumalive state to all learners and teachers + */ + private void sendRefresh(KumaliveDTO kumalive) throws JSONException, IOException { + JSONObject responseJSON = new JSONObject(); + responseJSON.put("type", "refresh"); + // current state of question and speaker responseJSON.put("raiseHandPrompt", kumalive.raiseHandPrompt); if (!kumalive.raisedHand.isEmpty()) { @@ -277,11 +315,9 @@ if (participant.isTeacher) { // send extra information to teachers if (teacherResponseJSON == null) { - responseJSON.put("isTeacher", true); responseJSON.put("logins", logins); teacherResponseJSON = responseJSON; } - teacherResponseJSON.put("roleTeacher", participant.roleTeacher); channel.sendText(teacherResponseJSON.toString()); } else { channel.sendText(learnerResponse); @@ -300,14 +336,17 @@ User user = getUser(websocket); Integer userId = user.getUserId(); - if (!getSecurityService().hasOrgRole(organisationId, userId, new String[] { Role.GROUP_MANAGER, Role.MONITOR }, - "kumalive raise hand prompt", false)) { + if (!KumaliveWebsocketServer.getSecurityService().hasOrgRole(organisationId, userId, + new String[] { Role.GROUP_MANAGER, Role.MONITOR }, "kumalive raise hand prompt", false)) { String warning = "User " + userId + " is not a monitor of organisation " + organisationId; - log.warn(warning); + logger.warn(warning); return; } kumalive.raiseHandPrompt = true; + if (logger.isDebugEnabled()) { + logger.debug("Teacher " + userId + " asked a question in Kumalive " + kumalive.id); + } sendRefresh(kumalive); } @@ -322,15 +361,19 @@ User user = getUser(websocket); Integer userId = user.getUserId(); - if (!getSecurityService().hasOrgRole(organisationId, userId, new String[] { Role.GROUP_MANAGER, Role.MONITOR }, - "kumalive down hand prompt", false)) { + if (!KumaliveWebsocketServer.getSecurityService().hasOrgRole(organisationId, userId, + new String[] { Role.GROUP_MANAGER, Role.MONITOR }, "kumalive down hand prompt", false)) { String warning = "User " + userId + " is not a monitor of organisation " + organisationId; - log.warn(warning); + logger.warn(warning); return; } kumalive.raiseHandPrompt = false; kumalive.raisedHand.clear(); + if (logger.isDebugEnabled()) { + logger.debug("Teacher " + userId + " finished a question in Kumalive " + kumalive.id); + } + sendRefresh(kumalive); } @@ -345,15 +388,15 @@ User user = getUser(websocket); Integer userId = user.getUserId(); - if (!getSecurityService().hasOrgRole(organisationId, userId, + if (!KumaliveWebsocketServer.getSecurityService().hasOrgRole(organisationId, userId, new String[] { Role.GROUP_MANAGER, Role.MONITOR, Role.LEARNER }, "kumalive raise hand", false)) { String warning = "User " + userId + " is not a monitor nor a learner of organisation " + organisationId; - log.warn(warning); + logger.warn(warning); return; } if (!kumalive.raiseHandPrompt) { - log.warn("Raise hand prompt was not sent by teacher yet for organisation " + organisationId); + logger.warn("Raise hand prompt was not sent by teacher yet for organisation " + organisationId); return; } @@ -362,6 +405,10 @@ } kumalive.raisedHand.add(userId); + if (logger.isDebugEnabled()) { + logger.debug("Learner " + userId + " raised hand in Kumalive " + kumalive.id); + } + sendRefresh(kumalive); } @@ -376,10 +423,10 @@ User user = getUser(websocket); Integer userId = user.getUserId(); - if (!getSecurityService().hasOrgRole(organisationId, userId, + if (!KumaliveWebsocketServer.getSecurityService().hasOrgRole(organisationId, userId, new String[] { Role.GROUP_MANAGER, Role.MONITOR, Role.LEARNER }, "kumalive down hand", false)) { String warning = "User " + userId + " is not a monitor nor a learner of organisation " + organisationId; - log.warn(warning); + logger.warn(warning); return; } @@ -388,6 +435,9 @@ } kumalive.raisedHand.remove(userId); + if (logger.isDebugEnabled()) { + logger.debug("Learner " + userId + " put hand down in Kumalive " + kumalive.id); + } sendRefresh(kumalive); } @@ -403,10 +453,10 @@ User user = getUser(websocket); Integer userId = user.getUserId(); - if (!getSecurityService().hasOrgRole(organisationId, userId, new String[] { Role.GROUP_MANAGER, Role.MONITOR }, - "kumalive speak", false)) { + if (!KumaliveWebsocketServer.getSecurityService().hasOrgRole(organisationId, userId, + new String[] { Role.GROUP_MANAGER, Role.MONITOR }, "kumalive speak", false)) { String warning = "User " + userId + " is not a monitor of organisation " + organisationId; - log.warn(warning); + logger.warn(warning); return; } @@ -420,20 +470,27 @@ private void score(JSONObject requestJSON, Session websocket) throws IOException, JSONException { Integer organisationId = Integer .valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_ORGANISATION_ID).get(0)); - KumaliveDTO kumalive = kumalives.get(organisationId); User user = getUser(websocket); Integer userId = user.getUserId(); - if (!getSecurityService().hasOrgRole(organisationId, userId, new String[] { Role.GROUP_MANAGER, Role.MONITOR }, - "kumalive score", false)) { + if (!KumaliveWebsocketServer.getSecurityService().hasOrgRole(organisationId, userId, + new String[] { Role.GROUP_MANAGER, Role.MONITOR }, "kumalive score", false)) { String warning = "User " + userId + " is not a monitor of organisation " + organisationId; - log.warn(warning); + logger.warn(warning); return; } + Long rubricId = requestJSON.getLong("rubricId"); + Integer learnerId = requestJSON.getInt(AttributeNames.PARAM_USER_ID); + KumaliveWebsocketServer.getKumaliveService().scoreKumalive(rubricId, learnerId, + Short.valueOf(requestJSON.getString("score"))); - KumaliveWebsocketServer.getLearnerService().scoreKumalive(kumalive.id, - requestJSON.getInt(AttributeNames.PARAM_USER_ID), Short.valueOf(requestJSON.getString("score"))); + KumaliveDTO kumalive = kumalives.get(organisationId); + if (logger.isDebugEnabled()) { + logger.debug("Teacher " + userId + " marked rubric " + rubricId + " for learner " + learnerId + + " in Kumalive " + kumalive.id); + } + sendRefresh(kumalive); } @@ -448,34 +505,39 @@ User user = getUser(websocket); Integer userId = user.getUserId(); - if (!getSecurityService().hasOrgRole(organisationId, userId, new String[] { Role.GROUP_MANAGER, Role.MONITOR }, - "kumalive finish", false)) { + if (!KumaliveWebsocketServer.getSecurityService().hasOrgRole(organisationId, userId, + new String[] { Role.GROUP_MANAGER, Role.MONITOR }, "kumalive finish", false)) { String warning = "User " + userId + " is not a monitor of organisation " + organisationId; - log.warn(warning); + logger.warn(warning); return; } - KumaliveWebsocketServer.getLearnerService().finishKumalive(kumalive.id); + KumaliveWebsocketServer.getKumaliveService().finishKumalive(kumalive.id); kumalives.remove(organisationId); for (KumaliveUser participant : kumalive.learners.values()) { participant.websocket.getBasicRemote().sendText("{ \"type\" : \"finish\"}"); } + + if (logger.isDebugEnabled()) { + logger.debug("Teacher " + userId + " finished Kumalive " + kumalive.id); + } } private User getUser(Session websocket) { - return getUserManagementService().getUserByLogin(websocket.getUserPrincipal().getName()); + return KumaliveWebsocketServer.getUserManagementService() + .getUserByLogin(websocket.getUserPrincipal().getName()); } - private static ILearnerService getLearnerService() { - if (learnerService == null) { + private static IKumaliveService getKumaliveService() { + if (kumaliveService == null) { WebApplicationContext ctx = WebApplicationContextUtils .getWebApplicationContext(SessionManager.getServletContext()); - learnerService = (ILearnerService) ctx.getBean("learnerService"); + kumaliveService = (IKumaliveService) ctx.getBean("kumaliveService"); } - return learnerService; + return kumaliveService; } - private ISecurityService getSecurityService() { + private static ISecurityService getSecurityService() { if (securityService == null) { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(SessionManager.getServletContext()); @@ -484,7 +546,7 @@ return securityService; } - private IUserManagementService getUserManagementService() { + private static IUserManagementService getUserManagementService() { if (userManagementService == null) { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(SessionManager.getServletContext()); Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/dao/IKumaliveDAO.java =================================================================== diff -u -r51a524d6c602ed95664f40f78dafa44dceac7bbb -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/dao/IKumaliveDAO.java (.../IKumaliveDAO.java) (revision 51a524d6c602ed95664f40f78dafa44dceac7bbb) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/dao/IKumaliveDAO.java (.../IKumaliveDAO.java) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -23,11 +23,14 @@ package org.lamsfoundation.lams.learning.kumalive.dao; +import java.util.List; + import org.lamsfoundation.lams.dao.IBaseDAO; import org.lamsfoundation.lams.learning.kumalive.model.Kumalive; +import org.lamsfoundation.lams.learning.kumalive.model.KumaliveRubric; public interface IKumaliveDAO extends IBaseDAO { - Kumalive findByOrganisationId(Integer organisationId); + Kumalive findKumaliveByOrganisationId(Integer organisationId); - void saveScore(Long kumaliveId, Integer userId, Short score); + List findRubricsByOrganisationId(Integer organisationId); } \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/dao/hibernate/KumaliveDAO.java =================================================================== diff -u -r51a524d6c602ed95664f40f78dafa44dceac7bbb -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/dao/hibernate/KumaliveDAO.java (.../KumaliveDAO.java) (revision 51a524d6c602ed95664f40f78dafa44dceac7bbb) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/dao/hibernate/KumaliveDAO.java (.../KumaliveDAO.java) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -25,32 +25,29 @@ import java.util.List; -import org.hibernate.Query; import org.lamsfoundation.lams.dao.hibernate.LAMSBaseDAO; import org.lamsfoundation.lams.learning.kumalive.dao.IKumaliveDAO; import org.lamsfoundation.lams.learning.kumalive.model.Kumalive; +import org.lamsfoundation.lams.learning.kumalive.model.KumaliveRubric; import org.springframework.stereotype.Repository; @Repository public class KumaliveDAO extends LAMSBaseDAO implements IKumaliveDAO { - private static final String FIND_BY_ORGANISATION = "FROM " + Kumalive.class.getName() + private static final String FIND_KUMALIVE_BY_ORGANISATION = "FROM " + Kumalive.class.getName() + " AS k WHERE k.organisation.organisationId = ? AND k.finished = 0"; + private static final String FIND_RUBRICS_BY_ORGANISATION = "FROM " + KumaliveRubric.class.getName() + + " AS r WHERE r.organisation.organisationId = ? AND r.kumalive IS NULL ORDER BY r.orderId ASC"; - private static final String SAVE_SCORE_SQL = "INSERT INTO lams_kumalive_score VALUES (NULL, ?, ?, ?)"; - @Override @SuppressWarnings("unchecked") - public Kumalive findByOrganisationId(Integer organisationId) { - List result = (List) doFind(FIND_BY_ORGANISATION, organisationId); + public Kumalive findKumaliveByOrganisationId(Integer organisationId) { + List result = (List) doFind(FIND_KUMALIVE_BY_ORGANISATION, organisationId); return result.isEmpty() ? null : result.get(0); } + @SuppressWarnings("unchecked") @Override - public void saveScore(Long kumaliveId, Integer userId, Short score) { - Query query = getSession().createSQLQuery(SAVE_SCORE_SQL); - query.setLong(0, kumaliveId); - query.setInteger(1, userId); - query.setShort(2, score); - query.executeUpdate(); + public List findRubricsByOrganisationId(Integer organisationId) { + return (List) doFind(FIND_RUBRICS_BY_ORGANISATION, organisationId); } } \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/Kumalive.java =================================================================== diff -u -r51a524d6c602ed95664f40f78dafa44dceac7bbb -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/Kumalive.java (.../Kumalive.java) (revision 51a524d6c602ed95664f40f78dafa44dceac7bbb) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/Kumalive.java (.../Kumalive.java) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -23,6 +23,7 @@ package org.lamsfoundation.lams.learning.kumalive.model; import java.io.Serializable; +import java.util.Set; import org.lamsfoundation.lams.usermanagement.Organisation; import org.lamsfoundation.lams.usermanagement.User; @@ -36,6 +37,7 @@ private User createdBy; private String name; private Boolean finished = false; + private Set rubrics; public Kumalive() { } @@ -85,4 +87,12 @@ public void setFinished(Boolean finished) { this.finished = finished; } + + public Set getRubrics() { + return rubrics; + } + + public void setRubrics(Set rubrics) { + this.rubrics = rubrics; + } } \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/KumaliveRubric.java =================================================================== diff -u --- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/KumaliveRubric.java (revision 0) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/KumaliveRubric.java (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -0,0 +1,88 @@ +/*************************************************************************** + * 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.learning.kumalive.model; + +import java.io.Serializable; + +import org.lamsfoundation.lams.usermanagement.Organisation; + +public class KumaliveRubric implements Serializable { + + private static final long serialVersionUID = 1425357203513480609L; + + private Long rubricId; + private Organisation organisation; + private Kumalive kumalive; + private Short orderId; + private String name; + + public KumaliveRubric() { + } + + public KumaliveRubric(Organisation organisation, Kumalive kumalive, Short orderId, String name) { + this.organisation = organisation; + this.kumalive = kumalive; + this.orderId = orderId; + this.name = name; + } + + public Long getRubricId() { + return rubricId; + } + + public void setRubricId(Long rubricId) { + this.rubricId = rubricId; + } + + public Organisation getOrganisation() { + return organisation; + } + + public void setOrganisation(Organisation organisation) { + this.organisation = organisation; + } + + public Kumalive getKumalive() { + return kumalive; + } + + public void setKumalive(Kumalive kumalive) { + this.kumalive = kumalive; + } + + public Short getOrderId() { + return orderId; + } + + public void setOrderId(Short orderId) { + this.orderId = orderId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/KumaliveScore.java =================================================================== diff -u --- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/KumaliveScore.java (revision 0) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/KumaliveScore.java (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -0,0 +1,78 @@ +/*************************************************************************** + * 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 + * ***********************************************************************/ + +package org.lamsfoundation.lams.learning.kumalive.model; + +import java.io.Serializable; + +import org.lamsfoundation.lams.usermanagement.User; + +public class KumaliveScore implements Serializable { + + private static final long serialVersionUID = -5191089091527630037L; + + private Long scoreId; + private KumaliveRubric rubric; + private User user; + private Short score; + + public KumaliveScore() { + } + + public KumaliveScore(KumaliveRubric rubric, User user, Short score) { + this.rubric = rubric; + this.user = user; + this.score = score; + } + + public Long getScoreId() { + return scoreId; + } + + public void setScoreId(Long scoreId) { + this.scoreId = scoreId; + } + + public KumaliveRubric getRubric() { + return rubric; + } + + public void setRubric(KumaliveRubric rubric) { + this.rubric = rubric; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public Short getScore() { + return score; + } + + public void setScore(Short score) { + this.score = score; + } +} \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/IKumaliveService.java =================================================================== diff -u --- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/IKumaliveService.java (revision 0) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/IKumaliveService.java (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -0,0 +1,44 @@ +/**************************************************************** + * 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 + * **************************************************************** + */ + +package org.lamsfoundation.lams.learning.kumalive.service; + +import java.util.List; + +import org.apache.tomcat.util.json.JSONArray; +import org.apache.tomcat.util.json.JSONException; +import org.lamsfoundation.lams.learning.kumalive.model.Kumalive; +import org.lamsfoundation.lams.learning.kumalive.model.KumaliveRubric; + +public interface IKumaliveService { + Kumalive startKumalive(Integer organisationId, Integer userId, String name, JSONArray rubrics, boolean isTeacher) + throws JSONException; + + void finishKumalive(Long id); + + void scoreKumalive(Long rubricId, Integer userId, Short score); + + List getRubrics(Integer organisationId); + + void saveRubrics(Integer organisationId, JSONArray rubricsJSON) throws JSONException; +} \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/KumaliveService.java =================================================================== diff -u --- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/KumaliveService.java (revision 0) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/KumaliveService.java (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -0,0 +1,142 @@ +/**************************************************************** + * 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 + * **************************************************************** + */ + +package org.lamsfoundation.lams.learning.kumalive.service; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.apache.tomcat.util.json.JSONArray; +import org.apache.tomcat.util.json.JSONException; +import org.lamsfoundation.lams.learning.kumalive.dao.IKumaliveDAO; +import org.lamsfoundation.lams.learning.kumalive.model.Kumalive; +import org.lamsfoundation.lams.learning.kumalive.model.KumaliveRubric; +import org.lamsfoundation.lams.learning.kumalive.model.KumaliveScore; +import org.lamsfoundation.lams.security.ISecurityService; +import org.lamsfoundation.lams.usermanagement.Organisation; +import org.lamsfoundation.lams.usermanagement.User; + +public class KumaliveService implements IKumaliveService { + // --------------------------------------------------------------------- + // Instance variables + // --------------------------------------------------------------------- + private static Logger logger = Logger.getLogger(KumaliveService.class); + + private IKumaliveDAO kumaliveDAO; + private ISecurityService securityService; + + public void setSecurityService(ISecurityService securityService) { + this.securityService = securityService; + } + + public void setKumaliveDAO(IKumaliveDAO kumaliveDAO) { + this.kumaliveDAO = kumaliveDAO; + } + + /** + * Fetches or creates a Kumalive + * + * @throws JSONException + */ + @Override + public Kumalive startKumalive(Integer organisationId, Integer userId, String name, JSONArray rubricsJSON, + boolean isTeacher) throws JSONException { + if (isTeacher) { + securityService.isGroupMonitor(organisationId, userId, "start kumalive", true); + } + Kumalive kumalive = kumaliveDAO.findKumaliveByOrganisationId(organisationId); + if (kumalive == null) { + if (!isTeacher) { + return null; + } + } else { + return kumalive; + } + + Organisation organisation = (Organisation) kumaliveDAO.find(Organisation.class, organisationId); + User createdBy = (User) kumaliveDAO.find(User.class, userId); + kumalive = new Kumalive(organisation, createdBy, name); + kumaliveDAO.insert(kumalive); + + Set rubrics = new HashSet<>(); + if (rubricsJSON == null) { + KumaliveRubric rubric = new KumaliveRubric(organisation, kumalive, (short) 0, null); + kumaliveDAO.insert(rubric); + rubrics.add(rubric); + } else { + for (Short rubricIndex = 0; rubricIndex < rubricsJSON.length(); rubricIndex++) { + String rubricName = rubricsJSON.getString(rubricIndex.intValue()); + KumaliveRubric rubric = new KumaliveRubric(organisation, kumalive, rubricIndex, rubricName); + kumaliveDAO.insert(rubric); + rubrics.add(rubric); + } + } + kumalive.setRubrics(rubrics); + kumaliveDAO.update(kumalive); + + if (logger.isDebugEnabled()) { + logger.debug("Teacher " + userId + " started Kumalive " + kumalive.getKumaliveId()); + } + + return kumalive; + } + + /** + * Ends Kumalive + */ + @Override + public void finishKumalive(Long id) { + Kumalive kumalive = (Kumalive) kumaliveDAO.find(Kumalive.class, id); + kumalive.setFinished(true); + kumaliveDAO.update(kumalive); + } + + /** + * Save Kumalive score + */ + @Override + public void scoreKumalive(Long rubricId, Integer userId, Short score) { + KumaliveRubric rubric = (KumaliveRubric) kumaliveDAO.find(KumaliveRubric.class, rubricId); + User user = (User) kumaliveDAO.find(User.class, userId); + KumaliveScore kumaliveScore = new KumaliveScore(rubric, user, score); + kumaliveDAO.insert(kumaliveScore); + } + + @Override + public List getRubrics(Integer organisationId) { + return kumaliveDAO.findRubricsByOrganisationId(organisationId); + } + + @Override + public void saveRubrics(Integer organisationId, JSONArray rubricsJSON) throws JSONException { + Organisation organisation = (Organisation) kumaliveDAO.find(Organisation.class, organisationId); + kumaliveDAO.deleteByProperty(KumaliveRubric.class, "organisation", organisation); + for (Short rubricIndex = 0; rubricIndex < rubricsJSON.length(); rubricIndex++) { + String name = rubricsJSON.getString(rubricIndex.intValue()); + KumaliveRubric rubric = new KumaliveRubric(organisation, null, rubricIndex, name); + kumaliveDAO.insert(rubric); + } + } +} \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/learningApplicationContext.xml =================================================================== diff -u -r2584207dba753ac8e61c06022694b202597775d9 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/src/java/org/lamsfoundation/lams/learning/learningApplicationContext.xml (.../learningApplicationContext.xml) (revision 2584207dba753ac8e61c06022694b202597775d9) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/learningApplicationContext.xml (.../learningApplicationContext.xml) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -32,7 +32,7 @@ - + @@ -55,8 +55,6 @@ - - @@ -76,8 +74,30 @@ PROPAGATION_REQUIRED PROPAGATION_REQUIRED,readOnly PROPAGATION_REQUIRES_NEW - PROPAGATION_REQUIRED + + + + + + + + + + + + + + + + + + + + PROPAGATION_REQUIRED PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED + PROPAGATION_REQUIRED Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/ILearnerService.java =================================================================== diff -u -r2584207dba753ac8e61c06022694b202597775d9 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/ILearnerService.java (.../ILearnerService.java) (revision 2584207dba753ac8e61c06022694b202597775d9) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/ILearnerService.java (.../ILearnerService.java) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -27,7 +27,6 @@ import java.util.List; import org.lamsfoundation.lams.learning.command.model.Command; -import org.lamsfoundation.lams.learning.kumalive.model.Kumalive; import org.lamsfoundation.lams.learning.web.bean.ActivityPositionDTO; import org.lamsfoundation.lams.tool.ToolOutput; @@ -61,10 +60,4 @@ void createCommandForLearner(Long lessonId, String userName, String jsonCommand); List getCommandsForLesson(Long lessonId, Date laterThan); - - Kumalive startKumalive(Integer organisationId, Integer userId, String name, boolean isTeacher); - - void finishKumalive(Long id); - - void scoreKumalive(Long id, Integer userId, Short score); } Index: lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java =================================================================== diff -u -r51a524d6c602ed95664f40f78dafa44dceac7bbb -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 51a524d6c602ed95664f40f78dafa44dceac7bbb) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/service/LearnerService.java (.../LearnerService.java) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -39,8 +39,6 @@ import org.lamsfoundation.lams.gradebook.service.IGradebookService; import org.lamsfoundation.lams.learning.command.dao.ICommandDAO; import org.lamsfoundation.lams.learning.command.model.Command; -import org.lamsfoundation.lams.learning.kumalive.dao.IKumaliveDAO; -import org.lamsfoundation.lams.learning.kumalive.model.Kumalive; import org.lamsfoundation.lams.learning.progress.ProgressBuilder; import org.lamsfoundation.lams.learning.progress.ProgressEngine; import org.lamsfoundation.lams.learning.progress.ProgressException; @@ -83,7 +81,6 @@ import org.lamsfoundation.lams.lesson.service.LessonServiceException; import org.lamsfoundation.lams.logevent.LogEvent; import org.lamsfoundation.lams.logevent.service.ILogEventService; -import org.lamsfoundation.lams.security.ISecurityService; import org.lamsfoundation.lams.tool.Tool; import org.lamsfoundation.lams.tool.ToolCompletionStatus; import org.lamsfoundation.lams.tool.ToolOutput; @@ -92,7 +89,6 @@ import org.lamsfoundation.lams.tool.exception.RequiredGroupMissingException; import org.lamsfoundation.lams.tool.exception.ToolException; import org.lamsfoundation.lams.tool.service.ILamsCoreToolService; -import org.lamsfoundation.lams.usermanagement.Organisation; import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; @@ -115,15 +111,13 @@ private ProgressEngine progressEngine; private IDataFlowDAO dataFlowDAO; private ICommandDAO commandDAO; - private IKumaliveDAO kumaliveDAO; private ILamsCoreToolService lamsCoreToolService; private ActivityMapping activityMapping; private IUserManagementService userManagementService; private ILessonService lessonService; - private static HashMap syncMap = new HashMap<>(); + private static HashMap syncMap = new HashMap(); private IGradebookService gradebookService; private ILogEventService logEventService; - private ISecurityService securityService; // --------------------------------------------------------------------- // Inversion of Control Methods - Constructor injection @@ -224,10 +218,6 @@ this.logEventService = logEventService; } - public void setSecurityService(ISecurityService securityService) { - this.securityService = securityService; - } - // --------------------------------------------------------------------- // Service Methods // --------------------------------------------------------------------- @@ -774,7 +764,7 @@ private boolean forceGrouping(Lesson lesson, Grouping grouping, Group group, User learner) { boolean groupingDone = false; if (lesson.isPreviewLesson()) { - ArrayList learnerList = new ArrayList<>(); + ArrayList learnerList = new ArrayList(); learnerList.add(learner); if (group != null) { if (group.getGroupId() != null) { @@ -867,7 +857,7 @@ @Override public Set getGroupsForGate(GateActivity gate) { Lesson lesson = getLessonByActivity(gate); - Set result = new HashSet<>(); + Set result = new HashSet(); Activity branchActivity = gate.getParentBranch(); while ((branchActivity != null) && !(branchActivity.getParentActivity().isChosenBranchingActivity() @@ -919,7 +909,7 @@ * @return the lesson dto array. */ private LessonDTO[] getLessonDataFor(List lessons) { - List lessonDTOList = new ArrayList<>(); + List lessonDTOList = new ArrayList(); for (Iterator i = lessons.iterator(); i.hasNext();) { Lesson currentLesson = (Lesson) i.next(); lessonDTOList.add(new LessonDTO(currentLesson)); @@ -979,7 +969,7 @@ if (toolSession != null) { // Get all the conditions for this branching activity, ordered by order id. - Map conditionsMap = new TreeMap<>(); + Map conditionsMap = new TreeMap(); Iterator branchIterator = branchingActivity.getActivities().iterator(); while (branchIterator.hasNext()) { Activity branchActivity = (Activity) branchIterator.next(); @@ -996,7 +986,7 @@ // Go through each condition until we find one that passes and that is the required branch. // Cache the tool output so that we aren't calling it over an over again. - Map toolOutputMap = new HashMap<>(); + Map toolOutputMap = new HashMap(); Iterator conditionIterator = conditionsMap.keySet().iterator(); while ((matchedBranch == null) && conditionIterator.hasNext()) { @@ -1111,7 +1101,7 @@ // Go through each condition until we find one that passes and that opens the gate. // Cache the tool output so that we aren't calling it over an over again. - Map toolOutputMap = new HashMap<>(); + Map toolOutputMap = new HashMap(); for (BranchActivityEntry entry : conditionGate.getBranchActivityEntries()) { BranchCondition condition = entry.getCondition(); String conditionName = condition.getName(); @@ -1296,14 +1286,14 @@ this.dataFlowDAO = dataFlowDAO; } + public ICommandDAO getCommandDAO() { + return commandDAO; + } + public void setCommandDAO(ICommandDAO commandDAO) { this.commandDAO = commandDAO; } - public void setKumaliveDAO(IKumaliveDAO kumaliveDAO) { - this.kumaliveDAO = kumaliveDAO; - } - /** * Gets the concreted tool output (not the definition) from a tool. This method is called by target tool in order to * get data from source tool. @@ -1410,48 +1400,6 @@ return toolSession == null ? null : getActivityPosition(toolSession.getToolActivity().getActivityId()); } - /** - * Fetches or creates a Kumalive - */ - @Override - public Kumalive startKumalive(Integer organisationId, Integer userId, String name, boolean isTeacher) { - if (isTeacher) { - securityService.isGroupMonitor(organisationId, userId, "start kumalive", true); - } - Kumalive kumalive = kumaliveDAO.findByOrganisationId(organisationId); - if (kumalive == null) { - if (!isTeacher) { - return null; - } - } else { - return kumalive; - } - - Organisation organisation = (Organisation) kumaliveDAO.find(Organisation.class, organisationId); - User createdBy = (User) kumaliveDAO.find(User.class, userId); - kumalive = new Kumalive(organisation, createdBy, name); - kumaliveDAO.insert(kumalive); - return kumalive; - } - - /** - * Ends Kumalive - */ - @Override - public void finishKumalive(Long id) { - Kumalive kumalive = (Kumalive) kumaliveDAO.find(Kumalive.class, id); - kumalive.setFinished(true); - kumaliveDAO.update(kumalive); - } - - /** - * Save Kumalive score - */ - @Override - public void scoreKumalive(Long id, Integer userId, Short score) { - kumaliveDAO.saveScore(id, userId, score); - } - private boolean isActivityLast(Activity activity) { Transition transition = activity.getTransitionFrom(); while (transition != null) { @@ -1653,4 +1601,5 @@ public IActivityDAO getActivityDAO() { return activityDAO; } + } \ No newline at end of file Index: lams_learning/web/WEB-INF/struts-config.xml =================================================================== diff -u -r75496fa1baab1302fe097cce2183029e19285ebf -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision 75496fa1baab1302fe097cce2183029e19285ebf) +++ lams_learning/web/WEB-INF/struts-config.xml (.../struts-config.xml) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -363,7 +363,20 @@ redirect="false" /> - + + + + Index: lams_learning/web/css/kumalive.scss =================================================================== diff -u -r73ede1d25edfa50fa65a795350daf356ef5ba06a -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/web/css/kumalive.scss (.../kumalive.scss) (revision 73ede1d25edfa50fa65a795350daf356ef5ba06a) +++ lams_learning/web/css/kumalive.scss (.../kumalive.scss) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -15,10 +15,17 @@ font-weight: bold; } -#createKumaliveDiv input { +#createKumaliveDiv input[type="text"] { width: 60%; + display: inline; } +#createKumaliveDiv #rubrics { + display: inline-block; + text-align: left; + margin: 10px auto; +} + #mainDiv { display: none; } @@ -115,6 +122,7 @@ display: none; text-align: center; padding-top: 20px; + margin-bottom: 20px; } #raiseHandPrompt i { @@ -123,7 +131,6 @@ .score { display: none; - padding-top: 20px; } .score span { @@ -136,6 +143,10 @@ cursor: pointer; } +.scoreButtons { + text-align: center; +} + .scoreGood { color: green; } @@ -152,6 +163,10 @@ color: gray; } +.score:last-child hr { + display: none; +} + @media (min-width : $screen-sm-min) { #actionCell { width: 350px; Index: lams_learning/web/includes/javascript/kumalive.js =================================================================== diff -u -rba88d64806e27fb40451aee2520613ec2ec2d465 -r3cccb9ba98efd5722b7365ffec582e2889143166 --- lams_learning/web/includes/javascript/kumalive.js (.../kumalive.js) (revision ba88d64806e27fb40451aee2520613ec2ec2d465) +++ lams_learning/web/includes/javascript/kumalive.js (.../kumalive.js) (revision 3cccb9ba98efd5722b7365ffec582e2889143166) @@ -12,6 +12,8 @@ queuedMessage = null, // is there a learner speaking right now speakerId = null, + // rubrics to evaluate speaker + rubrics = null, // learners with no profile picture will get an icon with one of these colours learnerColors = ['#001f3f', '#FF851B', '#85144b', '#111111', '#3D9970', '#0074D9', '#FF4136'], // index of user icon colour currently used @@ -96,8 +98,24 @@ // hide splash screen $('#initDiv').hide(); // show name input - var createDiv = $('#createKumaliveDiv').show(), - createButton = createDiv.children('button').click(create).prop('disabled', true); + var createDiv = $('#createKumaliveDiv'), + rubricsDiv = $('#rubrics .panel-body', createDiv); + if (message.rubrics) { + $.each(message.rubrics, function(){ + if (this) { + var checkbox = $('
    ').addClass('checkbox').appendTo(rubricsDiv), + label = $('