package fi.otavanopisto.muikku.plugins.timed.notifications.strategies; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.ejb.Singleton; import javax.ejb.Startup; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import org.apache.commons.lang3.LocaleUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import fi.otavanopisto.muikku.controller.PluginSettingsController; import fi.otavanopisto.muikku.i18n.LocaleController; import fi.otavanopisto.muikku.jade.JadeLocaleHelper; import fi.otavanopisto.muikku.model.users.UserEntity; import fi.otavanopisto.muikku.model.workspace.WorkspaceEntity; import fi.otavanopisto.muikku.plugins.timed.notifications.NotificationController; import fi.otavanopisto.muikku.plugins.timed.notifications.RequestedAssessmentSupplementationsNotificationController; import fi.otavanopisto.muikku.schooldata.GradingController; import fi.otavanopisto.muikku.schooldata.SchoolDataIdentifier; import fi.otavanopisto.muikku.schooldata.WorkspaceController; import fi.otavanopisto.muikku.schooldata.entity.GradingScale; import fi.otavanopisto.muikku.schooldata.entity.GradingScaleItem; import fi.otavanopisto.muikku.schooldata.entity.Workspace; import fi.otavanopisto.muikku.schooldata.entity.WorkspaceAssessment; import fi.otavanopisto.muikku.schooldata.entity.WorkspaceAssessmentRequest; import fi.otavanopisto.muikku.search.SearchResult; import fi.otavanopisto.muikku.users.UserEntityController; import fi.otavanopisto.muikku.users.WorkspaceUserEntityController; @Startup @Singleton @ApplicationScoped public class RequestedAssessmentSupplementationsNotificationStrategy extends AbstractTimedNotificationStrategy{ private static final int FIRST_RESULT = 0; private static final int MAX_RESULTS = NumberUtils.createInteger(System.getProperty("muikku.timednotifications.requestedassessmentsupplementation.maxresults", "20")); private static final int NOTIFICATION_THRESHOLD_DAYS = NumberUtils.createInteger(System.getProperty("muikku.timednotifications.requestedassessmentsupplementation.notificationthreshold", "7")); private static final long NOTIFICATION_CHECK_FREQ = NumberUtils.createLong(System.getProperty("muikku.timednotifications.requestedassessmentsupplementation.checkfreq", "1800000")); @Inject private PluginSettingsController pluginSettingsController; @Inject private UserEntityController userEntityController; @Inject private NotificationController notificationController; @Inject private LocaleController localeController; @Inject private JadeLocaleHelper jadeLocaleHelper; @Inject private GradingController gradingController; @Inject private WorkspaceUserEntityController workspaceUserEntityController; @Inject private WorkspaceController workspaceController; @Inject private RequestedAssessmentSupplementationsNotificationController requestedAssessmentSupplementationsNotificationController; @Inject private Logger logger; @Override public boolean isActive(){ return active; } @Override public long getDuration() { return NOTIFICATION_CHECK_FREQ; } @Override public void sendNotifications() { Collection<Long> groups = getGroups(); if (groups.isEmpty()) { return; } SearchResult searchResult = requestedAssessmentSupplementationsNotificationController.searchActiveStudentIds(groups, FIRST_RESULT + offset, MAX_RESULTS); if (searchResult.getFirstResult() + MAX_RESULTS >= searchResult.getTotalHitCount()) { offset = 0; } else { offset += MAX_RESULTS; } for (Map<String, Object> result : searchResult.getResults()) { String studentId = (String) result.get("id"); if (StringUtils.isBlank(studentId)) { logger.severe("Could not process user found from search index because it had a null id"); continue; } String[] studentIdParts = studentId.split("/", 2); SchoolDataIdentifier studentIdentifier = studentIdParts.length == 2 ? new SchoolDataIdentifier(studentIdParts[0], studentIdParts[1]) : null; if (studentIdentifier == null) { logger.severe(String.format("Could not process user found from search index with id %s", studentId)); continue; } List<WorkspaceEntity> workspaceEntities = workspaceUserEntityController.listWorkspaceEntitiesByUserIdentifier(studentIdentifier); for (WorkspaceEntity workspaceEntity : workspaceEntities) { SchoolDataIdentifier workspaceIdentifier = new SchoolDataIdentifier(workspaceEntity.getIdentifier(), workspaceEntity.getDataSource().getIdentifier()); if (requestedAssessmentSupplementationsNotificationController.countByStudentIdentifierAndWorkspaceIdentifier(studentIdentifier, workspaceIdentifier) == 0) { List<WorkspaceAssessment> workspaceAssessments = gradingController.listWorkspaceAssessments(workspaceIdentifier, studentIdentifier); if (workspaceAssessments != null && !workspaceAssessments.isEmpty()) { WorkspaceAssessment assessment = workspaceAssessments.get(0); //TODO: loop and find latest Date assessmentDate = assessment.getDate(); if (assessmentDate != null && assessmentDate.before(Date.from(OffsetDateTime.now().minusDays(NOTIFICATION_THRESHOLD_DAYS).toInstant()))) { GradingScale gradingScale = gradingController.findGradingScale(assessment.getGradingScaleIdentifier()); GradingScaleItem grade = gradingController.findGradingScaleItem(gradingScale, assessment.getGradeIdentifier()); if (!grade.isPassingGrade()) { WorkspaceAssessmentRequest latestAssesmentRequest = null; List<WorkspaceAssessmentRequest> studentAssesmentRequests = gradingController.listWorkspaceAssessmentRequests(workspaceIdentifier.getDataSource(), workspaceIdentifier.getIdentifier(), studentIdentifier.getIdentifier()); for (WorkspaceAssessmentRequest assessmentRequest : studentAssesmentRequests) { Date assessmentRequestDate = assessmentRequest.getDate(); if (assessmentRequestDate != null) { if (latestAssesmentRequest == null || latestAssesmentRequest.getDate().before(assessmentRequestDate)) { latestAssesmentRequest = assessmentRequest; } } } if (latestAssesmentRequest == null || latestAssesmentRequest.getDate().before(assessmentDate)) { UserEntity studentEntity = userEntityController.findUserEntityByUserIdentifier(studentIdentifier); Workspace workspace = workspaceController.findWorkspace(workspaceIdentifier); if (studentEntity != null && workspace != null) { Locale studentLocale = localeController.resolveLocale(LocaleUtils.toLocale(studentEntity.getLocale())); Map<String, Object> templateModel = new HashMap<>(); templateModel.put("workspaceName", workspace.getName()); templateModel.put("locale", studentLocale); templateModel.put("localeHelper", jadeLocaleHelper); String notificationContent = renderNotificationTemplate("requested-assessment-supplementation-notification", templateModel); notificationController.sendNotification( localeController.getText(studentLocale, "plugin.timednotifications.notification.category"), localeController.getText(studentLocale, "plugin.timednotifications.notification.requestedassessmentsupplementation.subject"), notificationContent, studentEntity ); requestedAssessmentSupplementationsNotificationController.createRequestedAssessmentSupplementationNotification(studentIdentifier, workspaceIdentifier); } else { logger.log(Level.SEVERE, String.format("Cannot send notification to student with identifier %s because UserEntity or workspace was not found", studentIdentifier.toId())); } } } } } } } } } private Collection<Long> getGroups(){ String groupsString = pluginSettingsController.getPluginSetting("timed-notifications", "requested-assessment-supplementations-notification.groups"); if (StringUtils.isBlank(groupsString)) { this.active = false; logger.log(Level.WARNING, "Disabling timed noPassedCourses notifications because no groups were configured as targets"); return Collections.emptyList(); } Collection<Long> groups = new ArrayList<>(); String[] groupSplit = groupsString.split(","); for (String group : groupSplit) { if (NumberUtils.isNumber(group)) { groups.add(NumberUtils.createLong(group)); } } return groups; } private int offset = 0; private boolean active = true; }