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 = $('').appendTo(checkbox);
+ $('').text(this).appendTo(label);
+ $('').attr('type', 'checkbox')
+ .prependTo(label);
+ }
+ });
+ }
+ if (rubricsDiv.is(':empty')){
+ rubricsDiv.remove();
+ }
+
+ var createButton = createDiv.show().children('button').click(create).prop('disabled', true);
createDiv.children('input').focus().keyup(function(){
// name can not be empty
createButton.prop('disabled', !$(this).val());
@@ -111,12 +129,14 @@
}));
}
break;
- case 'refresh': {
+ case 'init' : {
if (!initialised) {
// it is the first refresh message ever
init(message);
}
-
+ }
+ break;
+ case 'refresh': {
if (refreshing) {
// set current message as the next one to be processed
queuedMessage = message;
@@ -156,7 +176,7 @@
}
// set dialog name
- $('#dialogKumaliveLabel', window.parent.document).text(LABELS.KUMALIVE_TITLE + ' ' + message.name);
+ $('head title').text(LABELS.KUMALIVE_TITLE + ' ' + message.name);
// set teacher portrait and name
if (message.teacherPortraitUuid) {
$('#actionCell #teacher .profilePicture').css('background-image',
@@ -166,6 +186,8 @@
}
$('#teacher .name').text(message.teacherName);
+ rubrics = message.rubrics;
+
// show proper work screen
$('#initDiv').hide();
$('#mainDiv').show();
@@ -401,13 +423,18 @@
speaker.remove();
if (roleTeacher) {
if ($('#actionCell .score[userId="' + speakerId + '"]').length == 0) {
- $('#score').clone(true).attr({
- 'id' : null,
- 'userId' : speakerId
- }).appendTo('#actionCell')
- .slideDown()
- .find('span')
- .text($('#learnersContainer .learner[userId="' + speakerId + '"] .name').text());
+ // create a score panel for each rubric
+ $.each(rubrics, function(){
+ $('#score').clone(true).attr({
+ 'id' : null,
+ 'userId' : speakerId,
+ 'rubricId' : this.id
+ }).appendTo('#actionCell')
+ .slideDown()
+ // user name and rubric
+ .find('p').html('' + $('#learnersContainer .learner[userId="' + speakerId + '"] .name').text() + ''
+ + (this.name ? '
' + this.name : ''));
+ });
}
speakerId = null;
} else if (message.raiseHandPrompt) {
@@ -552,7 +579,7 @@
*/
function score(){
var button = $(this),
- container = button.parent(),
+ container = button.closest('.score'),
score = null;
if (button.is('.scoreGood')) {
score = 2;
@@ -564,9 +591,10 @@
if (score !== null) {
kumaliveWebsocket.send(JSON.stringify({
- 'type' : 'score',
- 'userID' : container.attr('userId'),
- 'score' : score
+ 'type' : 'score',
+ 'userID' : container.attr('userId'),
+ 'rubricId' : container.attr('rubricId'),
+ 'score' : score
}));
}
@@ -580,12 +608,18 @@
* Create a new Kumalive
*/
function create(){
- var container = $('#createKumaliveDiv').hide(),
- name = $('input', container).val();
+ var createDiv = $('#createKumaliveDiv').hide(),
+ name = $('input', createDiv).val(),
+ rubrics = [];
+ // find checked rubrics and prepare them for serialization
+ $('#rubrics input:checked', createDiv).each(function(){
+ rubrics.push($(this).siblings('span').text());
+ });
kumaliveWebsocket.send(JSON.stringify({
- 'type' : 'start',
- 'role' : role,
- 'name' : name
+ 'type' : 'start',
+ 'role' : role,
+ 'name' : name,
+ 'rubrics' : rubrics.length > 0 ? rubrics : null
}));
}
Fisheye: Tag 3cccb9ba98efd5722b7365ffec582e2889143166 refers to a dead (removed) revision in file `lams_learning/web/kumalive.jsp'.
Fisheye: No comparison available. Pass `N' to diff?
Index: lams_learning/web/kumalive/kumalive.jsp
===================================================================
diff -u
--- lams_learning/web/kumalive/kumalive.jsp (revision 0)
+++ lams_learning/web/kumalive/kumalive.jsp (revision 3cccb9ba98efd5722b7365ffec582e2889143166)
@@ -0,0 +1,102 @@
+<%@ page contentType="text/html; charset=utf-8" language="java"%>
+
+<%@ taglib uri="tags-lams" prefix="lams"%>
+<%@ taglib uri="tags-fmt" prefix="fmt"%>
+<%@ taglib uri="tags-core" prefix="c"%>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ " class="scoreGood fa fa-smile-o">
+ " class="scoreNeutral fa fa-meh-o">
+ " class="scoreBad fa fa-frown-o">
+ " class="scoreNone fa fa-times">
+
+
+
+
+
+
+
+
+
\ No newline at end of file
Index: lams_learning/web/kumalive/kumaliveRubrics.jsp
===================================================================
diff -u
--- lams_learning/web/kumalive/kumaliveRubrics.jsp (revision 0)
+++ lams_learning/web/kumalive/kumaliveRubrics.jsp (revision 3cccb9ba98efd5722b7365ffec582e2889143166)
@@ -0,0 +1,134 @@
+
+
+<%@ page contentType="text/html; charset=utf-8" language="java"%>
+<%@ taglib uri="tags-lams" prefix="lams"%>
+<%@ taglib uri="tags-fmt" prefix="fmt"%>
+<%@ taglib uri="tags-core" prefix="c"%>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file