Index: lams_learning/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r4f526e3455fe0ed91e6a838c833f1cd916844b98 -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 4f526e3455fe0ed91e6a838c833f1cd916844b98) +++ lams_learning/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -197,4 +197,8 @@ label.discussion.move.option.11 = Outside LOs (pls KIV to Post-Session) label.discussion.move.option.12 = Pls state key point(s) and move on label.discussion.move.option.13 = We already understand! -label.discussion.move.option.14 = Other \ No newline at end of file +label.discussion.move.option.14 = Other +label.discussion.votes = votes +label.discussion.votes.of.students = votes of {0} students +label.discussion.restart = Restart +label.discussion.stop = Stop \ No newline at end of file Index: lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/controller/DiscussionSentimentController.java =================================================================== diff -u -r4f526e3455fe0ed91e6a838c833f1cd916844b98 -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/controller/DiscussionSentimentController.java (.../DiscussionSentimentController.java) (revision 4f526e3455fe0ed91e6a838c833f1cd916844b98) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/controller/DiscussionSentimentController.java (.../DiscussionSentimentController.java) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -1,12 +1,17 @@ package org.lamsfoundation.lams.learning.discussion.controller; import java.io.IOException; +import java.util.Map; +import java.util.Set; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.lamsfoundation.lams.learning.discussion.model.DiscussionSentimentVote; import org.lamsfoundation.lams.learning.discussion.service.IDiscussionSentimentService; +import org.lamsfoundation.lams.lesson.service.ILessonService; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.beans.factory.annotation.Autowired; @@ -19,12 +24,19 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + @Controller @RequestMapping("/discussionSentiment") public class DiscussionSentimentController { @Autowired private IDiscussionSentimentService discussionSentimentService; + @Autowired + private ILessonService lessonService; + /** * Called via Page.tag. * Checks if there is a discussion running. If so, send the learner a command to show widget. @@ -85,19 +97,76 @@ return ResponseEntity.ok(discussionActive ? "voted" : "stop"); } - @RequestMapping(path = "/startMonitor", method = RequestMethod.POST) + /** + * Sends discussion IDs (question UID, burning question UID) + * where there is any data (active discussion, inactive discussion where someone voted). + * It is used to reinitialised discussion widgets on monitoring screen. + */ + @RequestMapping("/checkMonitor") @ResponseBody - public void startMonitorWidget(@RequestParam long toolQuestionUid, - @RequestParam(required = false) Long burningQuestionUid) { - discussionSentimentService.startDiscussionForMonitor(toolQuestionUid, burningQuestionUid); + public ResponseEntity checkMonitorWidget(@RequestParam long toolContentId) { + Set tokens = discussionSentimentService.getDiscussions(toolContentId); + + ArrayNode result = JsonNodeFactory.instance.arrayNode(); + for (DiscussionSentimentVote token : tokens) { + ObjectNode tokenJSON = JsonNodeFactory.instance.objectNode(); + tokenJSON.put("toolQuestionUid", token.getToolQuestionUid()); + tokenJSON.put("burningQuestionUid", token.getBurningQuestionUid()); + result.add(tokenJSON); + } + + return ResponseEntity.ok(result.toString()); } + /** + * Fetches details to build a monitor widget. + * If markAsActive is true, the monitor clicked "Start Discussion" or "Restart" button. + * If markAsActive is false, this is monitor widget reinitialising after page load. + */ + @RequestMapping("/startMonitor") + public String startMonitorWidget(@RequestParam long toolQuestionUid, + @RequestParam(required = false) Long burningQuestionUid, @RequestParam boolean markAsActive, Model model) { + Long lessonId = null; + if (markAsActive) { + lessonId = discussionSentimentService.startDiscussionForMonitor(toolQuestionUid, burningQuestionUid); + } else { + lessonId = discussionSentimentService.getLessonIdByQuestion(toolQuestionUid); + } + + int learnerCount = lessonService.getCountLessonLearners(lessonId, null); + model.addAttribute("learnerCount", learnerCount); + return "/discussion/monitor"; + } + @RequestMapping(path = "/stopMonitor", method = RequestMethod.POST) @ResponseBody public void stopMonitorWidget(@RequestParam long toolQuestionUid) { discussionSentimentService.stopDiscussionForMonitor(toolQuestionUid); } + /** + * Periodic refresh of discussion chart. + */ + @RequestMapping("/getMonitorData") + @ResponseBody + public ResponseEntity getMonitorData(@RequestParam long toolQuestionUid, + @RequestParam(required = false) Long burningQuestionUid) throws IOException { + Map votes = discussionSentimentService.getDiscussionAggregatedVotes(toolQuestionUid, + burningQuestionUid); + + DiscussionSentimentVote activeDiscussionToken = discussionSentimentService + .getActiveDiscussionByQuestion(toolQuestionUid); + ObjectNode response = JsonNodeFactory.instance.objectNode(); + // check if this discussion is active, so the widget knows if periodic refresh should keep running + response.put("isActive", + activeDiscussionToken != null && activeDiscussionToken.getToolQuestionUid().equals(toolQuestionUid) + && (activeDiscussionToken.getBurningQuestionUid() == null ? burningQuestionUid == null + : activeDiscussionToken.getBurningQuestionUid().equals(burningQuestionUid))); + response.set("votes", JsonUtil.readObject(votes)); + + return ResponseEntity.ok(response.toString()); + } + private static UserDTO getCurrentUserDto() { HttpSession ss = SessionManager.getSession(); return (UserDTO) ss.getAttribute(AttributeNames.USER); Index: lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/dao/IDiscussionSentimentDAO.java =================================================================== diff -u -r4f526e3455fe0ed91e6a838c833f1cd916844b98 -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/dao/IDiscussionSentimentDAO.java (.../IDiscussionSentimentDAO.java) (revision 4f526e3455fe0ed91e6a838c833f1cd916844b98) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/dao/IDiscussionSentimentDAO.java (.../IDiscussionSentimentDAO.java) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -1,6 +1,7 @@ package org.lamsfoundation.lams.learning.discussion.dao; import java.util.Map; +import java.util.Set; import org.lamsfoundation.lams.dao.IBaseDAO; import org.lamsfoundation.lams.learning.discussion.model.DiscussionSentimentVote; @@ -9,6 +10,8 @@ DiscussionSentimentVote getActiveDiscussion(long lessonId); + Set getDiscussions(long lessonId); + Map getDiscussionAggregatedVotes(long toolQuestionUid, Long burningQuestionUid); DiscussionSentimentVote getDiscussionVote(long toolQuestionUid, Long burningQuestionUid, int userId); Index: lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/dao/hibernate/DiscussionSentimentDAO.java =================================================================== diff -u -r4f526e3455fe0ed91e6a838c833f1cd916844b98 -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/dao/hibernate/DiscussionSentimentDAO.java (.../DiscussionSentimentDAO.java) (revision 4f526e3455fe0ed91e6a838c833f1cd916844b98) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/dao/hibernate/DiscussionSentimentDAO.java (.../DiscussionSentimentDAO.java) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -1,8 +1,10 @@ package org.lamsfoundation.lams.learning.discussion.dao.hibernate; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; @@ -14,13 +16,30 @@ private static final String FIND_ACTIVE_DISCUSSION = "FROM " + DiscussionSentimentVote.class.getName() + " WHERE lessonId = :lessonId AND userId IS NULL"; + private static final String FIND_ALL_LESSON_DISCUSSIONS = "SELECT toolQuestionUid FROM " + + DiscussionSentimentVote.class.getName() + " WHERE lessonId = :lessonId GROUP BY toolQuestionUid"; + @Override public DiscussionSentimentVote getActiveDiscussion(long lessonId) { return getSession().createQuery(FIND_ACTIVE_DISCUSSION, DiscussionSentimentVote.class) .setParameter("lessonId", lessonId).uniqueResult(); } @Override + @SuppressWarnings("unchecked") + public Set getDiscussions(long lessonId) { + List queryResult = getSession().createQuery(FIND_ALL_LESSON_DISCUSSIONS) + .setParameter("lessonId", lessonId).getResultList(); + Set result = new HashSet<>(); + + for (Long toolQuestionUid : queryResult) { + DiscussionSentimentVote token = new DiscussionSentimentVote(lessonId, toolQuestionUid, null); + result.add(token); + } + return result; + } + + @Override public Map getDiscussionAggregatedVotes(long toolQuestionUid, Long burningQuestionUid) { Map properties = new HashMap<>(); properties.put("toolQuestionUid", toolQuestionUid); Index: lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/service/DiscussionSentimentService.java =================================================================== diff -u -r4f526e3455fe0ed91e6a838c833f1cd916844b98 -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/service/DiscussionSentimentService.java (.../DiscussionSentimentService.java) (revision 4f526e3455fe0ed91e6a838c833f1cd916844b98) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/service/DiscussionSentimentService.java (.../DiscussionSentimentService.java) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -1,6 +1,7 @@ package org.lamsfoundation.lams.learning.discussion.service; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.lamsfoundation.lams.learning.discussion.dao.IDiscussionSentimentDAO; @@ -22,7 +23,7 @@ private static long ACTIVE_DISCUSSION_TOKEN_REFRESH_PERIOD = 5 * 1000; @Override - public void startDiscussionForMonitor(long toolQuestionUid, Long burningQuestionUid) { + public long startDiscussionForMonitor(long toolQuestionUid, Long burningQuestionUid) { long toolContentId = getToolContentId(toolQuestionUid); long lessonId = getLessonIdByToolContentId(toolContentId); // stop current discussion, if any @@ -42,6 +43,8 @@ jsonCommand.put("discussion", "startLearner"); learnerService.createCommandForLessonLearners(toolContentId, jsonCommand.toString()); + + return lessonId; } @Override @@ -121,10 +124,23 @@ } @Override - public Map getDiscussionAggregatedVotes(long lessonId, long toolContentId, Long burningQuestionUid) { - return discussionSentimentDAO.getDiscussionAggregatedVotes(toolContentId, burningQuestionUid); + public Set getDiscussions(long toolContentId) { + long lessonId = getLessonIdByToolContentId(toolContentId); + return discussionSentimentDAO.getDiscussions(lessonId); } + @Override + public Map getDiscussionAggregatedVotes(long toolQuestionUid, Long burningQuestionUid) { + return discussionSentimentDAO.getDiscussionAggregatedVotes(toolQuestionUid, burningQuestionUid); + } + + @Override + public DiscussionSentimentVote getActiveDiscussionByQuestion(long toolQuestionUid) { + long toolContentId = getToolContentId(toolQuestionUid); + long lessonId = getLessonIdByToolContentId(toolContentId); + return getCachedActiveDiscussion(lessonId); + } + private DiscussionSentimentVote getCachedActiveDiscussion(long lessonId) { Map cachedActiveDiscussion = cachedActiveDiscussionTokens.get(lessonId); @@ -164,6 +180,12 @@ return currentActiveDiscussionToken; } + @Override + public long getLessonIdByQuestion(long toolQuestionUid) { + long toolContentId = getToolContentId(toolQuestionUid); + return getLessonIdByToolContentId(toolContentId); + } + private long getToolContentId(long toolQuestionUid) { return discussionSentimentDAO.find(QbToolQuestion.class, toolQuestionUid).getToolContentId(); } Index: lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/service/IDiscussionSentimentService.java =================================================================== diff -u -r4f526e3455fe0ed91e6a838c833f1cd916844b98 -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/service/IDiscussionSentimentService.java (.../IDiscussionSentimentService.java) (revision 4f526e3455fe0ed91e6a838c833f1cd916844b98) +++ lams_learning/src/java/org/lamsfoundation/lams/learning/discussion/service/IDiscussionSentimentService.java (.../IDiscussionSentimentService.java) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -1,10 +1,13 @@ package org.lamsfoundation.lams.learning.discussion.service; import java.util.Map; +import java.util.Set; +import org.lamsfoundation.lams.learning.discussion.model.DiscussionSentimentVote; + public interface IDiscussionSentimentService { - void startDiscussionForMonitor(long toolQuestionUid, Long burningQuestionUid); + long startDiscussionForMonitor(long toolQuestionUid, Long burningQuestionUid); void stopDiscussionForMonitor(long toolQuestionUid); @@ -14,5 +17,11 @@ Integer getDiscussionVoteSelectedOption(long lessonId, int userId); - Map getDiscussionAggregatedVotes(long lessonId, long toolQuestionUid, Long burningQuestionUid); + Map getDiscussionAggregatedVotes(long toolQuestionUid, Long burningQuestionUid); + + DiscussionSentimentVote getActiveDiscussionByQuestion(long toolQuestionUid); + + Set getDiscussions(long toolContentId); + + long getLessonIdByQuestion(long toolQuestionUid); } \ No newline at end of file Index: lams_learning/web/discussion/learner.jsp =================================================================== diff -u -r4f526e3455fe0ed91e6a838c833f1cd916844b98 -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_learning/web/discussion/learner.jsp (.../learner.jsp) (revision 4f526e3455fe0ed91e6a838c833f1cd916844b98) +++ lams_learning/web/discussion/learner.jsp (.../learner.jsp) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -11,8 +11,8 @@ width: 40px; } - /* Underlining the link in title does not look nice*/ #discussion-sentiment-widget .panel-title a { + /* Underlining the link in title does not look nice*/ text-decoration: none !important; } @@ -22,6 +22,7 @@ } #discussion-sentiment-widget th { + /* Table headers feels better this way */ text-align: center; font-weight: bold; font-style: normal; @@ -39,6 +40,19 @@ $('#discussion-sentiment-widget-content').data('remove', true).collapse('hide'); } + function selectDiscussionSentimentOption(selectedOption) { + // clear other cells + var widget = $('#discussion-sentiment-widget'); + $('td', widget).removeClass('selected warning success'); + + if (!selectedOption) { + return; + } + // highlight the successfuly selected cell + var selectedCell = $('#discussion-sentiment-widget-option-cell-' + selectedOption, widget).addClass('selected'); + selectedCell.addClass(selectedCell.hasClass('discussion-sentiment-widget-option-stay') ? 'warning' : 'success'); + } + $(document).ready(function(){ let discussionSentimentWidget = $('#discussion-sentiment-widget'), discussionSentimentContent = $('#discussion-sentiment-widget-content', discussionSentimentWidget) @@ -94,17 +108,16 @@ stopDiscussionSentimentLearnerWidget(); } if (response == 'voted') { - // highlight the successfuly selected cell - $('#discussion-sentiment-widget td').removeClass('selected warning success'); - selectedCell.addClass('selected') - .addClass(selectedCell.hasClass('discussion-sentiment-widget-option-stay') ? 'warning' : 'success'); + selectDiscussionSentimentOption(selectedOption); } }, error : function(){ stopDiscussionSentimentLearnerWidget(); } }); }); + + selectDiscussionSentimentOption('${param.selectedOption}'); }); @@ -133,14 +146,14 @@ - <%-- Stay options start from 1, Move options start from 11 --%> - - + Index: lams_learning/web/discussion/monitor.jsp =================================================================== diff -u --- lams_learning/web/discussion/monitor.jsp (revision 0) +++ lams_learning/web/discussion/monitor.jsp (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -0,0 +1,295 @@ +<%@include file="/common/taglibs.jsp"%> + + + + + +
+
+
+ + + ( + + + + ) +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+ + ( ) + +
+ + +
+ + ( ) + +
+ + +
+
+
+
+
\ No newline at end of file Index: lams_learning/web/discussion/startLearner.jsp =================================================================== diff -u -r4f526e3455fe0ed91e6a838c833f1cd916844b98 -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_learning/web/discussion/startLearner.jsp (.../startLearner.jsp) (revision 4f526e3455fe0ed91e6a838c833f1cd916844b98) +++ lams_learning/web/discussion/startLearner.jsp (.../startLearner.jsp) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -6,7 +6,7 @@ $('
').attr('id', 'discussion-sentiment-widget').appendTo('body') .load("learning/discussion/learner.jsp?lessonId=${param.lessonId}&selectedOption=${selectedOption}"); } else { - // the widget already exists and monitor changed the topic, so clear out the selected option - $('#discussion-sentiment-widget td').removeClass('selected warning success'); + // the widget already exists and monitor changed the topic, so clear out the selected option and optionally set a new one + selectDiscussionSentimentOption('${selectedOption}'); } \ No newline at end of file Index: lams_monitoring/web/tblmonitor/tblmonitor.jsp =================================================================== diff -u -r403a0da00fe43c0d695b3f86c50fd891c34a735d -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_monitoring/web/tblmonitor/tblmonitor.jsp (.../tblmonitor.jsp) (revision 403a0da00fe43c0d695b3f86c50fd891c34a735d) +++ lams_monitoring/web/tblmonitor/tblmonitor.jsp (.../tblmonitor.jsp) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -12,6 +12,7 @@ + @@ -59,6 +64,19 @@ location.reload(); return false; } + + function startDiscussionSentiment(toolQuestionUid, markAsActive) { + $('#discussion-sentiment-chart-panel-container-' + toolQuestionUid).load( + '${lams}learning/discussionSentiment/startMonitor.do', + { + toolQuestionUid : toolQuestionUid, + markAsActive : markAsActive + }, + function(){ + $('#discussion-sentiment-start-button-' + toolQuestionUid).remove(); + } + ) + } $(document).ready(function() { $("time.timeago").timeago(); @@ -73,14 +91,25 @@ commandWebsocketHookTrigger = 'assessment-results-refresh-${assessment.contentId}'; // if the trigger is recognised, the following action occurs commandWebsocketHook = function() { - debugger; // delay reload by a period to prevent flood of reloads from students setTimeout(function(){ - debugger; location.reload(); }, Math.round(8000 * Math.random())); }; + + $.ajax({ + url : '${lams}learning/discussionSentiment/checkMonitor.do', + data : { + toolContentId : ${assessment.contentId} + }, + dataType : 'json', + success : function(result){ + result.forEach(function(discussion){ + startDiscussionSentiment(discussion.toolQuestionUid, false); + }); + } + }); }); @@ -90,25 +119,33 @@
- -
- <%-- Allow disclosing correct answers only for multiple choice questions --%> - -
+ + +
+ <%-- Allow disclosing correct answers only for multiple choice questions --%> + +
+ disabled="disabled">  + > + +
+
+
disabled="disabled">  > - +
- -
- disabled="disabled">  - > -
+ + +
+
@@ -239,6 +276,8 @@ + +
Index: lams_tool_assessment/web/pages/tblmonitoring/assessmentStudentChoices.jsp =================================================================== diff -u -r34765bdae65d16f9a5f085b48c841eaed4216883 -r0d458a161ee50dd2db8283520b80b5cc559705bf --- lams_tool_assessment/web/pages/tblmonitoring/assessmentStudentChoices.jsp (.../assessmentStudentChoices.jsp) (revision 34765bdae65d16f9a5f085b48c841eaed4216883) +++ lams_tool_assessment/web/pages/tblmonitoring/assessmentStudentChoices.jsp (.../assessmentStudentChoices.jsp) (revision 0d458a161ee50dd2db8283520b80b5cc559705bf) @@ -14,7 +14,6 @@ - -