Java tutorial
/** * Copyright 2005 Sakai Foundation Licensed under the * Educational Community License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.osedu.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing * permissions and limitations under the License. */ package org.sakaiproject.evaluation.beans; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.evaluation.constant.EvalConstants; import org.sakaiproject.evaluation.logic.EvalCommonLogic; import org.sakaiproject.evaluation.logic.EvalSettings; import org.sakaiproject.evaluation.logic.entity.EvalCategoryEntityProvider; import org.sakaiproject.evaluation.logic.exceptions.InvalidDatesException; import org.sakaiproject.evaluation.logic.exceptions.InvalidEvalCategoryException; import org.sakaiproject.evaluation.logic.model.EvalUser; import org.sakaiproject.evaluation.model.EvalEvaluation; import org.sakaiproject.evaluation.utils.EvalUtils; /** * Utils which depend on some of the basic eval beans<br/> * <b>NOTE:</b> These utils require other spring beans and thus this class must be injected, * attempting to access this without injecting it will cause failures * * @author Aaron Zeckoski (aaron@caret.cam.ac.uk) */ public class EvalBeanUtils { private static final Log LOG = LogFactory.getLog(EvalBeanUtils.class); // Section awareness default setting from sakai.properties private static final String SAKAI_PROP_EVALSYS_SECTION_AWARE_DEFAULT = "evalsys.section.aware.default"; private static final String SAKAI_PROP_EVALSYS_RESULTS_SHARING_DEFAULT = "evalsys.results.sharing.default"; private static final String SAKAI_PROP_EVALSYS_INSTRUCTOR_VIEW_RESPONSES_DEFAULT = "evalsys.instructor.view.responses.default"; private static final boolean EVALSYS_SECTION_AWARE_DEFAULT = ServerConfigurationService .getBoolean(SAKAI_PROP_EVALSYS_SECTION_AWARE_DEFAULT, false); private static final String EVALSYS_RESULTS_SHARING_DEFAULT = ServerConfigurationService .getString(SAKAI_PROP_EVALSYS_RESULTS_SHARING_DEFAULT, EvalConstants.SHARING_VISIBLE); private static final boolean EVALSYS_INSTRUCTOR_VIEW_RESPONSES_DEFAULT = ServerConfigurationService .getBoolean(SAKAI_PROP_EVALSYS_INSTRUCTOR_VIEW_RESPONSES_DEFAULT, true); private EvalCommonLogic commonLogic; public void setCommonLogic(EvalCommonLogic commonLogic) { this.commonLogic = commonLogic; } private EvalSettings settings; public void setSettings(EvalSettings settings) { this.settings = settings; } /** * Determines if evaluation results can be viewed based on the minimum count of responses for the system * and the inputs, also checks if user is an admin (they can always view results) * * @param responsesCount the current number of responses for an evaluation * @param enrollmentsCount the count of enrollments (can be 0 if anonymous or unknown) * @return number of responses needed before viewing is allowed, 0 indicates viewable now */ public int getResponsesNeededToViewForResponseRate(int responsesCount, int enrollmentsCount) { int responsesNeeded; if (commonLogic.isUserAdmin(commonLogic.getCurrentUserId())) { responsesNeeded = 0; } else { int minResponses = ((Integer) settings.get(EvalSettings.RESPONSES_REQUIRED_TO_VIEW_RESULTS)); responsesNeeded = minResponses - responsesCount; if (responsesCount >= enrollmentsCount) { // special check to make sure the cases where there is a very small enrollment count is still ok responsesNeeded = 0; } if (responsesNeeded < 0) { responsesNeeded = 0; } } return responsesNeeded; } /** * General check for admin/owner permissions, * this will check to see if the provided userId is an admin and * also check if they are equal to the provided ownerId * * @param userId internal user id * @param ownerId an internal user id * @return true if this user is admin or matches the owner user id */ public boolean checkUserPermission(String userId, String ownerId) { boolean allowed = false; if (commonLogic.isUserAdmin(userId)) { allowed = true; } else if (ownerId.equals(userId)) { allowed = true; } return allowed; } /** * Check if an instructor can view the results of a given evaluation * (NOTE: this only checks is an evaluatee/instructor can view the results based on this evals settings, * user permissions and response rates still need to be checked), * probably should be using a method like this one: ReportingPermissions.canViewEvaluationResponses(), * similar logic to {@link #getInstructorViewDateForEval(EvalEvaluation)} * * @param eval the evaluation * @param evalState * @return true if results can be viewed, false otherwise */ public boolean checkInstructorViewResultsForEval(EvalEvaluation eval, String evalState) { // now handle the results viewing flags (i.e. filter out evals the instructor should not see) boolean instViewResultsEval = false; if (eval != null) { if (evalState == null || "".equals(evalState)) { evalState = commonLogic.calculateViewability(eval.getState()); } if (EvalConstants.EVALUATION_STATE_DELETED.equals(eval.getState())) { // skip this one } else if (EvalUtils.checkStateAfter(evalState, EvalConstants.EVALUATION_STATE_INQUEUE, false)) { // this eval is active or later and nothing before active is viewable boolean evalViewable = false; // check if this eval is forced to a viewable state String forcedViewableState = commonLogic.calculateViewability(evalState); if (EvalUtils.checkStateAfter(forcedViewableState, EvalConstants.EVALUATION_STATE_VIEWABLE, true)) { // forced viewable evalViewable = true; } else { // not forced so check if it is actually viewable if (EvalUtils.checkStateAfter(evalState, EvalConstants.EVALUATION_STATE_VIEWABLE, true)) { // check for viewable state evals evalViewable = true; } } if (evalViewable) { // finally check if the instructor can actually view it Boolean instViewResultsSetting = (Boolean) settings .get(EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESULTS); // probably should be using a method like this one: ReportingPermissions.canViewEvaluationResponses() if (instViewResultsSetting == null) { instViewResultsEval = eval.getInstructorViewResults(); } else { instViewResultsEval = instViewResultsSetting; } } } } return instViewResultsEval; } /** * Find the date at which an instructor can view the report/results of an evaluation, * similar logic to {@link #checkInstructorViewResultsForEval(EvalEvaluation, String)} * * @param eval an evaluation * @return the date OR null if instructors cannot view the report */ public Date getInstructorViewDateForEval(EvalEvaluation eval) { Date instViewDate = null; if (eval != null) { if (EvalConstants.EVALUATION_STATE_DELETED.equals(eval)) { // skip this one } else if (EvalUtils.checkStateAfter(eval.getState(), EvalConstants.EVALUATION_STATE_INQUEUE, false)) { // this eval is active or later and nothing before active is viewable boolean evalViewable = false; // check if this eval is forced to a viewable state String forcedViewableState = commonLogic.calculateViewability(eval.getState()); if (EvalUtils.checkStateAfter(forcedViewableState, EvalConstants.EVALUATION_STATE_VIEWABLE, true)) { // forced viewable evalViewable = true; instViewDate = eval.getStartDate(); } else { // not forced so check if it is actually viewable if (EvalUtils.checkStateAfter(eval.getState(), EvalConstants.EVALUATION_STATE_VIEWABLE, true)) { // check for viewable state evals evalViewable = true; instViewDate = eval.getSafeViewDate(); } } if (evalViewable) { // finally check if the instructor can actually view it Boolean instViewResultsSetting = (Boolean) settings .get(EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESULTS); if (instViewResultsSetting == null) { evalViewable = eval.getInstructorViewResults(); } else { evalViewable = instViewResultsSetting; } } if (evalViewable) { // see if there is a local override for the instructor view date if (eval.getInstructorsDate() != null) { instViewDate = eval.getInstructorsDate(); } } else { // not viewable after all instViewDate = null; } } } return instViewDate; } /** * Sets all the system defaults for this evaluation object * and ensures all required fields are correctly set, * use this whenever you create a new evaluation <br/> * This is guaranteed to be non-destructive (i.e. it will not replace existing values * but it will fixup any required fields which are nulls to default values), * will force null due date to be non-null but will respect the {@link EvalEvaluation#useDueDate} flag * * @param eval an {@link EvalEvaluation} object (can be persisted or new) * @param evaluationType a type constant of EvalConstants#EVALUATION_TYPE_*, * if left null then {@link EvalConstants#EVALUATION_TYPE_EVALUATION} is used */ public void setEvaluationDefaults(EvalEvaluation eval, String evaluationType) { // set the type to the default to ensure not null if (eval.getType() == null) { eval.setType(EvalConstants.EVALUATION_TYPE_EVALUATION); } // set to the supplied type if supplied and do any special settings if needed based on the type if (evaluationType != null) { eval.setType(evaluationType); } // only do these for new evals if (eval.getId() == null) { if (eval.getState() == null) { eval.setState(EvalConstants.EVALUATION_STATE_PARTIAL); } } // make sure the dates are set Calendar calendar = new GregorianCalendar(); Date now = new Date(); // if default start hour is set, use it for start time (must be tomorrow as eval cannot start in the past). Integer hour = (Integer) settings.get(EvalSettings.EVAL_DEFAULT_START_HOUR); if (hour != null) { // add 1 day to make it tomorrow now.setTime(now.getTime() + 86400000L); // set desired hour now.setHours(hour); now.setMinutes(0); now.setSeconds(0); } calendar.setTime(now); if (eval.getStartDate() == null) { eval.setStartDate(now); LOG.debug("Setting start date to default of: " + eval.getStartDate()); } else { calendar.setTime(eval.getStartDate()); } if (eval.useDueDate != null && !eval.useDueDate) { // allow evals which are open forever eval.setDueDate(null); eval.setStopDate(null); eval.setViewDate(null); } else { // using the due date calendar.add(Calendar.DATE, 1); // +1 day if (eval.getDueDate() == null) { // default the due date to the end of the start date + 1 day Date endOfDay = EvalUtils.getEndOfDayDate(calendar.getTime()); eval.setDueDate(endOfDay); LOG.debug("Setting due date to default of: " + eval.getDueDate()); } else { calendar.setTime(eval.getDueDate()); } boolean useStopDate; if (eval.useStopDate != null && !eval.useStopDate) { useStopDate = false; } else { useStopDate = (Boolean) settings.get(EvalSettings.EVAL_USE_STOP_DATE); } if (useStopDate) { // assign stop date to equal due date for now if (eval.getStopDate() == null) { eval.setStopDate(eval.getDueDate()); LOG.debug("Setting stop date to default of: " + eval.getStopDate()); } } else { eval.setStopDate(null); } boolean useViewDate; if (eval.useViewDate != null && !eval.useViewDate) { useViewDate = false; } else { useViewDate = (Boolean) settings.get(EvalSettings.EVAL_USE_VIEW_DATE); } if (useViewDate) { // assign default view date calendar.add(Calendar.DATE, 1); if (eval.getViewDate() == null) { // default the view date to the today + 2 eval.setViewDate(calendar.getTime()); LOG.debug("Setting view date to default of: " + eval.getViewDate()); } } else { eval.setViewDate(null); } } // handle the view dates default Boolean useSameViewDates = (Boolean) settings.get(EvalSettings.EVAL_USE_SAME_VIEW_DATES); Date sharedDate = eval.getViewDate() == null ? eval.getDueDate() : eval.getViewDate(); if (eval.getStudentsDate() == null || useSameViewDates) { eval.setStudentsDate(sharedDate); } if (eval.getInstructorsDate() == null || useSameViewDates) { eval.setInstructorsDate(sharedDate); } // results viewable settings Date studentsDate; Boolean studentsView = (Boolean) settings.get(EvalSettings.STUDENT_ALLOWED_VIEW_RESULTS); if (studentsView != null) { eval.setStudentViewResults(studentsView); } Date instructorsDate; Boolean instructorsView = (Boolean) settings.get(EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESULTS); if (instructorsView != null) { eval.setInstructorViewResults(instructorsView); } // Added by EVALSYS-1063. Modified by EVALSYS-1176. // Will modify the value of EvalEvaluation.instructorViewAllResults property iff current value is null. // Will use value of EvalSettings.INSTRUCTOR_ALLOWED_VIEW_ALL_RESULTS setting if available, false otherwise. Boolean instructorsAllView = eval.getInstructorViewAllResults(); if (instructorsAllView == null) { Boolean instructorsAllViewSetting = (Boolean) settings .get(EvalSettings.INSTRUCTOR_ALLOWED_VIEW_ALL_RESULTS); if (instructorsAllViewSetting == null) { eval.setInstructorViewAllResults(Boolean.FALSE); } else { eval.setInstructorViewAllResults(instructorsAllViewSetting); } } // Section awareness default controlled by sakai.property if (eval.getSectionAwareness() == null || !eval.getSectionAwareness()) { eval.setSectionAwareness(EVALSYS_SECTION_AWARE_DEFAULT); } // Results sharing default controlled by sakai.property if (eval.getResultsSharing() == null) { if (!EvalConstants.SHARING_VISIBLE.equals(EVALSYS_RESULTS_SHARING_DEFAULT) && !EvalConstants.SHARING_PRIVATE.equals(EVALSYS_RESULTS_SHARING_DEFAULT) && !EvalConstants.SHARING_PUBLIC.equals(EVALSYS_RESULTS_SHARING_DEFAULT)) { eval.setResultsSharing(EvalConstants.SHARING_VISIBLE); } else { eval.setResultsSharing(EVALSYS_RESULTS_SHARING_DEFAULT); } } // Instructors view results default controlled by sakai.property if ((Boolean) eval.getInstructorViewResults() == null) { eval.setInstructorViewResults(EVALSYS_INSTRUCTOR_VIEW_RESPONSES_DEFAULT); } if (eval.getInstructorViewAllResults() == null) { eval.setInstructorViewAllResults(EVALSYS_INSTRUCTOR_VIEW_RESPONSES_DEFAULT); } if (EvalConstants.SHARING_PRIVATE.equals(eval.getResultsSharing())) { eval.setStudentViewResults(false); eval.setInstructorViewResults(false); eval.setInstructorViewAllResults(false); } else if (EvalConstants.SHARING_PUBLIC.equals(eval.getResultsSharing())) { eval.setStudentViewResults(true); eval.setInstructorViewResults(true); eval.setInstructorViewAllResults(true); studentsDate = eval.getViewDate(); eval.setStudentsDate(studentsDate); instructorsDate = eval.getViewDate(); eval.setInstructorsDate(instructorsDate); } // student completion settings if (eval.getBlankResponsesAllowed() == null) { Boolean blankAllowed = (Boolean) settings.get(EvalSettings.STUDENT_ALLOWED_LEAVE_UNANSWERED); if (blankAllowed == null) { blankAllowed = false; } eval.setBlankResponsesAllowed(blankAllowed); } if (eval.getModifyResponsesAllowed() == null) { Boolean modifyAllowed = (Boolean) settings.get(EvalSettings.STUDENT_MODIFY_RESPONSES); if (modifyAllowed == null) { modifyAllowed = false; } eval.setModifyResponsesAllowed(modifyAllowed); } if (eval.getUnregisteredAllowed() == null) { eval.setUnregisteredAllowed(Boolean.FALSE); } if (eval.getAllRolesParticipate() == null) { Boolean allRolesParticipate = (Boolean) settings.get(EvalSettings.ALLOW_ALL_SITE_ROLES_TO_RESPOND); if (allRolesParticipate == null) { allRolesParticipate = false; } eval.setAllRolesParticipate(allRolesParticipate); } // fix up the reminder days to the default if (eval.getReminderDays() == null) { Integer reminderDays = 1; Integer defaultReminderDays = (Integer) settings.get(EvalSettings.DEFAULT_EMAIL_REMINDER_FREQUENCY); if (defaultReminderDays != null) { reminderDays = defaultReminderDays; } eval.setReminderDays(reminderDays); } // set the reminder email address to the default if (eval.getReminderFromEmail() == null) { // email from address control String from = (String) settings.get(EvalSettings.FROM_EMAIL_ADDRESS); // https://bugs.caret.cam.ac.uk/browse/CTL-1525 - default to admin address if option set Boolean useAdminEmail = (Boolean) settings.get(EvalSettings.USE_ADMIN_AS_FROM_EMAIL); if (useAdminEmail) { // try to get the email address for the owner (eval admin) EvalUser owner = commonLogic.getEvalUserById(commonLogic.getCurrentUserId()); if (owner != null && owner.email != null && !"".equals(owner.email)) { from = owner.email; } } eval.setReminderFromEmail(from); } // admin settings if (eval.getInstructorOpt() == null) { String instOpt = (String) settings.get(EvalSettings.INSTRUCTOR_MUST_USE_EVALS_FROM_ABOVE); if (instOpt == null) { instOpt = EvalConstants.INSTRUCTOR_REQUIRED; } eval.setInstructorOpt(instOpt); } } /** * Fixes up the evaluation dates so that the evaluation is assured to save with * valid dates, this should be run whenever the dates of an evaluation are being updated or changed <br/> * This is guaranteed to be non-destructive and should only fixup invalid or null fields and dates <br/> * handles setting date fields based on the useDueDate, etc. fields in the evaluation as well <br/> * * @param eval an {@link EvalEvaluation} object (can be persisted or new) * @param ignoreMinTimeDiff if true, the minimum time difference is ignored, if false, it is enforced */ public void fixupEvaluationDates(EvalEvaluation eval, boolean ignoreMinTimeDiff) { if (eval == null) { throw new IllegalArgumentException("eval must be set to fix dates"); } boolean useDueDate = eval.useDueDate != null ? eval.useDueDate : true; boolean useStopDate; if (eval.useStopDate != null && !eval.useStopDate) { useStopDate = false; } else { useStopDate = (Boolean) settings.get(EvalSettings.EVAL_USE_STOP_DATE); } boolean useViewDate; if (eval.useViewDate != null && !eval.useViewDate) { useViewDate = false; } else { useViewDate = (Boolean) settings.get(EvalSettings.EVAL_USE_VIEW_DATE); } boolean useDateTime = ((Boolean) settings.get(EvalSettings.EVAL_USE_DATE_TIME)); Date now = new Date(); if (eval.getStartDate() == null) { eval.setStartDate(now); } if (eval.getStartDate().after(now)) { // set the start date/time to now if immediate start is selected (custom start date is false) AND // the start date is NOT in the past if (eval.customStartDate != null && !eval.customStartDate) { eval.setStartDate(now); } } if (!useDueDate) { // null out the due/stop/view dates eval.setDueDate(null); eval.setStopDate(null); eval.setViewDate(null); } // ensure the due date comes after the start date if (eval.getDueDate() != null) { if (!eval.getDueDate().after(eval.getStartDate())) { Calendar cal = new GregorianCalendar(); cal.setTime(eval.getStartDate()); cal.add(Calendar.HOUR, 25); eval.setDueDate(cal.getTime()); } } if (!useDateTime) { // force the due date to the end of the day if we are using dates only AND eval is not due yet if (eval.getDueDate() != null) { if (EvalUtils.checkStateBefore(eval.getState(), EvalConstants.EVALUATION_STATE_GRACEPERIOD, false)) { LOG.info("Forcing date to end of day for non null due date: " + eval.getDueDate()); eval.setDueDate(EvalUtils.getEndOfDayDate(eval.getDueDate())); } } } if (!useStopDate) { // force stop date to null if not in use eval.setStopDate(null); } if (!useDateTime) { // force the stop date to the end of the day if we are using dates only AND eval is not closed yet if (eval.getStopDate() != null) { if (EvalUtils.checkStateBefore(eval.getState(), EvalConstants.EVALUATION_STATE_CLOSED, false)) { LOG.info("Forcing date to end of day for non null stop date: " + eval.getStopDate()); eval.setStopDate(EvalUtils.getEndOfDayDate(eval.getStopDate())); } } } // Getting the system setting that tells what should be the minimum time difference between start date and due date. int minHoursDifference = 0; if (!ignoreMinTimeDiff) { minHoursDifference = ((Integer) settings.get(EvalSettings.EVAL_MIN_TIME_DIFF_BETWEEN_START_DUE)); } // Ensure minimum time difference between start and due/stop dates in eval - check this after the dates are set if (eval.getDueDate() != null) { EvalUtils.updateDueStopDates(eval, minHoursDifference); } if (!useViewDate) { if (EvalUtils.checkStateBefore(eval.getState(), EvalConstants.EVALUATION_STATE_ACTIVE, false)) { // force view date to null if not in use AND eval is still being created eval.setViewDate(null); } } if (!useDateTime) { // force the view date to the end of the day if we are using dates only AND eval is not viewable yet if (eval.getViewDate() != null) { if (EvalUtils.checkStateBefore(eval.getState(), EvalConstants.EVALUATION_STATE_VIEWABLE, false)) { LOG.info("Forcing date to end of day for non null stop date: " + eval.getViewDate()); eval.setViewDate(EvalUtils.getEndOfDayDate(eval.getViewDate())); } } } if (eval.getViewDate() != null && eval.getDueDate() != null) { if (eval.getViewDate().before(eval.getDueDate())) { // force view date to due date if it is before the due date eval.setViewDate(eval.getDueDate()); } } /* * If "EVAL_USE_SAME_VIEW_DATES" system setting (admin setting) flag is set * as true then don't look for student and instructor dates, instead make them * same as admin view date. If not then keep the student and instructor view dates. */ boolean sameViewDateForAll = ((Boolean) settings.get(EvalSettings.EVAL_USE_SAME_VIEW_DATES)); if (sameViewDateForAll) { if (eval.getStudentViewResults()) { eval.setStudentsDate(eval.getViewDate()); } if (eval.getInstructorViewResults()) { eval.setInstructorsDate(eval.getViewDate()); } } // force the student/instructor dates null based on the boolean settings if (!eval.getStudentViewResults()) { eval.setStudentsDate(null); } if (!eval.getInstructorViewResults()) { eval.setInstructorsDate(null); } } /** * Check the dates for an evaluation and throw an exception if they are invalid * (in an improper order) * @param evaluation any evaluation * @throws InvalidDatesException if the dates are invalid */ public static void validateEvalDates(EvalEvaluation evaluation) { if (evaluation.getDueDate() != null) { if (evaluation.getStartDate().compareTo(evaluation.getDueDate()) >= 0) { throw new InvalidDatesException("due date (" + evaluation.getDueDate() + ") must occur after start date (" + evaluation.getStartDate() + "), can occur on the same date but not at the same time", "dueDate"); } if (evaluation.getStopDate() != null) { if (evaluation.getDueDate().compareTo(evaluation.getStopDate()) > 0) { throw new InvalidDatesException( "stop date (" + evaluation.getStopDate() + ") must occur on or after due date (" + evaluation.getDueDate() + "), can be identical", "stopDate"); } if (evaluation.getViewDate() != null) { if (evaluation.getViewDate().compareTo(evaluation.getStopDate()) < 0) { throw new InvalidDatesException( "view date (" + evaluation.getViewDate() + ") must occur on or after stop date (" + evaluation.getStopDate() + "), can be identical", "viewDate"); } } } if (evaluation.getViewDate() != null) { if (evaluation.getViewDate().compareTo(evaluation.getDueDate()) < 0) { throw new InvalidDatesException( "view date (" + evaluation.getViewDate() + ") must occur on or after due date (" + evaluation.getDueDate() + "), can be identical", "viewDate"); } } } } /** * Tests validity of user-supplied evaluation category by attempting to create * the resulting entity URL. Throws an {@link InvalidEvalCategoryException} if * the eval category contains any invalid characters (i.e. characters that are * invalid for use in a URL). * * @param evalCategory the eval category entered by the user */ public void validateEvalCategory(String evalCategory) { try { if ((evalCategory != null) && (evalCategory.length() != 0)) { commonLogic.getEntityURL(EvalCategoryEntityProvider.ENTITY_PREFIX, evalCategory); } } catch (IllegalArgumentException ex) { throw new InvalidEvalCategoryException(ex); } } }