From 5e06079362a4068f41c4ba151614cfbfc46fcf50 Mon Sep 17 00:00:00 2001 From: Juan David Massanet Puentes <94039846+JuanDavid102@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:49:54 +0100 Subject: [PATCH] S2U-8 5.1.1.4 Tests & Quizzes: Tracking and reporting of delivery times for questions - fix --- .../impl/MicrosoftMessagingServiceImpl.java | 69 +++++++++----- .../webapp/WEB-INF/messaging-components.xml | 4 +- .../sass/modules/tool/samigo/_samigo.scss | 6 ++ .../MicrosoftAuthorizationServiceImpl.java | 4 - .../impl/MicrosoftCommonServiceImpl.java | 42 +++------ .../MicrosoftConfigurationServiceImpl.java | 4 - .../impl/MicrosoftLoggingServiceImpl.java | 4 - .../MicrosoftSynchronizationServiceImpl.java | 34 ++----- .../microsoft/impl/SakaiProxyImpl.java | 47 +++------- .../impl/src/webapp/WEB-INF/components.xml | 93 ++++++++++++------- .../bundle/EvaluationMessages.properties | 6 +- .../bundle/EvaluationMessages_ca.properties | 6 +- .../bundle/EvaluationMessages_es.properties | 6 +- .../bundle/EvaluationMessages_eu.properties | 6 +- .../HistogramQuestionScoresBean.java | 6 +- .../SubmitToGradingActionListener.java | 30 ++++-- .../evaluation/ExportReportServlet.java | 24 +++++ .../jsf/evaluation/gradeStudentResult.jsp | 4 +- .../webapp/jsf/evaluation/histogramScores.jsp | 6 +- 19 files changed, 208 insertions(+), 193 deletions(-) diff --git a/kernel/kernel-impl/src/main/java/org/sakaiproject/messaging/impl/MicrosoftMessagingServiceImpl.java b/kernel/kernel-impl/src/main/java/org/sakaiproject/messaging/impl/MicrosoftMessagingServiceImpl.java index fc555255f72c..efeae5f431fb 100644 --- a/kernel/kernel-impl/src/main/java/org/sakaiproject/messaging/impl/MicrosoftMessagingServiceImpl.java +++ b/kernel/kernel-impl/src/main/java/org/sakaiproject/messaging/impl/MicrosoftMessagingServiceImpl.java @@ -15,55 +15,78 @@ */ package org.sakaiproject.messaging.impl; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import javax.annotation.Resource; - import org.apache.ignite.IgniteMessaging; -import org.sakaiproject.ignite.EagerIgniteSpringBean; +import org.apache.ignite.IgniteSpringBean; +import org.apache.ignite.lang.IgniteBiPredicate; import org.sakaiproject.messaging.api.MicrosoftMessage; import org.sakaiproject.messaging.api.MicrosoftMessageListener; import org.sakaiproject.messaging.api.MicrosoftMessagingService; +import lombok.AllArgsConstructor; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; @Slf4j public class MicrosoftMessagingServiceImpl implements MicrosoftMessagingService { - @Resource - private EagerIgniteSpringBean ignite; - - private IgniteMessaging messaging; - + @Setter private IgniteSpringBean ignite; private ExecutorService executor; + private IgniteMessaging messaging; - public void init() { - log.info("Initializing Microsoft Messaging Service"); + private List messageTopics; - executor = Executors.newFixedThreadPool(20); + public MicrosoftMessagingServiceImpl() { + messageTopics = Collections.emptyList(); + } + + public void init() { + executor = Executors.newFixedThreadPool(10); messaging = ignite.message(ignite.cluster().forLocal()); } public void destroy() { - executor.shutdownNow(); + messageTopics.forEach(t -> messaging.stopLocalListen(t.topic, t.predicate)); + executor.shutdown(); } public void listen(MicrosoftMessage.Topic topic, MicrosoftMessageListener listener) { - messaging.localListen(topic, (nodeId, message) -> { - executor.execute(() -> { - listener.read((MicrosoftMessage)message); - }); - return true; - }); + if (topic != null && listener != null) { + MessageTopic messageTopic = new MessageTopic(topic, (nodeId, message) -> { + executor.execute(() -> listener.read((MicrosoftMessage) message)); + return true; + }); + + List updatedTopics = new ArrayList<>(messageTopics); + messaging.localListen(messageTopic.topic, messageTopic.predicate); + updatedTopics.add(messageTopic); + messageTopics = Collections.unmodifiableList(updatedTopics); + } else { + log.warn("Unable to register listener for topic [{}]", topic); + } } public void send(MicrosoftMessage.Topic topic, MicrosoftMessage msg) { - try { - messaging.send(topic, msg); - } catch(Exception e) { - log.error("Error sending MicrosoftMessage"); - } + if (topic != null && msg != null) { + try { + messaging.send(topic, msg); + } catch (Exception e) { + log.warn("Could not send message for topic [{}], message [{}], {}", topic, msg, e.toString()); + } + } else { + log.debug("skip sending message for topic [{}], {}", topic, msg); + } } + @AllArgsConstructor + private class MessageTopic { + private MicrosoftMessage.Topic topic; + private IgniteBiPredicate predicate; + } } diff --git a/kernel/kernel-impl/src/main/webapp/WEB-INF/messaging-components.xml b/kernel/kernel-impl/src/main/webapp/WEB-INF/messaging-components.xml index 25da25ade1ee..026932216898 100644 --- a/kernel/kernel-impl/src/main/webapp/WEB-INF/messaging-components.xml +++ b/kernel/kernel-impl/src/main/webapp/WEB-INF/messaging-components.xml @@ -10,7 +10,9 @@ + init-method="init" + destroy-method="destroy"> + disabledGroupListeners = ConcurrentHashMap.newKeySet(); @@ -99,8 +83,6 @@ public class MicrosoftSynchronizationServiceImpl implements MicrosoftSynchroniza private ConcurrentHashMap newGroupLock = new ConcurrentHashMap<>(); public void init() { - log.info("Initializing MicrosoftSynchService Service"); - microsoftMessagingService.listen(MicrosoftMessage.Topic.CREATE_ELEMENT, message -> { printMessage(MicrosoftMessage.Topic.CREATE_ELEMENT, message); elementCreated(message); diff --git a/microsoft-integration/impl/src/main/java/org/sakaiproject/microsoft/impl/SakaiProxyImpl.java b/microsoft-integration/impl/src/main/java/org/sakaiproject/microsoft/impl/SakaiProxyImpl.java index a7dcd7415b70..1e4e23b98ce3 100644 --- a/microsoft-integration/impl/src/main/java/org/sakaiproject/microsoft/impl/SakaiProxyImpl.java +++ b/microsoft-integration/impl/src/main/java/org/sakaiproject/microsoft/impl/SakaiProxyImpl.java @@ -67,43 +67,18 @@ @Transactional public class SakaiProxyImpl implements SakaiProxy { - @Autowired - private SecurityService securityService; - - @Autowired - private SiteService siteService; - - @Autowired - private ToolManager toolManager; - - @Autowired - private UserDirectoryService userDirectoryService; - - @Autowired - private SessionManager sessionManager; - - @Autowired - private PreferencesService preferencesService; - - @Autowired - private CalendarService calendarService; - - @Autowired - private TimeService timeService; - - @Setter - private UserTimeService userTimeService; - - @Autowired - private EmailService emailService; - - @Autowired - private ServerConfigurationService serverConfigurationService; + @Setter private CalendarService calendarService; + @Setter private EmailService emailService; + @Setter private PreferencesService preferencesService; + @Setter private SecurityService securityService; + @Setter private ServerConfigurationService serverConfigurationService; + @Setter private SessionManager sessionManager; + @Setter private SiteService siteService; + @Setter private TimeService timeService; + @Setter private ToolManager toolManager; + @Setter private UserDirectoryService userDirectoryService; + @Setter private UserTimeService userTimeService; - public void init() { - log.info("Initializing Sakai Proxy"); - } - // ------------------------------------------ SECURITY ---------------------------------------------------- @Override public boolean isAdmin() { diff --git a/microsoft-integration/impl/src/webapp/WEB-INF/components.xml b/microsoft-integration/impl/src/webapp/WEB-INF/components.xml index dd9f8adda8b4..1564ab255e9a 100644 --- a/microsoft-integration/impl/src/webapp/WEB-INF/components.xml +++ b/microsoft-integration/impl/src/webapp/WEB-INF/components.xml @@ -49,54 +49,75 @@ - - - - - + + + + + + + + + - + - - - - - + + + + + - - - - + + + + - - - + + + + + + + + + + + + + - - - + + + - - - + + + - + - - - - - + + + + + - - - + class="org.sakaiproject.component.app.scheduler.jobs.SpringStatefulJobBeanWrapper"> + + + diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages.properties b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages.properties index 1f491d782a51..e528c2a21e5d 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages.properties +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages.properties @@ -404,9 +404,9 @@ fixed_random_draw_info=(fixed draw, {0} questions and random draw, {1} questions # S2U-8 t_sortTimeElapsed=Sort by Time Elapsed time_elapsed=Time Elapsed -time_min=Minimum time: -time_avg=Average time: -time_max=Maximum time: +time_min=Minimum time +time_avg=Average time +time_max=Maximum time timeStats_title=Time elapsed per response timeStatsVariation_title=Variation questionVariation_title=Variation of students who have obtained more than a {0} in the score ({1} submitted) diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_ca.properties b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_ca.properties index 60d005beed22..bb4eab52b2f5 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_ca.properties +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_ca.properties @@ -401,9 +401,9 @@ fixed_random_draw_info=(elecci\u00f3 fixa, {0} preguntes i selecci\u00f3 aleat\u # S2U-8 t_sortTimeElapsed=Ordenar per Temps Emprat time_elapsed=Temps Emprat -time_min=Temps m\u00ednim: -time_avg=Temps mitj\u00e0: -time_max=Temps m\u00e0xim: +time_min=Temps m\u00ednim +time_avg=Temps mitj\u00e0 +time_max=Temps m\u00e0xim timeStats_title=Temps transcorregut per resposta timeStatsVariation_title=Variaci\u00f3 questionVariation_title=Variaci\u00f3 d'estudiants que han obtingut m\u00e9s d'un {0} en la puntuaci\u00f3 ({1} enviada) diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_es.properties b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_es.properties index fff88859e819..d583de02f1fa 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_es.properties +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_es.properties @@ -401,9 +401,9 @@ fixed_random_draw_info=(modo fijo, {0} preguntas, modo aleatorio, {1} de {2} pre # S2U-8 t_sortTimeElapsed=Ordenar por Tiempo Empleado time_elapsed=Tiempo Empleado -time_min=Tiempo m\u00ednimo: -time_avg=Tiempo medio: -time_max=Tiempo m\u00e1ximo: +time_min=Tiempo m\u00ednimo +time_avg=Tiempo medio +time_max=Tiempo m\u00e1ximo timeStats_title=Tiempo transcurrido por respuesta timeStatsVariation_title=Variaci\u00f3n questionVariation_title=Variaci\u00f3n de los alumnos que han sacado mas de un {0} de la puntuaci\u00f3n ({1} env\u00edos) diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_eu.properties b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_eu.properties index 57372dedd54f..d4e0b30d3dd7 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_eu.properties +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/bundle/EvaluationMessages_eu.properties @@ -375,9 +375,9 @@ fixed_random_draw_info=(finkoak {0} galdera dira, eta ausazkoak {1} galdera dira # S2U-8 t_sortTimeElapsed=Ordenatu erabilitako denboraren arabera time_elapsed=Erabilitako denbora -time_min=Gutxieneko denbora: -time_avg=Batez besteko denbora: -time_max=Gehienezko denbora: +time_min=Gutxieneko denbora +time_avg=Batez besteko denbora +time_max=Gehienezko denbora timeStats_title=Erantzun bakoitzeko igarotako denbora timeStatsVariation_title=Aldakuntza questionVariation_title=Puntuazioan {0} bat baino gehiago lortu duten ikasleen aldakuntza ({1} bidalitakoak) diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/evaluation/HistogramQuestionScoresBean.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/evaluation/HistogramQuestionScoresBean.java index c810814aa87e..0773de54021e 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/evaluation/HistogramQuestionScoresBean.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/bean/evaluation/HistogramQuestionScoresBean.java @@ -1259,9 +1259,9 @@ public ArrayList getTimeStatsArray() { } ArrayList timeStringArray = new ArrayList<>(); - timeStringArray.add(new String[]{evaluationMessages.getString("time_min"), TimeUtil.getFormattedTime(timeStatsArray.get(1))}); - timeStringArray.add(new String[]{evaluationMessages.getString("time_avg"), TimeUtil.getFormattedTime(timeStatsArray.get(0))}); - timeStringArray.add(new String[]{evaluationMessages.getString("time_max"), TimeUtil.getFormattedTime(timeStatsArray.get(2))}); + timeStringArray.add(new String[]{evaluationMessages.getString("time_min") + ":", TimeUtil.getFormattedTime(timeStatsArray.get(1))}); + timeStringArray.add(new String[]{evaluationMessages.getString("time_avg") + ":", TimeUtil.getFormattedTime(timeStatsArray.get(0))}); + timeStringArray.add(new String[]{evaluationMessages.getString("time_max") + ":", TimeUtil.getFormattedTime(timeStatsArray.get(2))}); return timeStringArray; } diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/delivery/SubmitToGradingActionListener.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/delivery/SubmitToGradingActionListener.java index 6b775c7e39de..d97561281794 100755 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/delivery/SubmitToGradingActionListener.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/listener/delivery/SubmitToGradingActionListener.java @@ -657,7 +657,7 @@ private void prepareItemGradingPerItem(ActionEvent ae, DeliveryBean delivery, || itemgrading.getAttemptDate() != null) { // null=> skipping this question itemgrading.setAgentId(AgentFacade.getAgentString()); - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); if (itemgrading.getRationale() != null && itemgrading.getRationale().length() > 0) { itemgrading.setRationale(TextFormat.convertPlaintextToFormattedTextNoHighUnicode(itemgrading.getRationale())); } @@ -678,7 +678,7 @@ private void prepareItemGradingPerItem(ActionEvent ae, DeliveryBean delivery, for (int m = 0; m < grading.size(); m++) { ItemGradingData itemgrading = grading.get(m); itemgrading.setAgentId(AgentFacade.getAgentString()); - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); } for (int m = 0; m < grading.size(); m++) { ItemGradingData itemgrading = grading.get(m); @@ -694,7 +694,7 @@ private void prepareItemGradingPerItem(ActionEvent ae, DeliveryBean delivery, for (int m = 0; m < grading.size(); m++) { ItemGradingData itemgrading = grading.get(m); itemgrading.setAgentId(AgentFacade.getAgentString()); - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); } for (int m = 0; m < grading.size(); m++) { ItemGradingData itemgrading = grading.get(m); @@ -717,7 +717,7 @@ private void prepareItemGradingPerItem(ActionEvent ae, DeliveryBean delivery, for (int m = 0; m < grading.size(); m++) { ItemGradingData itemgrading = grading.get(m); itemgrading.setAgentId(AgentFacade.getAgentString()); - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); } int fakeitemgrading=-1; for (int m = 0; m < grading.size(); m++) { @@ -760,7 +760,7 @@ else if (s != null) { if (itemgrading.getPublishedAnswerId() != null || (itemgrading.getRationale() != null && !itemgrading.getRationale().trim().equals(""))) { itemgrading.setAgentId(AgentFacade.getAgentString()); - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); adds.add(itemgrading); } else { removes.add(itemgrading); @@ -771,7 +771,7 @@ else if (s != null) { (itemgrading.getRationale() != null && !itemgrading.getRationale().trim().equals(""))) { // new addition not accepting any new answer with null for MCMR itemgrading.setAgentId(AgentFacade.getAgentString()); - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); adds.add(itemgrading); } } @@ -789,7 +789,7 @@ else if (s != null) { // old answer, check which one to keep, not keeping null answer if (itemgrading.getPublishedAnswerId() != null) { itemgrading.setAgentId(AgentFacade.getAgentString()); - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); adds.add(itemgrading); log.debug("adding answer: " + itemgrading.getItemGradingId()); } else if((!item.isTimedQuestion() && !delivery.isTrackingQuestions()) || grading.size() > 1){ @@ -801,7 +801,7 @@ else if (s != null) { if (itemgrading.getPublishedAnswerId() != null) { // new addition not accepting any new answer with null for EMI itemgrading.setAgentId(AgentFacade.getAgentString()); - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); adds.add(itemgrading); log.debug("adding new answer answer: " + itemgrading.getItemGradingId()); } @@ -834,7 +834,7 @@ else if (s != null) { for(MediaData md : medias) { delivery.getSubmissionFiles().put(itemgrading.getItemGradingId()+"_"+md.getMediaId(), md); } - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); grading.set(m, itemgrading); } } @@ -869,7 +869,7 @@ else if (s != null) { if (itemgrading !=null && (itemgrading.getPublishedAnswerId() != null || itemgrading.getAnswerText() != null || (itemgrading.getRationale() != null && StringUtils.isNotBlank(itemgrading.getRationale())))) { itemgrading.setAgentId(AgentFacade.getAgentString()); - itemgrading.setSubmittedDate(new Date()); + verifySubmittedDateInItemGrading(item, itemgrading); if (itemgrading.getRationale() != null && itemgrading.getRationale().length() > 0) { itemgrading.setRationale(TextFormat.convertPlaintextToFormattedTextNoHighUnicode(itemgrading.getRationale())); } @@ -932,6 +932,16 @@ else if (s != null) { alladds.addAll(adds); } + public void verifySubmittedDateInItemGrading(ItemContentsBean item, ItemGradingData itemgrading) { + int currentTimeInSeconds = 0; + if (itemgrading.getAttemptDate() != null) { + currentTimeInSeconds = (int) ((new Date()).getTime()/1000 - itemgrading.getAttemptDate().getTime()/1000); + } + if (item.getTimeLimit().equals("false") || Integer.parseInt(item.getTimeLimit()) >= currentTimeInSeconds) { + itemgrading.setSubmittedDate(new Date()); + } + return itemgrading; + } /** * Identify the items in an EMI Answer that are orphaned * @param grading diff --git a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/servlet/evaluation/ExportReportServlet.java b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/servlet/evaluation/ExportReportServlet.java index ca95ce281247..6c41a9d70aa0 100644 --- a/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/servlet/evaluation/ExportReportServlet.java +++ b/samigo/samigo-app/src/java/org/sakaiproject/tool/assessment/ui/servlet/evaluation/ExportReportServlet.java @@ -320,6 +320,24 @@ private AssessmentReport statisticsReport(String title, String subject, Histogra } private List statisticsHeader(HistogramScoresBean histogramScoresBean) { + if(histogramScoresBean.isTrackingQuestion()) { + return Stream.of( + "sub_view", + "tot_score_possible", + "mean_eq", + "median", + "mode", + "range_eq", + "time_min", + "time_avg", + "time_max", + "qtile_1_eq", + "qtile_3_eq", + "std_dev", + "skew_coef" + ).map(EVALUATION_BUNDLE::getFormattedMessage).collect(Collectors.toList()); + } + return Stream.of( "sub_view", "tot_score_possible", @@ -343,6 +361,12 @@ private List> statisticsData(HistogramScoresBean histogramScoresBea dataRow.add(histogramScoresBean.getMedian()); dataRow.add(histogramScoresBean.getMode()); dataRow.add(histogramScoresBean.getRange()); + if (histogramScoresBean.isTrackingQuestion()) { + String[] timeStats = histogramScoresBean.getTimeStats(); + dataRow.add(timeStats[0]); + dataRow.add(timeStats[1]); + dataRow.add(timeStats[2]); + } dataRow.add(histogramScoresBean.getQ1()); dataRow.add(histogramScoresBean.getQ3()); dataRow.add(histogramScoresBean.getStandDev()); diff --git a/samigo/samigo-app/src/webapp/jsf/evaluation/gradeStudentResult.jsp b/samigo/samigo-app/src/webapp/jsf/evaluation/gradeStudentResult.jsp index 0a3da4f1e58f..25a1baf7fd8d 100755 --- a/samigo/samigo-app/src/webapp/jsf/evaluation/gradeStudentResult.jsp +++ b/samigo/samigo-app/src/webapp/jsf/evaluation/gradeStudentResult.jsp @@ -230,11 +230,11 @@ function toPoint(id)

- + -

+

diff --git a/samigo/samigo-app/src/webapp/jsf/evaluation/histogramScores.jsp b/samigo/samigo-app/src/webapp/jsf/evaluation/histogramScores.jsp index 0720130a9acd..93fb105454ff 100755 --- a/samigo/samigo-app/src/webapp/jsf/evaluation/histogramScores.jsp +++ b/samigo/samigo-app/src/webapp/jsf/evaluation/histogramScores.jsp @@ -276,7 +276,7 @@ $Id$ - + @@ -284,7 +284,7 @@ $Id$ - + @@ -292,7 +292,7 @@ $Id$ - +