/*
* #%L
* Course Signup Implementation
* %%
* Copyright (C) 2010 - 2013 University of Oxford
* %%
* 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://opensource.org/licenses/ecl2
*
* 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.
* #L%
*/
package uk.ac.ox.oucs.vle;
import java.util.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import uk.ac.ox.oucs.vle.email.EmailSendingService;
import uk.ac.ox.oucs.vle.email.StateChange;
public class CourseSignupServiceImpl implements CourseSignupService {
private final static Log log = LogFactory.getLog(CourseSignupServiceImpl.class);
private CourseDAO dao;
private SakaiProxy proxy;
private SearchService searchService;
private EmailSendingService emailSendingService;
private NowService now;
protected final Comparator<CourseGroup> noDateCompatator = new NoDateComparator();
public void setDao(CourseDAO dao) {
this.dao = dao;
}
public void setProxy(SakaiProxy proxy) {
this.proxy = proxy;
}
public void setSearchService(SearchService searchService) {
this.searchService = searchService;
}
public void setNowService(NowService now) {
this.now = now;
}
public void setEmailSendingService(EmailSendingService emailSendingService) {
this.emailSendingService = emailSendingService;
}
/**
*
*/
public void approve(String signupId) {
approve(signupId, false, proxy.getCurrentPlacementId());
}
public void approve(String signupId, boolean skipAuth, String placementId) {
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
throw new NotFoundException(signupId);
}
CourseGroupDAO groupDao = signupDao.getGroup();
if (!skipAuth) {
if (groupDao.getSupervisorApproval()) {
String currentUserId = proxy.getCurrentUser().getId();
boolean canApprove = false;
if (currentUserId.equals(signupDao.getSupervisorId())) {
canApprove = true;
} else {
canApprove = isAdministrator(groupDao, currentUserId, canApprove);
}
if (!canApprove) {
throw new PermissionDeniedException(currentUserId);
}
}
}
Status oldStatus = signupDao.getStatus();
signupDao.setStatus(Status.APPROVED);
signupDao.setAmended(getNow());
dao.save(signupDao);
proxy.logEvent(groupDao.getCourseId(), EVENT_SIGNUP, placementId);
//departmental approval
boolean departmentApproval = false;
CourseDepartmentDAO departmentDao = null;
if (null != signupDao.getDepartment()) {
departmentDao = dao.findDepartmentByCode(signupDao.getDepartment());
if (null != departmentDao) {
if (departmentDao.getApprove()) {
if (!departmentDao.getApprovers().isEmpty()) {
departmentApproval = true;
}
}
}
}
if (departmentApproval) {
sendMails(oldStatus, signupId, placementId, emailSendingService);
} else {
confirm(signupId, skipAuth, placementId);
}
}
/**
*
*/
public void accept(String signupId) {
accept(signupId, false, proxy.getCurrentPlacementId());
}
public void accept(String signupId, boolean skipAuth, String placementId) {
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
throw new NotFoundException(signupId);
}
CourseGroupDAO groupDao = signupDao.getGroup();
if (!skipAuth) {
if (groupDao.getAdministratorApproval()) {
String currentUserId = proxy.getCurrentUser().getId();
boolean canAccept = false;
// If is course admin on one of the components.
canAccept = isAdministrator(signupDao.getGroup(), currentUserId, canAccept);
if (!canAccept) {
throw new PermissionDeniedException(currentUserId);
}
}
}
if (!Status.PENDING.equals(signupDao.getStatus()) &&
!Status.WAITING.equals(signupDao.getStatus())) {
throw new IllegalStateException("You can only accept signups that are waiting or pending.");
}
for (CourseComponentDAO componentDao : signupDao.getComponents()) {
componentDao.setTaken(componentDao.getTaken()+1);
dao.save(componentDao);
}
Status oldStatus = signupDao.getStatus();
signupDao.setStatus(Status.ACCEPTED);
signupDao.setAmended(getNow());
dao.save(signupDao);
// Send emails
proxy.logEvent(signupDao.getGroup().getCourseId(), EVENT_ACCEPT, placementId);
if (groupDao.getSupervisorApproval()) {
sendMails(oldStatus, signupId, placementId, emailSendingService);
} else {
approve(signupId, skipAuth, placementId);
}
}
/**
*
*/
public void confirm(String signupId) {
confirm(signupId, false, proxy.getCurrentPlacementId());
}
public void confirm(String signupId, boolean skipAuth, String placementId) {
String currentUserId = proxy.getCurrentUser().getId();
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
throw new NotFoundException(signupId);
}
CourseGroupDAO groupDao = signupDao.getGroup();
boolean departmentApproval = false;
if (null != signupDao.getDepartment()) {
CourseDepartmentDAO department = dao.findDepartmentByCode(signupDao.getDepartment());
if (null != department) {
departmentApproval = department.getApprove();
}
}
if (!skipAuth) {
if (departmentApproval) {
List<CourseDepartmentDAO> departments = dao.findApproverDepartments(currentUserId);
boolean canConfirm = false;
for (CourseDepartmentDAO dept : departments) {
if (dept.getCode().equals(signupDao.getDepartment())) {
canConfirm = true;
break;
}
}
if (!canConfirm) {
throw new PermissionDeniedException(currentUserId);
}
}
}
Status oldStatus = signupDao.getStatus();
signupDao.setStatus(Status.CONFIRMED);
signupDao.setAmended(getNow());
dao.save(signupDao);
proxy.logEvent(groupDao.getCourseId(), EVENT_SIGNUP, placementId);
sendMails(oldStatus, signupId, placementId, emailSendingService);
}
/**
*
*/
public void waiting(String signupId) {
waiting(signupId, false, proxy.getCurrentPlacementId());
}
public void waiting(String signupId, boolean skipAuth, String placementId) {
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
throw new NotFoundException(signupId);
}
CourseGroupDAO groupDao = signupDao.getGroup();
if (!skipAuth) {
if (groupDao.getAdministratorApproval()) {
String currentUserId = proxy.getCurrentUser().getId();
boolean canAccept = false;
// If is course admin on one of the components.
canAccept = isAdministrator(signupDao.getGroup(), currentUserId, canAccept);
if (!canAccept) {
throw new PermissionDeniedException(currentUserId);
}
}
}
if (!Status.PENDING.equals(signupDao.getStatus())) {
throw new IllegalStateException("You can only add to waiting list signups that pending.");
}
Status oldStatus = signupDao.getStatus();
signupDao.setStatus(Status.WAITING);
signupDao.setAmended(getNow());
dao.save(signupDao);
proxy.logEvent(signupDao.getGroup().getCourseId(), EVENT_WAITING, placementId);
sendMails(oldStatus, signupId, placementId, emailSendingService);
}
/**
*
*/
public String findSupervisor(String search) {
// TODO Auto-generated method stub
return null;
}
/**
*
*/
public void setSupervisor(String signupId, String supervisorId) {
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
throw new NotFoundException(signupId);
}
String currentUserId = proxy.getCurrentUser().getId();
if (!isAdministrator(signupDao.getGroup(), currentUserId, false)) {
throw new PermissionDeniedException(currentUserId);
}
String currentSupervisorId = signupDao.getSupervisorId();
if (null == currentSupervisorId) {
signupDao.setSupervisorId(supervisorId);
dao.save(signupDao);
}
}
/**
* @inheritDoc
*/
public void setHideCourse(String courseId, boolean hideGroup) {
UserProxy user = proxy.getCurrentUser();
CourseGroupDAO courseGroupDao = dao.findCourseGroupById(courseId);
if (!isAdministrator(courseGroupDao, user.getId(), false)) {
throw new PermissionDeniedException(user.getId());
}
courseGroupDao.setHideGroup(hideGroup);
dao.save(courseGroupDao);
// Re-index. This should be re-factored so that all saves on the CourseGroup
// cause a re-index to happen.
searchService.addCourseGroup(new CourseGroupImpl(courseGroupDao, this));
searchService.tidyUp();
}
/**
*
*/
public List<CourseGroup> getAdministering() {
String userId = proxy.getCurrentUser().getId();
List <CourseGroupDAO> groupDaos;
if (proxy.isAdministrator()) {
groupDaos = dao.findAllGroups();
} else {
groupDaos = dao.findAdminCourseGroups(userId);
}
List<CourseGroup> groups = new ArrayList<CourseGroup>(groupDaos.size());
for(CourseGroupDAO groupDao : groupDaos) {
groups.add(new CourseGroupImpl(groupDao, this));
}
return groups;
}
/**
* Get list of course groups for which current user is a teacher
*/
public List<CourseGroup> getLecturing() {
String userId = proxy.getCurrentUser().getId();
List <CourseGroupDAO> groupDaos = dao.findLecturingCourseGroups(userId);
List<CourseGroup> groups = new ArrayList<CourseGroup>(groupDaos.size());
for(CourseGroupDAO groupDao : groupDaos) {
groups.add(new CourseGroupImpl(groupDao, this));
}
return groups;
}
/**
*
*/
public List<CourseSignup> getPendings() {
String currentUser = proxy.getCurrentUser().getId();
List <CourseSignupDAO> signupDaos = dao.findSignupPending(currentUser);
List<CourseSignup> signups = new ArrayList<CourseSignup>(signupDaos.size());
for(CourseSignupDAO signupDao : signupDaos) {
signups.add(new CourseSignupImpl(signupDao, this));
}
return signups;
}
/**
*
*/
public List<CourseSignup> getApprovals() {
String currentUser = proxy.getCurrentUser().getId();
List <CourseSignupDAO> signupDaos = dao.findSignupApproval(currentUser);
List<CourseSignup> signups = new ArrayList<CourseSignup>(signupDaos.size());
for(CourseSignupDAO signupDao : signupDaos) {
signups.add(new CourseSignupImpl(signupDao, this));
}
return signups;
}
/**
*
*/
public List<CourseSignup> getMySignups(Set<Status> statuses) {
String userId = proxy.getCurrentUser().getId();
if (log.isDebugEnabled()) {
log.debug("Loading all signups for : "+ userId+ " of status "+ statuses);
}
List<CourseSignup> signups = new ArrayList<CourseSignup>();
for (CourseSignupDAO signupDao: dao.findSignupForUser(userId, (statuses==null)?Collections.<Status>emptySet():statuses)) {
signups.add(new CourseSignupImpl(signupDao, this));
}
return signups;
}
/**
*
*/
public List<CourseSignup> getUserComponentSignups(String userId, Set<Status> statuses) {
if (log.isDebugEnabled()) {
log.debug("Loading all signups for : "+ userId+ " of status "+ statuses);
}
List<CourseSignup> signups = new ArrayList<CourseSignup>();
for (CourseSignupDAO signupDao: dao.findSignupForUser(userId, (statuses==null)?Collections.<Status>emptySet():statuses)) {
signups.add(new CourseSignupImpl(signupDao, this));
}
return signups;
}
/**
* Get a course group with components. The components can be limited by specifying a range to load.
*/
public CourseGroup getCourseGroup(String courseId, Range range) {
if (range == null) {
range = Range.UPCOMING;
}
CourseGroupDAO courseGroupDao = dao.findCourseGroupById(courseId);
CourseGroup courseGroup = null;
if (courseGroupDao != null) {
List<CourseComponentDAO> componentDAOs = dao.findCourseComponents(courseId, range, getNow());
courseGroup = new CourseGroupImpl(courseGroupDao, this, componentDAOs);
}
return courseGroup;
}
/**
*
*/
public List<CourseSignup> getCourseSignups(String courseId, Set<Status> statuses) {
// Find all the components and then find all the signups.
String userId = proxy.getCurrentUser().getId();
CourseGroupDAO groupDao = dao.findCourseGroupById(courseId);
if (groupDao == null) {
return null;
}
if(!isAdministrator(groupDao, userId, false) && !isLecturer(groupDao, proxy.getCurrentUser(), false)) {
throw new PermissionDeniedException(userId);
}
List<CourseSignupDAO> signupDaos = dao.findSignupByCourse(userId, courseId, statuses);
List<CourseSignup> signups = new ArrayList<CourseSignup>(signupDaos.size());
for(CourseSignupDAO signupDao: signupDaos) {
signups.add(new CourseSignupImpl(signupDao, this));
}
return signups;
}
public Integer getCountCourseSignups(String courseId, Set<Status> statuses) {
CourseGroupDAO groupDao = dao.findCourseGroupById(courseId);
if (groupDao == null) {
return null;
}
return dao.countSignupByCourse(courseId, statuses, getNow());
}
public String getDirectUrl(String courseId) {
return proxy.getDirectUrl(courseId);
}
/**
*
*/
public CourseComponent getCourseComponent(String componentId) {
CourseComponentDAO componentDao = dao.findCourseComponent(componentId);
return new CourseComponentImpl(componentDao);
}
public List<CourseComponent> getAllComponents() {
List<CourseComponentDAO> componentDaos = dao.findAllComponents();
List<CourseComponent> courseComponents = new ArrayList<CourseComponent>();
for (CourseComponentDAO componentDao : componentDaos) {
courseComponents.add(new CourseComponentImpl(componentDao));
}
return courseComponents;
}
/**
*
*/
public List<CourseSignup> getComponentSignups(String componentId, Set<Status> statuses)
throws NotFoundException {
return getComponentSignups(componentId, statuses, null);
}
public List<CourseSignup> getComponentSignups(String componentId, Set<Status> statuses, Integer year)
throws NotFoundException {
// Permission check.
CourseComponentDAO componentDao = dao.findCourseComponent(componentId);
if (componentDao == null) {
throw new NotFoundException(componentId);
}
UserProxy currentUser = proxy.getCurrentUser();
if (!isAdministrator(componentDao) && !isLecturer(componentDao, currentUser)) {
throw new PermissionDeniedException(currentUser.getId());
}
List<CourseSignupDAO> signupDaos = dao.findSignupByComponent(componentId, statuses, year);
List<CourseSignup> signups = new ArrayList<CourseSignup>(signupDaos.size());
for(CourseSignupDAO signupDao : signupDaos) {
signups.add(new CourseSignupImpl(signupDao, this));
}
return signups;
}
/**
* Check if the current user is a member of a set.
* @param userIds The set of user IDs to check
* @return <code>true</code> if the user is in the set.
*/
boolean containsCurrentUser(Set<String> userIds) {
// This is used by the CourseGroup class
String currentUserId = proxy.getCurrentUser().getId();
return userIds.contains(currentUserId);
}
private boolean isAdministrator(CourseGroupDAO groupGroup, String currentUserId, boolean defaultValue) {
if (groupGroup.getAdministrators().contains(currentUserId)) {
return true;
}
UserProxy user = proxy.findUserById(currentUserId);
if (user != null && user.getEid().equals(this.getDaisyAdmin())) {
return true;
}
if (proxy.isAdministrator()) {
return true;
}
if (groupGroup.getSuperusers().contains(currentUserId)) {
return true;
}
return defaultValue;
}
private boolean isLecturer(CourseGroupDAO groupGroup, UserProxy user, boolean defaultValue) {
for (CourseComponentDAO componentDao : groupGroup.getComponents()) {
if (isLecturer(componentDao, user)) {
return true;
}
}
return defaultValue;
}
private boolean isAdministrator(CourseComponentDAO componentDao) {
UserProxy user = proxy.getCurrentUser();
if (null == user) {
return false;
}
if (user.getEid().equals(this.getDaisyAdmin())) {
return true;
}
if (proxy.isAdministrator()) {
return true;
}
// Check all the CourseGroups
for (CourseGroupDAO groupDao: componentDao.getGroups()) {
if (isAdministrator(groupDao, user.getId(), false)) {
return true;
}
}
return false;
}
private boolean isLecturer(CourseComponentDAO componentDao, UserProxy user) {
if (null == user) {
return false;
}
if (user.getId().equals(componentDao.getTeacher())) {
return true;
}
return false;
}
/**
*
*/
public void reject(String signupId) {
reject(signupId, false, proxy.getCurrentPlacementId());
}
public void reject(String signupId, boolean skipAuth, String placementId) {
String currentUserId = proxy.getCurrentUser().getId();
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
throw new NotFoundException(signupId);
}
CourseSignup signup = new CourseSignupImpl(signupDao, this);
Status status = signupDao.getStatus();
if (Status.PENDING.equals(status) || Status.WAITING.equals(status)) { // Rejected at pending or waiting.
if (!skipAuth) {
if (!isAdministrator(signupDao.getGroup(), currentUserId, false)) {
throw new PermissionDeniedException(currentUserId);
}
}
signupDao.setStatus(Status.REJECTED);
signupDao.setAmended(getNow());
dao.save(signupDao);
proxy.logEvent(signupDao.getGroup().getCourseId(), EVENT_REJECT, placementId);
sendMails(status, signupId, placementId, emailSendingService);
} else if (Status.ACCEPTED.equals(status)) { // Rejected at supervisor stage
if (!skipAuth) {
if (!isAdministrator(signupDao.getGroup(), currentUserId, currentUserId.equals(signupDao.getSupervisorId()))) {
throw new PermissionDeniedException(currentUserId);
}
}
signupDao.setStatus(Status.REJECTED);
signupDao.setAmended(getNow());
dao.save(signupDao);
for (CourseComponentDAO componentDao: signupDao.getComponents()) {
componentDao.setTaken(componentDao.getTaken()-1);
dao.save(componentDao);
}
proxy.logEvent(signupDao.getGroup().getCourseId(), EVENT_REJECT, placementId);
sendMails(Status.ACCEPTED, signupId, placementId, emailSendingService);
} else if (Status.APPROVED.equals(status)) {// Rejected at approver stage
if (!skipAuth) {
boolean isApprover = dao.findDepartmentApprovers(signupDao.getDepartment()).contains(currentUserId);
if (!isAdministrator(signupDao.getGroup(), currentUserId, isApprover)) {
throw new PermissionDeniedException(currentUserId);
}
}
signupDao.setStatus(Status.REJECTED);
signupDao.setAmended(getNow());
dao.save(signupDao);
for (CourseComponentDAO componentDao: signupDao.getComponents()) {
componentDao.setTaken(componentDao.getTaken()-1);
dao.save(componentDao);
}
proxy.logEvent(signupDao.getGroup().getCourseId(), EVENT_REJECT, placementId);
sendMails(Status.ACCEPTED, signupId, placementId, emailSendingService);
} else {
throw new IllegalStateException("You can only reject signups that are WAITING, PENDING, ACCEPTED or APPROVED");
}
}
/**
*
*/
public void setSignupStatus(String signupId, Status newStatus) {
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
throw new NotFoundException(signupId);
}
String currentUserId = proxy.getCurrentUser().getId();
if (isAdministrator(signupDao.getGroup(), currentUserId, false)) {
Status currentStatus = signupDao.getStatus();
if (!currentStatus.equals(newStatus)) { // Check it actually needs changing.
signupDao.setStatus(newStatus);
signupDao.setAmended(getNow());
dao.save(signupDao);
int spaceAdjustment = (-currentStatus.getSpacesTaken()) + newStatus.getSpacesTaken();
if (spaceAdjustment != 0) {
for(CourseComponentDAO component: signupDao.getComponents()) {
component.setTaken(component.getTaken()+spaceAdjustment);
dao.save(component);
}
}
}
} else {
throw new PermissionDeniedException(currentUserId);
}
}
/**
* @inheritDoc
*/
public CourseSignup signup(String userId, String userName, String userEmail, String courseId, Set<String> componentIds, String supervisorId) {
CourseGroupDAO groupDao = dao.findCourseGroupById(courseId);
if (groupDao == null) {
throw new NotFoundException(courseId);
}
Set<CourseComponentDAO> componentDaos = loadComponents(componentIds, groupDao);
// Check the current user is the administrator for all the components.
String currentUserId = proxy.getCurrentUser().getId();
if (!isAdministrator(groupDao, currentUserId, false)) {
throw new PermissionDeniedException(currentUserId);
}
// Create the signup.
UserProxy user = null;
if (userId == null) {
// Check for the user by email.
if (userEmail == null) {
throw new IllegalArgumentException("If you don't supply a userId you must supply an email address");
}
user = proxy.findUserByEmail(userEmail);
if (user == null) {
user = proxy.newUser(userName, userEmail);
}
} else {
user = proxy.findUserById(userId);
}
CourseSignupDAO signupDao = dao.newSignup(user.getId(), supervisorId, getNow());
signupDao.setGroup(groupDao);
signupDao.setStatus(Status.PENDING);
signupDao.setAmended(getNow());
Department department = findPracDepartment(user.getPrimaryOrgUnit());
if (null != department) {
signupDao.setDepartment(department.getPracCode());
}
String signupId = dao.save(signupDao);
for (CourseComponentDAO componentDao: componentDaos) {
List<CourseSignupDAO> signupsToRemove = new ArrayList<CourseSignupDAO>();
for(CourseSignupDAO componentSignupDao: componentDao.getSignups()) {
if (componentSignupDao.getUserId().equals(user.getId())) {
signupsToRemove.add(componentSignupDao);
}
}
Set <CourseSignupDAO> signupDaos = componentDao.getSignups();
for (CourseSignupDAO removeSignup: signupsToRemove) {
// If they had already been accepted then decrement the taken count.
if (removeSignup.getStatus().equals(Status.APPROVED) ||
removeSignup.getStatus().equals(Status.ACCEPTED) ||
removeSignup.getStatus().equals(Status.CONFIRMED)) {
for (CourseComponentDAO signupComponentDao : removeSignup.getComponents()) {
signupComponentDao.setTaken(signupComponentDao.getTaken()-1);
signupComponentDao.getSignups().remove(removeSignup);
dao.save(signupComponentDao);
}
}
signupDaos.remove(removeSignup);
dao.remove(removeSignup);
}
componentDao.getSignups().add(signupDao);
componentDao.setTaken(componentDao.getTaken()+1);
dao.save(componentDao);
}
accept(signupId, false, null);
return new CourseSignupImpl(signupDao, this);
}
/**
* Signup by Student
*/
public CourseSignup signup(String courseId, Set<String> componentIds, String supervisorEmail,
String message, String specialReq) throws IllegalStateException, IllegalArgumentException {
CourseGroupDAO groupDao = dao.findCourseGroupById(courseId);
if (groupDao == null) {
throw new NotFoundException(courseId);
}
boolean full = false;
Set<Status> statuses = Collections.singleton(Status.WAITING);
if (dao.countSignupByCourse(courseId, statuses, getNow()).intValue() > 0) {
full = true;
}
Set<CourseComponentDAO> componentDaos = loadComponents(componentIds, groupDao);
// Check they are valid as a choice (in signup period (student), not for same component in same term)
UserProxy user = proxy.getCurrentUser();
Date now = getNow();
List<CourseSignupDAO> existingSignups = new ArrayList<CourseSignupDAO>();
for(CourseComponentDAO componentDao: componentDaos) {
if(componentDao.getOpens().after(now) || componentDao.getCloses().before(now)) {
throw new IllegalStateException("Component isn't currently open: "+ componentDao.getPresentationId());
}
if ( (componentDao.getSize()-componentDao.getTaken()) < 1) {
full = true;
}
for (CourseSignupDAO signupDao: componentDao.getSignups()) {
// Look for exisiting signups for these components
if (user.getId().equals(signupDao.getUserId())) {
existingSignups.add(signupDao);
if(!signupDao.getStatus().equals(Status.WITHDRAWN)) {
throw new IllegalStateException(
"User "+ user.getId()+ " already has a place on component: "+ componentDao.getPresentationId());
}
}
}
}
// Remove all traces of the existing signup.
for (CourseSignupDAO existingSignup :existingSignups) {
for (CourseComponentDAO componentDao: existingSignup.getComponents()) {
componentDao.getSignups().remove(existingSignup);
dao.save(componentDao);
}
dao.remove(existingSignup);
}
// Set the supervisor
String supervisorId = null;
if (null != supervisorEmail) {
UserProxy supervisor = proxy.findUserByEmail(supervisorEmail);
if (supervisor == null) {
if (groupDao.getSupervisorApproval()) {
throw new IllegalArgumentException(
"Can't find a supervisor with email: "+ supervisorEmail);
}
} else {
supervisorId = supervisor.getId();
}
}
// Create the signup.
CourseSignupDAO signupDao = dao.newSignup(user.getId(), supervisorId, getNow());
signupDao.setGroup(groupDao);
if (full) {
signupDao.setStatus(Status.WAITING);
} else {
signupDao.setStatus(Status.PENDING);
}
signupDao.setAmended(getNow());
signupDao.setMessage(message);
signupDao.setSpecialReq(specialReq);
Department department = findPracDepartment(user.getPrimaryOrgUnit());
if (null != department) {
signupDao.setDepartment(department.getPracCode());
} else {
signupDao.setDepartment(null);
}
String signupId = dao.save(signupDao);
// We're going to decrement the places on acceptance.
for (CourseComponentDAO componentDao: componentDaos) {
componentDao.getSignups().add(signupDao);
signupDao.getComponents().add(componentDao); // So when sending out email we know the components.
dao.save(componentDao);
}
proxy.logEvent(groupDao.getCourseId(), EVENT_SIGNUP, null);
// Now send emails.
// Old status, new status, signup ID.
String placementId = proxy.getCurrentPlacementId();
CourseSignup signup = new CourseSignupImpl(signupDao, this);
if (full || groupDao.getAdministratorApproval()) {
sendMails(null, signupId, placementId, emailSendingService);
} else {
accept(signupId, false, null);
}
return new CourseSignupImpl(signupDao, this);
}
/**
* Find all the components and check they are associated with the supplied course group.
* @param componentIds The component IDs to load.
* @param groupDao The course group to check they belong to.
* @return The loaded components.
* @throws IllegalArgumentException If there aren't any component IDs or they don't belong to the group.
* @throws NotFoundException If one of the component IDs couldn't be found.
*/
private Set<CourseComponentDAO> loadComponents(Set<String> componentIds, CourseGroupDAO groupDao) {
if (componentIds == null) {
throw new IllegalArgumentException("You must specify some components to signup to.");
}
Set<CourseComponentDAO> componentDaos = new HashSet<CourseComponentDAO>(componentIds.size());
for(String componentId: componentIds) {
CourseComponentDAO componentDao = dao.findCourseComponent(componentId);
if (componentDao != null) {
componentDaos.add(componentDao);
if (!componentDao.getGroups().contains(groupDao)) { // Check that the component is actually part of the set.
throw new IllegalArgumentException("The component: "+ componentId+ " is not part of the course: "+ groupDao.getCourseId());
}
} else {
throw new NotFoundException(componentId);
}
}
return componentDaos;
}
public void withdraw(String signupId) {
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
throw new NotFoundException(signupId);
}
Status oldStatus = signupDao.getStatus();
if (Status.ACCEPTED.equals(signupDao.getStatus()) ||
Status.APPROVED.equals(signupDao.getStatus()) ||
Status.CONFIRMED.equals(signupDao.getStatus())) {
for (CourseComponentDAO componentDao: signupDao.getComponents()) {
componentDao.setTaken(componentDao.getTaken()-1);
dao.save(componentDao);
}
}
signupDao.setStatus(Status.WITHDRAWN);
signupDao.setAmended(getNow());
dao.save(signupDao);
proxy.logEvent(signupDao.getGroup().getCourseId(), EVENT_WITHDRAW, null);
String placementId = proxy.getCurrentPlacementId();
sendMails(oldStatus, signupId, placementId, emailSendingService);
}
/**
* {@inheritDoc}
*/
@Override
public String split(String signupId, Set<String> componentPresentationIds) {
// Check we can find the signup.
CourseSignupDAO signupDAO = dao.findSignupById(signupId);
if (signupDAO == null) {
throw new NotFoundException(signupId);
}
String userId = proxy.getCurrentUser().getId();
if (!isAdministrator(signupDAO.getGroup(), userId, false)) {
throw new PermissionDeniedException(userId);
}
if (componentPresentationIds == null || componentPresentationIds.isEmpty()) {
throw new IllegalArgumentException("You must specify some componentPresentationIds.");
}
if (componentPresentationIds.size() >= signupDAO.getComponents().size()) {
throw new IllegalArgumentException("You can't specify all the componentPresentationIds in the signup.");
}
// This won't affect the take counts as we keep the same number of components and the new signup is in the
// same status as the existing one.
CourseSignupDAO newSignup = dao.newSignup(signupDAO.getUserId(), signupDAO.getSupervisorId(), getNow());
newSignup.setStatus(signupDAO.getStatus());
newSignup.setGroup(signupDAO.getGroup());
newSignup.setDepartment(signupDAO.getDepartment());
newSignup.setMessage(signupDAO.getMessage());
dao.save(newSignup);
// Now move the components to the new signup.
Set<CourseComponentDAO> newSignupComponents = new HashSet<CourseComponentDAO>();
// We don't modify arguments.
Set<String> remainingComponentIds = new HashSet<String>(componentPresentationIds);
for (CourseComponentDAO componentDAO: signupDAO.getComponents()) {
if (remainingComponentIds.remove(componentDAO.getPresentationId())) {
newSignupComponents.add(componentDAO);
componentDAO.getSignups().remove(signupDAO);
componentDAO.getSignups().add(newSignup);
dao.save(componentDAO);
}
}
// Check we removed them all, transactions will clear up the mess.
if (!remainingComponentIds.isEmpty()) {
throw new IllegalArgumentException("Some components weren't part of the signup: "+ componentPresentationIds);
}
return newSignup.getId();
}
public List<CourseGroup> getCourseGroupsByDept(String deptId, Range range, boolean externalUser) {
List<CourseGroupDAO> cgDaos = dao.findCourseGroupByDept(deptId, range, getNow(), externalUser);
List<CourseGroup> cgs = new ArrayList<CourseGroup>(cgDaos.size());
for (CourseGroupDAO cgDao: cgDaos) {
cgs.add(new CourseGroupImpl(cgDao, this));
}
return cgs;
}
public List<CourseGroup> getCourseGroupsBySubUnit(String subunitId, Range range, boolean externalUser) {
List<CourseGroupDAO> cgDaos = dao.findCourseGroupBySubUnit(subunitId, range, getNow(), externalUser);
List<CourseGroup> cgs = new ArrayList<CourseGroup>(cgDaos.size());
for (CourseGroupDAO cgDao: cgDaos) {
cgs.add(new CourseGroupImpl(cgDao, this));
}
return cgs;
}
public List<CourseGroup> getCourseGroupsByComponent(String componentId) {
List<CourseGroupDAO> cgDaos = dao.findCourseGroupByComponent(componentId);
List<CourseGroup> cgs = new ArrayList<CourseGroup>(cgDaos.size());
for (CourseGroupDAO cgDao: cgDaos) {
cgs.add(new CourseGroupImpl(cgDao, this));
}
return cgs;
}
public List<SubUnit> getSubUnitsByDept(String deptId) {
List<Object[]> subNodes = dao.findSubUnitByDept(deptId);
List<SubUnit> subUnits = new ArrayList<SubUnit>(subNodes.size());
for (Object[] subNode : subNodes) {
subUnits.add(new SubUnitImpl((String) subNode[0], (String) subNode[1]));
}
return subUnits;
}
public Map<String, String> getDepartments() {
List<CourseDepartmentDAO> subNodes = dao.findAllDepartments();
Map<String, String> departments = new HashMap<String, String>();
for (CourseDepartmentDAO departmentDAO : subNodes) {
departments.put(departmentDAO.getCode(), departmentDAO.getName());
}
return departments;
}
public Date getNow() {
return now.getNow();
}
/**
* Loads details about a user.
* @return The loaded user or null.
*/
UserProxy loadUser(String id) {
return proxy.findUserById(id);
}
public Department findPracDepartment(String primaryOrgUnit) {
CourseDepartmentDAO department = dao.findDepartmentByPrimaryOrgUnit(primaryOrgUnit);
if (null == department) {
return null;
}
return new DepartmentImpl(department);
}
/**
*
*/
public boolean isDepartmentCode(String code) {
return dao.findDepartmentByCode(code) != null;
}
public List<CourseGroup> search(String search, Range range, boolean external) {
String words[] = search.split(" ");
List<CourseGroupDAO> groupDaos = dao.findCourseGroupByWords(words, range, getNow(), external);
List<CourseGroup> groups = new ArrayList<CourseGroup>(groupDaos.size());
for(CourseGroupDAO groupDao: groupDaos) {
groups.add(new CourseGroupImpl(groupDao, this));
}
return groups;
}
public CourseSignup getCourseSignup(String signupId) {
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
return null;
}
String currentUserId = proxy.getCurrentUser().getId();
if (
currentUserId.equals(signupDao.getUserId()) ||
currentUserId.equals(signupDao.getSupervisorId()) ||
isAdministrator(signupDao.getGroup(), currentUserId, false)
) {
return new CourseSignupImpl(signupDao, this);
} else {
throw new PermissionDeniedException(currentUserId);
}
}
public CourseSignup getCourseSignupAnyway(String signupId) {
CourseSignupDAO signupDao = dao.findSignupById(signupId);
if (signupDao == null) {
return null;
} else {
return new CourseSignupImpl(signupDao, this);
}
}
public String[] getCourseSignupFromEncrypted(String encrypted) {
String string = proxy.uncode(encrypted);
if (null == string){
throw new IllegalStateException("the encryptied string cannot be decyphered");
}
return string.split("\\$");
}
/**
*
*/
public List<CourseGroup> getCourseCalendar(boolean external, String providerId) {
String userId = proxy.getCurrentUser().getId();
List <CourseComponentDAO> componentDaos = dao.findCourseGroupsByCalendar(external, providerId);
List<CourseGroup> groups = new ArrayList<CourseGroup>();
for (CourseComponentDAO componentDao : componentDaos) {
for (CourseGroupDAO groupDao : componentDao.getGroups()) {
CourseGroupDAO myGroupDao = (CourseGroupDAO)groupDao.clone();
myGroupDao.setComponents(Collections.singleton(componentDao));
groups.add(new CourseGroupImpl(myGroupDao, this));
}
}
return groups;
}
/**
*
*/
public List<CourseGroup> getCourseNoDates(boolean external, String providerId) {
String userId = proxy.getCurrentUser().getId();
List <CourseComponentDAO> componentDaos = dao.findCourseGroupsByNoDates(external, providerId);
List<CourseGroup> groups = new ArrayList<CourseGroup>();
for (CourseComponentDAO componentDao : componentDaos) {
for (CourseGroupDAO groupDao : componentDao.getGroups()) {
CourseGroupDAO myGroupDao = (CourseGroupDAO)groupDao.clone();
myGroupDao.setComponents(Collections.singleton(componentDao));
groups.add(new CourseGroupImpl(myGroupDao, this));
}
}
Collections.sort(groups, noDateCompatator);
return groups;
}
/**
* @return This returns the EID of the Daisy administrator.
*/
protected String getDaisyAdmin() {
return proxy.getConfigParam("daisy.administrator", "admin");
}
/**
*
* @return
*/
public Integer getRecentDays() {
return proxy.getConfigParam("recent.days", 14);
}
@Override
public CourseDepartmentImpl findDepartmentByCode(String departmentCode) {
CourseDepartmentDAO departmentDao = dao.findDepartmentByCode(departmentCode);
if (departmentDao != null) {
return new CourseDepartmentImpl(departmentDao.getCode(), departmentDao.getApprove(), departmentDao.getApprovers());
}
return null;
}
@Override
public List<CourseComponentExport> exportComponentSignups(String componentId, Set<Status> statuses, Integer year) {
List<Map> componentSignups = dao.findComponentSignups(componentId, statuses, year);
// These should be ordered already
List<CourseComponentExport> exports = new ArrayList<>();
CourseComponentExport export = null;
for (Map map : componentSignups) {
CourseSignupDAO signupDAO = (CourseSignupDAO) map.get("signup");
CourseComponentDAO componentDAO = (CourseComponentDAO) map.get("this");
CourseGroupDAO groupDAO = (CourseGroupDAO) map.get("group");
if (componentDAO == null) {
// We don't bail out here so that we still get a partial export.
log.error(String.format("Failed to get the complete data when exporting %s, %s, %d", componentId, statuses.toString(), year));
continue;
}
CourseComponent component = new CourseComponentImpl(componentDAO);
if (isAdministrator(componentDAO)) {
if (export == null || !export.getComponent().equals(component)) {
export = new CourseComponentExport(component);
exports.add(export);
}
if (signupDAO != null && groupDAO != null) {
CourseSignup signup = new CourseSignupImpl(signupDAO, this);
CourseGroup group = new CourseGroupImpl(groupDAO, this);
export.addSignup(new CourseSignupExport(signup, group));
}
}
}
return exports;
}
/**
* This should get called whenever a signup is changed.
* @param current The current signup status.
* @param old The original signup status, can be <code>null</code>.
* @param signupId The ID of the signup.
* @param placementId The current placement.
* @param emailSendingService
*/
public void sendMails(Status old, String signupId, String placementId, EmailSendingService emailSendingService) {
CourseSignup signup = getCourseSignupAnyway(signupId);
CourseDepartment department = null;
if (null != signup.getDepartment()) {
department = findDepartmentByCode(signup.getDepartment());
}
StateChange stateChange = new StateChange(old, signup, department, placementId);
emailSendingService.applyRules(stateChange);
}
}