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.logic; import java.io.OutputStream; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.Map.Entry; import java.util.Objects; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.evaluation.constant.EvalConstants; import org.sakaiproject.evaluation.dao.EvaluationDao; import org.sakaiproject.evaluation.logic.externals.EvalSecurityChecksImpl; import org.sakaiproject.evaluation.logic.model.EvalGroup; import org.sakaiproject.evaluation.logic.model.EvalReminderStatus; import org.sakaiproject.evaluation.model.*; import org.sakaiproject.evaluation.utils.ArrayUtils; import org.sakaiproject.evaluation.utils.EvalUtils; import org.sakaiproject.genericdao.api.search.Order; import org.sakaiproject.genericdao.api.search.Restriction; import org.sakaiproject.genericdao.api.search.Search; import org.sakaiproject.evaluation.toolaccess.EvaluationAccessAPI; import org.sakaiproject.evaluation.toolaccess.ToolApi; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.site.api.SiteService.SortType; /** * Implementation of the evals service, * this is a LOWER level service and should have dependencies on LOWER and BOTTOM level services only * * @author Aaron Zeckoski (aaron@caret.cam.ac.uk) */ public class EvalEvaluationServiceImpl implements EvalEvaluationService, EvaluationAccessAPI { private static final Log LOG = LogFactory.getLog(EvalEvaluationServiceImpl.class); // Event names cannot be over 32 chars long // max-32:12345678901234567890123456789012 protected final String EVENT_EVAL_STATE_START = "eval.evaluation.state.start"; protected final String EVENT_EVAL_STATE_DUE = "eval.evaluation.state.due"; protected final String EVENT_EVAL_STATE_STOP = "eval.evaluation.state.stop"; protected final String EVENT_EVAL_STATE_VIEWABLE = "eval.evaluation.state.viewable"; private EvaluationDao dao; public void setDao(EvaluationDao dao) { this.dao = dao; } private EvalCommonLogic commonLogic; public void setCommonLogic(EvalCommonLogic commonLogic) { this.commonLogic = commonLogic; } private EvalSecurityChecksImpl securityChecks; public void setSecurityChecks(EvalSecurityChecksImpl securityChecks) { this.securityChecks = securityChecks; } private EvalSettings settings; public void setSettings(EvalSettings settings) { this.settings = settings; } private ToolApi toolApi = null; public void setToolApi(ToolApi t) { toolApi = t; } public void exportReport(EvalEvaluation evaluation, String groupIds, OutputStream outputStream, String exportType) { toolApi.exportReport(evaluation, groupIds, outputStream, exportType); } public void exportReport(EvalEvaluation evaluation, String groupIds, String evaluateeId, OutputStream outputStream, String exportType) { toolApi.exportReport(evaluation, groupIds, evaluateeId, outputStream, exportType); } public void exportReport(EvalEvaluation evaluation, String[] groupIds, String evaluateeId, OutputStream outputStream, String exportType) { toolApi.exportReport(evaluation, groupIds, evaluateeId, outputStream, exportType); } private SiteService siteService; public void setSiteService(SiteService siteService) { this.siteService = siteService; } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#getEvaluationById(java.lang.Long) */ public EvalEvaluation getEvaluationById(Long evaluationId) { LOG.debug("evalId: " + evaluationId); EvalEvaluation eval = (EvalEvaluation) dao.findById(EvalEvaluation.class, evaluationId); fixupEvaluation(eval); return eval; } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#checkEvaluationExists(java.lang.Long) */ public boolean checkEvaluationExists(Long evaluationId) { if (evaluationId == null) { throw new NullPointerException("evaluationId cannot be null"); } boolean exists; long count = dao.countBySearch(EvalEvaluation.class, new Search("id", evaluationId)); exists = count > 0l; return exists; } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#getEvaluationByEid(java.lang.String) */ public EvalEvaluation getEvaluationByEid(String eid) { EvalEvaluation evalEvaluation = null; if (eid != null) { evalEvaluation = dao.findOneBySearch(EvalEvaluation.class, new Search("eid", eid)); } fixupEvaluation(evalEvaluation); return evalEvaluation; } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#countEvaluationsByTemplateId(java.lang.Long) */ public int countEvaluationsByTemplateId(Long templateId) { LOG.debug("templateId: " + templateId); Search search = makeSearchForEvalsByTemplate(templateId); int count = (int) dao.countBySearch(EvalEvaluation.class, search); return count; } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#getEvaluationsByTemplateId(java.lang.Long) */ public List<EvalEvaluation> getEvaluationsByTemplateId(Long templateId) { LOG.debug("templateId: " + templateId); Search search = makeSearchForEvalsByTemplate(templateId); List<EvalEvaluation> evals = dao.findBySearch(EvalEvaluation.class, search); for (EvalEvaluation evaluation : evals) { fixupEvaluation(evaluation); } return evals; } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#getEvaluationsByTermId(java.lang.String) */ public List<EvalEvaluation> getEvaluationsByTermId(String termId) { LOG.debug("termId: " + termId); Search search = makeSearchForEvalsByTermId(termId); List<EvalEvaluation> evals = dao.findBySearch(EvalEvaluation.class, search); for (EvalEvaluation evaluation : evals) { fixupEvaluation(evaluation); } return evals; } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#getEvaluationsByState(java.lang.String) */ public List<EvalEvaluation> getEvaluationsByState(String state) { LOG.debug("state: " + state); Search search = new Search(); search.addRestriction(new Restriction("state", state)); List<EvalEvaluation> evals = dao.findBySearch(EvalEvaluation.class, search); for (EvalEvaluation evaluation : evals) { fixupEvaluation(evaluation); } return evals; } /** * @param templateId unique id of a template (must be set or exception occurs) * @return the search which will find evals based on a template id */ private Search makeSearchForEvalsByTemplate(Long templateId) { int count = (int) dao.countBySearch(EvalTemplate.class, new Search("id", templateId)); if (count <= 0) { throw new IllegalArgumentException("Cannot find template with id: " + templateId); } Search search = new Search(new Restriction[] { new Restriction("template.id", templateId), new Restriction("state", EvalConstants.EVALUATION_STATE_PARTIAL, Restriction.NOT_EQUALS), new Restriction("state", EvalConstants.EVALUATION_STATE_DELETED, Restriction.NOT_EQUALS) }); return search; } /** * @param termId the term id of an {@link EvalEvaluation} * @return the search object that will select {@link EvalEvaluation} objects based on term id */ private Search makeSearchForEvalsByTermId(String termId) { Search search = new Search(new Restriction[] { new Restriction("termId", termId), new Restriction("state", EvalConstants.EVALUATION_STATE_PARTIAL, Restriction.NOT_EQUALS), new Restriction("state", EvalConstants.EVALUATION_STATE_DELETED, Restriction.NOT_EQUALS) }); return search; } public void setAvailableEmailSent(Long[] evalIds) { for (Long evaluationId : evalIds) { EvalEvaluation eval = getEvaluationById(evaluationId); eval.setAvailableEmailSent(Boolean.TRUE); // use dao because evaluation is locked dao.save(eval); } } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#updateEvaluationState(java.lang.Long) */ public String updateEvaluationState(Long evaluationId) { LOG.debug("evalId: " + evaluationId); EvalEvaluation eval = getEvaluationOrFail(evaluationId); // fix the state of this eval if needed, save it, and return the state constant return returnAndFixEvalState(eval, true); } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#updateEvaluationReminderStatus(java.lang.Long, org.sakaiproject.evaluation.logic.model.EvalReminderStatus) */ public void updateEvaluationReminderStatus(Long evaluationId, EvalReminderStatus reminderStatus) { LOG.debug("evalId: " + evaluationId); EvalEvaluation eval = getEvaluationOrFail(evaluationId); eval.setCurrentReminderStatus(reminderStatus); dao.update(eval); dao.forceCommit(); } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#returnAndFixEvalState(org.sakaiproject.evaluation.model.EvalEvaluation, boolean) */ public String returnAndFixEvalState(EvalEvaluation evaluation, boolean saveState) { String trueState = EvalUtils.getEvaluationState(evaluation, true); // check state against stored state if (EvalConstants.EVALUATION_STATE_UNKNOWN.equals(trueState)) { LOG.warn("Evaluation (" + evaluation.getTitle() + ") in UNKNOWN state"); } else if (EvalConstants.EVALUATION_STATE_PARTIAL.equals(evaluation.getState()) || EvalConstants.EVALUATION_STATE_DELETED.equals(evaluation.getState())) { // never fix the state if it is currently in a special state trueState = evaluation.getState(); } else { // compare state and set if not equal if (!trueState.equals(evaluation.getState())) { evaluation.setState(trueState); // will only save the state if this eval is already saved if ((evaluation.getId() != null) && saveState) { if (EvalConstants.EVALUATION_STATE_ACTIVE.equals(trueState)) { commonLogic.registerEntityEvent(EVENT_EVAL_STATE_START, evaluation); } else if (EvalConstants.EVALUATION_STATE_GRACEPERIOD.equals(trueState)) { commonLogic.registerEntityEvent(EVENT_EVAL_STATE_DUE, evaluation); } else if (EvalConstants.EVALUATION_STATE_CLOSED.equals(trueState)) { commonLogic.registerEntityEvent(EVENT_EVAL_STATE_STOP, evaluation); } else if (EvalConstants.EVALUATION_STATE_VIEWABLE.equals(trueState)) { commonLogic.registerEntityEvent(EVENT_EVAL_STATE_VIEWABLE, evaluation); } dao.update(evaluation); } } } return trueState; } // USER ASSIGNMENTS /** * @deprecated use {@link #getParticipantsForEval(Long, String, String, String, String, String, String)} */ public Set<String> getUserIdsTakingEvalInGroup(Long evaluationId, String evalGroupId, String includeConstant) { EvalUtils.validateEmailIncludeConstant(includeConstant); List<EvalAssignUser> userAssignments = getParticipantsForEval(evaluationId, null, new String[] { evalGroupId }, EvalAssignUser.TYPE_EVALUATOR, null, includeConstant, null); Set<String> userIds = EvalUtils.getUserIdsFromUserAssignments(userAssignments); return userIds; } public EvalAssignUser getAssignUserByEid(String eid) { EvalAssignUser eau = null; if (eid != null) { eau = dao.findOneBySearch(EvalAssignUser.class, new Search("eid", eid)); } return eau; } public EvalAssignUser getAssignUserById(Long assignUserId) { EvalAssignUser eau = (EvalAssignUser) dao.findById(EvalAssignUser.class, assignUserId); return eau; } public List<EvalAssignUser> getParticipantsForEval(Long evaluationId, String userId, String[] evalGroupIds, String assignTypeConstant, String assignStatusConstant, String includeConstant, String evalStateConstant) { // validate arguments if (evaluationId == null && (userId == null || "".equals(userId))) { throw new IllegalArgumentException("At least one of the following must be set: evaluationId, userId"); } /** // create the search Search search = new Search(); if (evaluationId != null) { // getEvaluationOrFail(evaluationId); // took out eval fetch for now search.addRestriction( new Restriction("evaluation.id", evaluationId) ); } if (evalStateConstant != null) { EvalUtils.validateStateConstant(evalStateConstant); search.addRestriction( new Restriction("evaluation.state", evalStateConstant) ); } if (evalGroupIds != null && evalGroupIds.length > 0) { search.addRestriction( new Restriction("evalGroupId", evalGroupIds) ); } if (assignTypeConstant != null && includeConstant == null) { EvalAssignUser.validateType(assignTypeConstant); // only set this if the includeConstant is not set search.addRestriction( new Restriction("type", assignTypeConstant) ); } if (assignStatusConstant == null) { search.addRestriction( new Restriction("status", EvalAssignUser.STATUS_REMOVED, Restriction.NOT_EQUALS) ); } else if (STATUS_ANY.equals(assignStatusConstant)) { // no restriction needed in this case } else { EvalAssignUser.validateStatus(assignStatusConstant); search.addRestriction( new Restriction("status", assignStatusConstant) ); } if (userId != null && ! "".equals(userId)) { search.addRestriction( new Restriction("userId", userId) ); } boolean includeFilterUsers = false; Set<String> userFilter = null; if (includeConstant != null) { EvalUtils.validateEmailIncludeConstant(includeConstant); String[] groupIds = new String[] {}; if (evalGroupIds != null && evalGroupIds.length > 0) { groupIds = evalGroupIds; } // force the results to only include eval takers search.addRestriction( new Restriction("type", EvalAssignUser.TYPE_EVALUATOR) ); // now set up the filter if (EvalConstants.EVAL_INCLUDE_NONTAKERS.equals(includeConstant)) { // get all users who have NOT responded userFilter = dao.getResponseUserIds(evaluationId, groupIds); includeFilterUsers = false; } else if (EvalConstants.EVAL_INCLUDE_RESPONDENTS.equals(includeConstant)) { // get all users who have responded userFilter = dao.getResponseUserIds(evaluationId, groupIds); includeFilterUsers = true; } else if (EvalConstants.EVAL_INCLUDE_ALL.equals(includeConstant)) { // do nothing } else { throw new IllegalArgumentException("Unknown includeConstant: " + includeConstant); } } // get the assignments based on the search List<EvalAssignUser> results = dao.findBySearch(EvalAssignUser.class, search); List<EvalAssignUser> assignments = new ArrayList<EvalAssignUser>( results ); // This code is potentially expensive but there is not really a better way to handle it -AZ if (userFilter != null && ! userFilter.isEmpty()) { // filter the results based on the userFilter for (Iterator<EvalAssignUser> iterator = assignments.iterator(); iterator.hasNext();) { EvalAssignUser evalAssignUser = iterator.next(); String uid = evalAssignUser.getUserId(); if (includeFilterUsers) { // only include users in the filter if (! userFilter.contains(uid)) { iterator.remove(); } } else { // exclude all users in the filter if (userFilter.contains(uid)) { iterator.remove(); } } } } **/ // this is handled in the DAO now List<EvalAssignUser> assignments = dao.getParticipantsForEval(evaluationId, userId, evalGroupIds, assignTypeConstant, assignStatusConstant, includeConstant, evalStateConstant); return assignments; } public int countParticipantsForEval(Long evaluationId, String[] evalGroupIds) { int totalEnrollments = 0; EvalEvaluation eval = getEvaluationOrFail(evaluationId); // only counting if the eval is not anonymous, anon is always effectively 0 if (!EvalConstants.EVALUATION_AUTHCONTROL_NONE.equals(eval.getAuthControl())) { // count the participants Search search = new Search("evaluation.id", evaluationId); // only include evaluators which are not removed search.addRestriction(new Restriction("type", EvalAssignUser.TYPE_EVALUATOR)); search.addRestriction(new Restriction("status", EvalAssignUser.STATUS_REMOVED, Restriction.NOT_EQUALS)); // limit to a group if requested if (evalGroupIds != null && evalGroupIds.length > 0) { search.addRestriction(new Restriction("evalGroupId", evalGroupIds)); } totalEnrollments = (int) dao.countBySearch(EvalAssignUser.class, search); } return totalEnrollments; } /** * JIRA EvalSys-588 */ public boolean isEvalGroupValidForEvaluation(String evalGroupId, Long evaluationId) { // grab the evaluation itself first EvalEvaluation eval = getEvaluationOrFail(evaluationId); boolean valid = false; if (checkEvalStateValidForTaking(eval)) { valid = checkEvalGroupValidForEval(eval, evalGroupId); } return valid; } /** * Checks if the state of an evaluation is valid for taking it * @param eval an eval (cannot be null) * @return true if state is valid OR fale if not */ private boolean checkEvalStateValidForTaking(EvalEvaluation eval) { boolean valid = false; // check the evaluation state if (eval != null) { String state = EvalUtils.getEvaluationState(eval, false); valid = !(!EvalConstants.EVALUATION_STATE_ACTIVE.equals(state) && !EvalConstants.EVALUATION_STATE_GRACEPERIOD.equals(state)); //log.info("User (" + userId + ") cannot take evaluation (" + evaluationId + ") when eval state is: " + state); } return valid; } @Override public EvalEvaluation updateEvaluationOwner(Long evaluationId, String userId) { LOG.debug("evalId: " + evaluationId); EvalEvaluation eval = getEvaluationOrFail(evaluationId); eval.setOwner(userId); dao.update(eval); dao.forceCommit(); return eval; } /** * Checks that the group is valid for this evaluation * @param eval the evaluation * @param evalGroupId (OPTIONAL) the group id, if not set then do a check to make sure at least one group is set and valid * @param includeStateCheck if true then also check the state of the eval is valid for taking * @return true if the group is valid for this eval */ private boolean checkEvalGroupValidForEval(EvalEvaluation eval, String evalGroupId) { if (eval == null) { throw new IllegalArgumentException("eval must be set and cannot be null"); } boolean valid; String userId = commonLogic.getCurrentUserId(); Long evaluationId = eval.getId(); if (commonLogic.isUserAdmin(userId)) { // admin trumps being in a group valid = true; } else { Search search = new Search(new Restriction[] { new Restriction("evaluation.id", evaluationId), new Restriction("instructorApproval", Boolean.TRUE) }); if (evalGroupId == null) { // no groupId is supplied so do a simpler check // make sure at least one group is valid for this eval } else { // check that the evalGroupId is valid for this evaluation search.addRestriction(new Restriction("evalGroupId", evalGroupId)); } // do the search List<EvalAssignGroup> groups = dao.findBySearch(EvalAssignGroup.class, search); if (groups.size() <= 0) { // no valid groups valid = false; } else if (groups.size() == 1) { valid = commonLogic.isEvalGroupPublished(groups.get(0).getEvalGroupId()); } else { int validGroups = 0; for (EvalAssignGroup evalAssignGroup : groups) { validGroups = commonLogic.isEvalGroupPublished(groups.get(0).getEvalGroupId()) ? validGroups + 1 : validGroups; } valid = validGroups > 0; } } return valid; } // PERMISSIONS public boolean canTakeEvaluation(String userId, Long evaluationId, String evalGroupId) { LOG.debug("evalId: " + evaluationId + ", userId: " + userId + ", evalGroupId: " + evalGroupId); // grab the evaluation itself first EvalEvaluation eval = getEvaluationOrFail(evaluationId); boolean allowed = false; if (checkEvalStateValidForTaking(eval)) { // valid state if (checkEvalGroupValidForEval(eval, evalGroupId)) { // valid group (or at least some groups are valid for this eval) if (EvalConstants.EVALUATION_AUTHCONTROL_NONE.equals(eval.getAuthControl())) { // if this is anonymous then group membership does not matter allowed = true; } else if (EvalConstants.EVALUATION_AUTHCONTROL_KEY.equals(eval.getAuthControl())) { // if this uses a key then only the key matters // TODO add key check LOG.info("Evaluation key (" + eval.getAuthControl() + ") is not a valid evaluation authcontrol key"); allowed = false; } else if (EvalConstants.EVALUATION_AUTHCONTROL_AUTH_REQ.equals(eval.getAuthControl())) { if (commonLogic.isUserAdmin(userId)) { // short circuit the attempt to lookup every group in the system for the admin allowed = true; } else { if (evalGroupId == null) { // if no groupId is supplied then simply check to see if the user is in any of the groups assigned, // hopefully this is faster than checking if the user has the right permission in every group -AZ List<EvalAssignUser> userAssigns = getParticipantsForEval(evaluationId, userId, null, EvalAssignUser.TYPE_EVALUATOR, null, null, null); if (!userAssigns.isEmpty()) { Set<String> egids = EvalUtils.getGroupIdsFromUserAssignments(userAssigns); String[] evalGroupIds = egids.toArray(new String[egids.size()]); long count = dao.countBySearch(EvalAssignGroup.class, new Search( new Restriction[] { new Restriction("evaluation.id", evaluationId), new Restriction("instructorApproval", Boolean.TRUE), new Restriction("evalGroupId", evalGroupIds) })); if (count > 0l) { // ok if at least one group is approved and in the set of groups this user can take evals in for this eval id allowed = true; } else { LOG.info("User (" + userId + ") is not in a valid group for evaluation (" + evaluationId + ")"); allowed = false; } } } else { // check the user permissions String[] evalGroupIds = null; // added check for user in specific group - EVALSYS-858 evalGroupIds = new String[] { evalGroupId }; List<EvalAssignUser> userAssigns = getParticipantsForEval(evaluationId, userId, evalGroupIds, EvalAssignUser.TYPE_EVALUATOR, null, null, null); if (userAssigns.isEmpty()) { LOG.info("User (" + userId + ") cannot take evaluation (" + evaluationId + ") without permission"); allowed = false; } else { // check if the eval allows multiple submissions if (eval.getModifyResponsesAllowed() != null && Objects.equals(eval.getModifyResponsesAllowed(), Boolean.FALSE)) { // cannot modify responses // check if the user already took this evaluation for this group EvalResponse response = getResponseForUserAndGroup(evaluationId, userId, evalGroupId); if (response != null && response.complete && response.isSubmitted()) { // user already has a response saved for this evaluation and evalGroupId LOG.info("User (" + userId + ") cannot take evaluation (" + evaluationId + ") again in this group (" + evalGroupId + "), completed response exists (" + response.getId() + ") from " + response.getEndTime() + " and this evaluation does not allow multiple attempts"); allowed = false; } else { // multiple responses ok allowed = true; } } else { // multiple responses ok allowed = true; } } } // evalgroupid null } // is admin } // auth type } else { // invalid group if (evalGroupId == null) { LOG.info("User (" + userId + ") cannot take evaluation (" + evaluationId + "), there are no enabled groups assigned"); } else { LOG.info("User (" + userId + ") cannot take evaluation (" + evaluationId + ") with group (" + evalGroupId + "), group disabled or user not a member"); } } } else { // invalid state String state = EvalUtils.getEvaluationState(eval, false); LOG.info("User (" + userId + ") cannot take evaluation (" + evaluationId + ") when eval state is: " + state); } return allowed; } public boolean canBeginEvaluation(String userId) { LOG.debug("Checking begin eval for: " + userId); boolean isAdmin = commonLogic.isUserAdmin(userId); if (isAdmin && (dao.countAll(EvalTemplate.class) > 0)) { // admin can access all templates and create an evaluation if // there is at least one template return true; } Boolean instructorAllowedCreateEvals = (Boolean) settings .get(EvalSettings.INSTRUCTOR_ALLOWED_CREATE_EVALUATIONS); if (instructorAllowedCreateEvals != null && instructorAllowedCreateEvals) { // check if this user has the assign evals permission in any groups int permCount = commonLogic.countEvalGroupsForUser(userId, EvalConstants.PERM_ASSIGN_EVALUATION); if (permCount > 0) { LOG.debug("User has permission to assign evaluation in at least one group"); /* * TODO - this check needs to be more robust at some point * currently we are ignoring shared and visible templates - AZ */ int count = dao.countSharedEntitiesForUser(EvalTemplate.class, userId, new String[] { EvalConstants.SHARING_PUBLIC, EvalConstants.SHARING_PRIVATE }, null, null, null, new String[] { "notEmpty" }); if (count > 0) { // if they can access at least one template with an item then they can create an evaluation return true; } } } return false; } public boolean canControlEvaluation(String userId, Long evaluationId) { LOG.debug("evalId: " + evaluationId + ",userId: " + userId); EvalEvaluation eval = getEvaluationOrFail(evaluationId); return securityChecks.canUserControlEvaluation(userId, eval); } public boolean canRemoveEvaluation(String userId, Long evaluationId) { LOG.debug("evalId: " + evaluationId + ",userId: " + userId); EvalEvaluation eval = getEvaluationOrFail(evaluationId); boolean allowed; try { allowed = securityChecks.canUserRemoveEval(userId, eval); } catch (IllegalStateException e) { allowed = false; } catch (SecurityException e) { LOG.debug("User (" + userId + ") cannot remove evalaution: " + eval.getId() + ", " + e.getMessage()); allowed = false; } return allowed; } // EVAL AND ASSIGN GROUPS public int countEvaluationGroups(Long evaluationId, boolean includeUnApproved) { LOG.debug("evalId: " + evaluationId); Search search = new Search("evaluation.id", evaluationId); if (!includeUnApproved) { // only include those that are approved search.addRestriction(new Restriction("instructorApproval", Boolean.TRUE)); } int count = (int) dao.countBySearch(EvalAssignGroup.class, search); return count; } public EvalAssignGroup getAssignGroupByEid(String eid) { EvalAssignGroup eag = null; if (eid != null) { eag = dao.findOneBySearch(EvalAssignGroup.class, new Search("eid", eid)); } return eag; } public EvalAssignGroup getAssignGroupById(Long assignGroupId) { LOG.debug("assignGroupId: " + assignGroupId); EvalAssignGroup eag = (EvalAssignGroup) dao.findById(EvalAssignGroup.class, assignGroupId); return eag; } public EvalAssignGroup getAssignGroupByEvalAndGroupId(Long evaluationId, String evalGroupId) { LOG.debug("evaluationId: " + evaluationId + ", evalGroupId: " + evalGroupId); if (evaluationId == null || evalGroupId == null || "".equals(evalGroupId)) { throw new IllegalArgumentException("evaluationId and evalGroupId must not be null"); } EvalAssignGroup assignGroup = dao.findOneBySearch(EvalAssignGroup.class, new Search(new Restriction[] { new Restriction("evaluation.id", evaluationId), new Restriction("evalGroupId", evalGroupId) })); return assignGroup; } public List<EvalAssignHierarchy> getAssignHierarchyByEval(Long evaluationId) { List<EvalAssignHierarchy> l = dao.findBySearch(EvalAssignHierarchy.class, new Search(new Restriction[] { new Restriction("evaluation.id", evaluationId), new Restriction("nodeId", "", Restriction.NOT_NULL) }, new Order("id"))); return l; } public EvalAssignHierarchy getAssignHierarchyById(Long assignHierarchyId) { EvalAssignHierarchy eah = (EvalAssignHierarchy) dao.findById(EvalAssignHierarchy.class, assignHierarchyId); return eah; } public Map<Long, List<EvalAssignGroup>> getAssignGroupsForEvals(Long[] evaluationIds, boolean includeUnApproved, Boolean includeHierarchyGroups) { LOG.debug( "evalIds: " + ArrayUtils.arrayToString(evaluationIds) + ", includeUnApproved=" + includeUnApproved); Map<Long, List<EvalAssignGroup>> evals = new TreeMap<>(); if (evaluationIds != null && evaluationIds.length > 0) { // create the inner lists for (Long evaluationId : evaluationIds) { List<EvalAssignGroup> innerList = new ArrayList<>(); evals.put(evaluationId, innerList); } Search search = new Search("evaluation.id", evaluationIds); if (!includeUnApproved) { // only include those that are approved search.addRestriction(new Restriction("instructorApproval", Boolean.TRUE)); } // include all groups unless this is not null and then we limit if (includeHierarchyGroups != null) { if (includeHierarchyGroups) { // only include those which were added via nodes search.addRestriction(new Restriction("nodeId", "", Restriction.NOT_NULL)); } else { // only include those which were added directly (i.e. nodeId = null) search.addRestriction(new Restriction("nodeId", "", Restriction.NULL)); } } // get all the groups for the given eval ids in one storage call search.addOrder(new Order("evalGroupId")); List<EvalAssignGroup> l = dao.findBySearch(EvalAssignGroup.class, search); for (int i = 0; i < l.size(); i++) { EvalAssignGroup eac = l.get(i); // put stuff in inner list Long evalId = eac.getEvaluation().getId(); List<EvalAssignGroup> innerList = evals.get(evalId); innerList.add(eac); } } return evals; } public Map<Long, List<EvalGroup>> getEvalGroupsForEval(Long[] evaluationIds, boolean includeUnApproved, Boolean includeHierarchyGroups) { Map<Long, List<EvalGroup>> evals = new TreeMap<>(); Map<Long, List<EvalAssignGroup>> evalAGs = getAssignGroupsForEvals(evaluationIds, includeUnApproved, includeHierarchyGroups); // replace each assign group with an EvalGroup for (Entry<Long, List<EvalAssignGroup>> entry : evalAGs.entrySet()) { Long evalId = entry.getKey(); List<EvalAssignGroup> innerList = entry.getValue(); List<EvalGroup> newList = new ArrayList<>(); for (int i = 0; i < innerList.size(); i++) { EvalAssignGroup eag = innerList.get(i); String evalGroupId = eag.getEvalGroupId(); newList.add(commonLogic.makeEvalGroupObject(evalGroupId)); } evals.put(evalId, newList); } return evals; } public boolean canCreateAssignEval(String userId, Long evaluationId) { LOG.debug("userId: " + userId + ", evaluationId: " + evaluationId); boolean allowed = false; EvalEvaluation eval = getEvaluationOrFail(evaluationId); try { allowed = securityChecks.checkCreateAssignments(userId, eval); } catch (RuntimeException e) { LOG.info(e.getMessage()); } return allowed; } public boolean canDeleteAssignGroup(String userId, Long assignGroupId) { LOG.debug("userId: " + userId + ", assignGroupId: " + assignGroupId); boolean allowed = false; EvalAssignGroup assignGroup = getAssignGroupById(assignGroupId); if (assignGroup == null) { throw new IllegalArgumentException("Cannot find assign evalGroupId with this id: " + assignGroupId); } EvalEvaluation eval = getEvaluationOrFail(assignGroup.getEvaluation().getId()); try { allowed = securityChecks.checkRemoveAssignments(userId, assignGroup, eval); } catch (RuntimeException e) { LOG.info(e.getMessage()); } return allowed; } // RESPONSES public EvalResponse getResponseById(Long responseId) { LOG.debug("responseId: " + responseId); EvalResponse response = (EvalResponse) dao.findById(EvalResponse.class, responseId); return response; } public EvalResponse getResponseForUserAndGroup(Long evaluationId, String userId, String evalGroupId) { if (!checkEvaluationExists(evaluationId)) { throw new IllegalArgumentException("Invalid evaluation id, cannot find evaluation: " + evaluationId); } EvalResponse response = null; List<EvalResponse> responses = dao.findBySearch(EvalResponse.class, new Search(new Restriction[] { new Restriction("owner", userId), new Restriction("evaluation.id", evaluationId), new Restriction("evalGroupId", evalGroupId) })); if (responses.size() <= 0) { // do nothing, no response was found } else if (responses.size() == 1) { response = responses.get(0); } else { throw new IllegalStateException( "Invalid responses state, this user (" + userId + ") has more than 1 response " + "for evaluation (" + evaluationId + ") and evalGroupId (" + evalGroupId + ")"); } return response; } public List<Long> getResponseIds(Long evaluationId, String[] evalGroupIds, Boolean completed) { LOG.debug("evaluationId: " + evaluationId); if (dao.countBySearch(EvalEvaluation.class, new Search("id", evaluationId)) <= 0l) { throw new IllegalArgumentException("Could not find evaluation with id: " + evaluationId); } // pass through to the dao method List<Long> rids = dao.getResponseIds(evaluationId, evalGroupIds, null, completed); return rids; } public List<EvalResponse> getResponses(String userId, Long[] evaluationIds, String[] evalGroupIds, Boolean completed) { Search search = new Search(); makeResponsesSearchParams(userId, evaluationIds, evalGroupIds, completed, search); List<EvalResponse> responses = dao.findBySearch(EvalResponse.class, search); return responses; } public int countResponses(String userId, Long[] evaluationIds, String[] evalGroupIds, Boolean completed) { Search search = new Search(); makeResponsesSearchParams(userId, evaluationIds, evalGroupIds, completed, search); int count = (int) dao.countBySearch(EvalResponse.class, search); return count; } /** * Setup the responses search parameters, * this is here to reduce code duplication * @param userId * @param evaluationIds * @param evalGroupIds * @param completed * @param props * @param values * @param comparisons */ private void makeResponsesSearchParams(String userId, Long[] evaluationIds, String[] evalGroupIds, Boolean completed, Search search) { if (evaluationIds == null || evaluationIds.length == 0) { throw new IllegalArgumentException("evaluationIds cannot be null or empty"); } // basic search params search.addRestriction(new Restriction("evaluation.id", evaluationIds)); if (userId != null && userId.length() > 0) { // admin can see all responses if (!commonLogic.isUserAdmin(userId)) { search.addRestriction(new Restriction("owner", userId)); } } if (evalGroupIds != null && evalGroupIds.length > 0) { search.addRestriction(new Restriction("evalGroupId", evalGroupIds)); } if (completed != null) { // if endTime is null then the response is incomplete, if not null then it is complete search.addRestriction( new Restriction("endTime", "", completed ? Restriction.NOT_NULL : Restriction.NULL)); } } public boolean canModifyResponse(String userId, Long responseId) { LOG.debug("userId: " + userId + ", responseId: " + responseId); // get the response by id EvalResponse response = getResponseById(responseId); if (response == null) { throw new IllegalArgumentException("Cannot find response with id: " + responseId); } EvalEvaluation eval = getEvaluationOrFail(response.getEvaluation().getId()); // valid state, check perms and locked try { return securityChecks.checkUserModifyResponse(userId, response, eval); } catch (RuntimeException e) { LOG.info(e.getMessage()); } return false; } // EMAIL TEMPLATES public List<EvalEmailTemplate> getEmailTemplatesForUser(String userId, String emailTemplateTypeConstant, Boolean includeDefaultsOnly) { Search search = new Search(); if (emailTemplateTypeConstant != null) { search.addRestriction(new Restriction("type", emailTemplateTypeConstant)); } // admin can see all if (!commonLogic.isUserAdmin(userId)) { search.addRestriction(new Restriction("owner", userId)); } if (includeDefaultsOnly != null) { search.addRestriction(new Restriction("defaultType", "", includeDefaultsOnly ? Restriction.NOT_NULL : Restriction.NULL)); } List<EvalEmailTemplate> templates = dao.findBySearch(EvalEmailTemplate.class, search); return templates; } public EvalEmailTemplate getDefaultEmailTemplate(String emailTemplateTypeConstant) { LOG.debug("emailTemplateTypeConstant: " + emailTemplateTypeConstant); if (emailTemplateTypeConstant == null) { throw new IllegalArgumentException("Invalid emailTemplateTypeConstant, cannot be null"); } // fetch template by type List<EvalEmailTemplate> l = dao.findBySearch(EvalEmailTemplate.class, new Search("defaultType", emailTemplateTypeConstant)); if (l.isEmpty()) { throw new IllegalArgumentException( "Could not find any default template for type constant: " + emailTemplateTypeConstant); } return (EvalEmailTemplate) l.get(0); } public EvalEmailTemplate getEmailTemplate(Long evaluationId, String emailTemplateTypeConstant) { // get evaluation EvalEvaluation eval = getEvaluationOrFail(evaluationId); // check the type constant Long emailTemplateId = null; if (EvalConstants.EMAIL_TEMPLATE_AVAILABLE.equals(emailTemplateTypeConstant) || EvalConstants.EMAIL_TEMPLATE_CONSOLIDATED_AVAILABLE.equals(emailTemplateTypeConstant) || EvalConstants.EMAIL_TEMPLATE_AVAILABLE_EVALUATEE.equals(emailTemplateTypeConstant)) { if (eval.getAvailableEmailTemplate() != null) { emailTemplateId = eval.getAvailableEmailTemplate().getId(); } } else if (EvalConstants.EMAIL_TEMPLATE_REMINDER.equals(emailTemplateTypeConstant) || EvalConstants.EMAIL_TEMPLATE_CONSOLIDATED_REMINDER.equals(emailTemplateTypeConstant)) { if (eval.getReminderEmailTemplate() != null) { emailTemplateId = eval.getReminderEmailTemplate().getId(); } } else if (EvalConstants.EMAIL_TEMPLATE_SUBMITTED.equals(emailTemplateTypeConstant)) { if (eval.getSubmissionConfirmationEmailTemplate() != null) { emailTemplateId = eval.getSubmissionConfirmationEmailTemplate().getId(); } } else { throw new IllegalArgumentException("Invalid emailTemplateTypeConstant: " + emailTemplateTypeConstant); } EvalEmailTemplate emailTemplate = null; if (emailTemplateId != null) { emailTemplate = (EvalEmailTemplate) dao.findById(EvalEmailTemplate.class, emailTemplateId); } if (emailTemplate == null || emailTemplate.getMessage() == null) { emailTemplate = getDefaultEmailTemplate(emailTemplateTypeConstant); } return emailTemplate; } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#getEmailTemplate(java.lang.Long) */ public EvalEmailTemplate getEmailTemplate(Long emailTemplateId) { EvalEmailTemplate emailTemplate = (EvalEmailTemplate) dao.findById(EvalEmailTemplate.class, emailTemplateId); return emailTemplate; } // PERMISSIONS public boolean canControlEmailTemplate(String userId, Long evaluationId, String emailTemplateTypeConstant) { LOG.debug("userId: " + userId + ", evaluationId: " + evaluationId + ", emailTemplateTypeConstant: " + emailTemplateTypeConstant); // get evaluation EvalEvaluation eval = getEvaluationOrFail(evaluationId); // get the email template EvalEmailTemplate emailTemplate = getEmailTemplate(evaluationId, emailTemplateTypeConstant); // check the permissions and state try { return securityChecks.checkEvalTemplateControl(userId, eval, emailTemplate); } catch (RuntimeException e) { LOG.info(e.getMessage()); } return false; } public boolean canControlEmailTemplate(String userId, Long evaluationId, Long emailTemplateId) { LOG.debug( "userId: " + userId + ", evaluationId: " + evaluationId + ", emailTemplateId: " + emailTemplateId); // get the email template EvalEmailTemplate emailTemplate = getEmailTemplateOrFail(emailTemplateId); // get evaluation EvalEvaluation eval = null; if (evaluationId != null) { eval = getEvaluationOrFail(evaluationId); // make sure this template is associated with this evaluation if (eval.getAvailableEmailTemplate() != null && emailTemplate.getId().equals(eval.getAvailableEmailTemplate().getId())) { LOG.debug("template matches available template from eval (" + eval.getId() + ")"); } else if (eval.getReminderEmailTemplate() != null && emailTemplate.getId().equals(eval.getReminderEmailTemplate().getId())) { LOG.debug("template matches reminder template from eval (" + eval.getId() + ")"); } else { throw new IllegalArgumentException("email template (" + emailTemplate.getId() + ") does not match any template from eval (" + eval.getId() + ")"); } } // check the permissions and state try { return securityChecks.checkEvalTemplateControl(userId, eval, emailTemplate); } catch (RuntimeException e) { LOG.info(e.getMessage()); } return false; } // PRIVATE METHODS /** * @param emailTemplateId * @return */ private EvalEmailTemplate getEmailTemplateOrFail(Long emailTemplateId) { EvalEmailTemplate emailTemplate = (EvalEmailTemplate) dao.findById(EvalEmailTemplate.class, emailTemplateId); if (emailTemplate == null) { throw new IllegalArgumentException("Cannot find email template with this id: " + emailTemplateId); } return emailTemplate; } /** * Gets the evaluation or throws exception, * reduce code duplication * @param evaluationId * @return eval for this id * @throws IllegalArgumentException if no eval exists */ private EvalEvaluation getEvaluationOrFail(Long evaluationId) { EvalEvaluation eval = getEvaluationById(evaluationId); if (eval == null) { throw new IllegalArgumentException("Cannot find evaluation with id: " + evaluationId); } return eval; } private void fixupEvaluation(EvalEvaluation evaluation) { if (evaluation != null) { // add in any needed checks or change storage that is needed here evaluation.useDateTimes = (Boolean) settings.get(EvalSettings.EVAL_USE_DATE_TIME); } } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#countEvaluations(java.lang.String) */ public int countEvaluations(String searchString) { if (searchString == null || searchString.equals("")) { searchString = "%"; } else { searchString = "%" + searchString + "%"; } Object[] values = new Object[] { searchString }; String[] props = new String[] { "title" }; int[] comparisons = new int[] { Restriction.LIKE }; Search search = new Search(props, values, comparisons); return (int) this.dao.countBySearch(EvalEvaluation.class, search); } /* (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#getEvaluations(java.lang.String, java.lang.String, int, int) */ public List<EvalEvaluation> getEvaluations(String searchString, String order, int startResult, int maxResults) { if (searchString == null || searchString.equals("")) { searchString = "%"; } else { searchString = "%" + searchString + "%"; } Object[] values = new Object[] { searchString }; String[] props = new String[] { "title" }; int[] comparisons = new int[] { Restriction.LIKE }; Search search = new Search(props, values, comparisons); search.addOrder(new Order(order)); search.setStart(startResult); search.setLimit(maxResults); return this.dao.findBySearch(EvalEvaluation.class, search); } public EvalEmailTemplate getEmailTemplateByEid(String eid) { EvalEmailTemplate template = null; if (eid != null) { template = dao.findOneBySearch(EvalEmailTemplate.class, new Search("eid", eid)); } return template; } public List<Long> synchronizeUserAssignments(Long evaluationId, String evalGroupId) { return null; } /* * (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#getConsolidatedEmailMapping(java.lang.Boolean, java.lang.String, int, int) */ public List<Map<String, Object>> getConsolidatedEmailMapping(boolean sendingAvailableEmails, int pageSize, int page) { return this.dao.getConsolidatedEmailMapping(sendingAvailableEmails, pageSize, page); } /* * (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#selectConsoliatedEmailRecipients(boolean, java.util.Date, boolean, java.util.Date, java.lang.String) */ public int selectConsoliatedEmailRecipients(boolean useAvailableEmailSent, Date availableEmailSent, boolean useReminderEmailSent, Date reminderEmailSent, String emailTemplateType) { return this.dao.selectConsolidatedEmailRecipients(useAvailableEmailSent, availableEmailSent, useReminderEmailSent, reminderEmailSent, emailTemplateType); } /* * (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#resetConsolidatedEmailRecipients() */ public int resetConsolidatedEmailRecipients() { return this.dao.resetConsolidatedEmailRecipients(); } public Set<String> getInProgressEvaluationOwners() { boolean activeEvaluationsOnly = true; List<EvalResponse> responses = this.dao.getResponsesSavedInProgress(activeEvaluationsOnly); Set<String> results = new HashSet<>(); for (EvalResponse response : responses) { results.add(response.getOwner()); } return results; } /* * (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEvaluationService#countDistinctGroupsInConsolidatedEmailMapping() */ public int countDistinctGroupsInConsolidatedEmailMapping() { return this.dao.countDistinctGroupsInConsolidatedEmailMapping(); } public List<EvalEvaluation> getEvaluationsForEvalGroups(String[] evalGroupIds, int startResult, int maxResults) { if (evalGroupIds.length > 0) { return dao.getEvaluationsForOwnerAndGroups("", evalGroupIds, null, startResult, maxResults, Boolean.TRUE); } else { return new ArrayList<EvalEvaluation>(); } } }