uk.ac.cam.cl.dtg.isaac.api.managers.AssignmentManager.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.cam.cl.dtg.isaac.api.managers.AssignmentManager.java

Source

/*
 * Copyright 2015 Stephen Cummins
 *
 * Licensed under the Apache 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.apache.org/licenses/LICENSE-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 uk.ac.cam.cl.dtg.isaac.api.managers;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import uk.ac.cam.cl.dtg.isaac.dao.IAssignmentPersistenceManager;
import uk.ac.cam.cl.dtg.isaac.dto.AssignmentDTO;
import uk.ac.cam.cl.dtg.isaac.dto.GameboardDTO;
import uk.ac.cam.cl.dtg.segue.api.managers.GroupManager;
import uk.ac.cam.cl.dtg.segue.api.managers.IGroupObserver;
import uk.ac.cam.cl.dtg.segue.api.managers.UserAssociationManager;
import uk.ac.cam.cl.dtg.segue.api.managers.UserAccountManager;
import uk.ac.cam.cl.dtg.segue.auth.exceptions.NoUserException;
import uk.ac.cam.cl.dtg.segue.comm.EmailManager;
import uk.ac.cam.cl.dtg.segue.comm.EmailType;
import uk.ac.cam.cl.dtg.segue.dao.ResourceNotFoundException;
import uk.ac.cam.cl.dtg.segue.dao.SegueDatabaseException;
import uk.ac.cam.cl.dtg.segue.dao.content.ContentManagerException;
import uk.ac.cam.cl.dtg.segue.dto.UserGroupDTO;
import uk.ac.cam.cl.dtg.segue.dto.users.RegisteredUserDTO;
import uk.ac.cam.cl.dtg.segue.dto.users.UserSummaryDTO;

import com.google.api.client.util.Lists;
import com.google.inject.Inject;
import uk.ac.cam.cl.dtg.util.PropertiesLoader;

import static uk.ac.cam.cl.dtg.segue.api.Constants.HOST_NAME;

/**
 * AssignmentManager.
 */
public class AssignmentManager implements IGroupObserver {
    private static final Logger log = LoggerFactory.getLogger(AssignmentManager.class);

    private final IAssignmentPersistenceManager assignmentPersistenceManager;
    private final GroupManager groupManager;
    private final EmailManager emailManager;
    private final UserAccountManager userManager;
    private final GameManager gameManager;
    private final UserAssociationManager userAssociationManager;
    private final PropertiesLoader properties;

    /**
     * AssignmentManager.
     * 
     * @param assignmentPersistenceManager
     *            - to save assignments
     * @param groupManager
     *            - to allow communication with the group manager.
     * @param emailManager
     *            - email manager
     * @param userManager
     *            - the user manager object
     * @param gameManager
     *            - the game manager object
     * @param userAssociationManager
     *            - the userAssociationManager manager object
     */
    @Inject
    public AssignmentManager(final IAssignmentPersistenceManager assignmentPersistenceManager,
            final GroupManager groupManager, final EmailManager emailManager, final UserAccountManager userManager,
            final GameManager gameManager, final UserAssociationManager userAssociationManager,
            final PropertiesLoader properties) {
        this.assignmentPersistenceManager = assignmentPersistenceManager;
        this.groupManager = groupManager;
        this.emailManager = emailManager;
        this.userManager = userManager;
        this.gameManager = gameManager;
        this.userAssociationManager = userAssociationManager;
        this.properties = properties;
        groupManager.registerInterestInGroups(this);
    }

    /**
     * Get Assignments set for a given user.
     * 
     * @param user
     *            - to get the assignments for.
     * @return List of assignments for the given user.
     * @throws SegueDatabaseException
     *             - if we cannot complete a required database operation.
     */
    public Collection<AssignmentDTO> getAssignments(final RegisteredUserDTO user) throws SegueDatabaseException {
        List<UserGroupDTO> groups = groupManager.getGroupMembershipList(user);

        if (groups.size() == 0) {
            log.debug(String.format("User (%s) does not have any groups", user.getId()));
            return Lists.newArrayList();
        }

        List<AssignmentDTO> assignments = Lists.newArrayList();
        for (UserGroupDTO group : groups) {
            assignments.addAll(this.assignmentPersistenceManager.getAssignmentsByGroupId(group.getId()));
        }

        return assignments;
    }

    /**
     * getAssignmentById.
     * 
     * @param assignmentId
     *            to find
     * @return the assignment.
     * @throws SegueDatabaseException
     *             - if we cannot complete a required database operation.
     */
    public AssignmentDTO getAssignmentById(final Long assignmentId) throws SegueDatabaseException {
        return this.assignmentPersistenceManager.getAssignmentById(assignmentId);
    }

    /**
     * create Assignment.
     * 
     * @param newAssignment
     *            - to create - will be modified to include new id.
     * @return the assignment object now with the id field populated.
     * @throws SegueDatabaseException
     *             - if we cannot complete a required database operation.
     */
    public AssignmentDTO createAssignment(final AssignmentDTO newAssignment) throws SegueDatabaseException {
        Validate.isTrue(newAssignment.getId() == null, "The id field must be empty.");
        Validate.notNull(newAssignment.getGameboardId());
        Validate.notNull(newAssignment.getGroupId());

        if (assignmentPersistenceManager
                .getAssignmentsByGameboardAndGroup(newAssignment.getGameboardId(), newAssignment.getGroupId())
                .size() != 0) {
            log.error(
                    String.format("Duplicated Assignment Exception - cannot assign the same work %s to a group %s",
                            newAssignment.getGameboardId(), newAssignment.getGroupId()));
            throw new DuplicateAssignmentException("You cannot assign the same work to a group more than once.");
        }

        newAssignment.setCreationDate(new Date());
        newAssignment.setId(this.assignmentPersistenceManager.saveAssignment(newAssignment));

        UserGroupDTO userGroupDTO = groupManager.getGroupById(newAssignment.getGroupId());
        List<RegisteredUserDTO> users = groupManager.getUsersInGroup(userGroupDTO);

        GameboardDTO gameboard = gameManager.getGameboard(newAssignment.getGameboardId());

        //filter users so those that have revoked access to their data aren't emailed
        try {
            RegisteredUserDTO assignmentOwner = userManager.getUserDTOById(newAssignment.getOwnerUserId());

            for (Iterator<RegisteredUserDTO> iterator = users.iterator(); iterator.hasNext();) {
                RegisteredUserDTO user = iterator.next();
                UserSummaryDTO userSummary = userManager.convertToUserSummaryObject(user);
                if (!userAssociationManager.hasPermission(assignmentOwner, userSummary)) {
                    iterator.remove();
                }
            }

        } catch (NoUserException e1) {
            log.error(String.format("Could not find assignment owner (%s) for assignment (%s)",
                    newAssignment.getOwnerUserId(), newAssignment.getId()));
        }

        // inform all members of the group that there is now an assignment for them.
        try {
            final String gameboardURL = String.format("https://%s/#%s", properties.getProperty(HOST_NAME),
                    gameboard.getId());
            final String myAssignmentsURL = String.format("https://%s/assignments",
                    properties.getProperty(HOST_NAME));

            String gameboardName = gameboard.getId();
            if (gameboard.getTitle() != null) {
                gameboardName = gameboard.getTitle();
            }

            for (RegisteredUserDTO userDTO : users) {
                emailManager.sendTemplatedEmailToUser(userDTO,
                        emailManager.getEmailTemplateDTO("email-template-group-assignment"),
                        ImmutableMap.of("gameboardURL", gameboardURL, "gameboardName", gameboardName,
                                "myAssignmentsURL", myAssignmentsURL),
                        EmailType.ASSIGNMENTS);
            }

        } catch (ContentManagerException e) {
            log.error("Could not send group assignment emails due to content issue", e);
        }

        return newAssignment;
    }

    /**
     * Assignments set by user.
     * 
     * @param user
     *            - who set the assignments
     * @return the assignments.
     * @throws SegueDatabaseException
     *             - if we cannot complete a required database operation.
     */
    public List<AssignmentDTO> getAllAssignmentsSetByUser(final RegisteredUserDTO user)
            throws SegueDatabaseException {
        Validate.notNull(user);
        return this.assignmentPersistenceManager.getAssignmentsByOwner(user.getId());
    }

    /**
     * Assignments set by user and group.
     * 
     * @param user
     *            - who set the assignments
     * @param group
     *            - the group that was assigned the work.
     * @return the assignments.
     * @throws SegueDatabaseException
     *             - if we cannot complete a required database operation.
     */
    public List<AssignmentDTO> getAllAssignmentsSetByUserToGroup(final RegisteredUserDTO user,
            final UserGroupDTO group) throws SegueDatabaseException {
        Validate.notNull(user);
        Validate.notNull(group);
        return this.assignmentPersistenceManager.getAssignmentsByOwnerIdAndGroupId(user.getId(), group.getId());
    }

    /**
     * deleteAssignment.
     * 
     * @param assignment
     *            - to delete (must have an id).
     * @throws SegueDatabaseException
     *             - if we cannot complete a required database operation.
     */
    public void deleteAssignment(final AssignmentDTO assignment) throws SegueDatabaseException {
        Validate.notNull(assignment);
        Validate.notNull(assignment.getId());
        this.assignmentPersistenceManager.deleteAssignment(assignment.getId());
    }

    /**
     * findAssignmentByGameboardAndGroup.
     * 
     * @param gameboardId
     *            to match
     * @param groupId
     *            group id to match
     * @return assignment or null if none matches the parameters provided.
     * @throws SegueDatabaseException
     *             - if we cannot complete a required database operation.
     */
    public AssignmentDTO findAssignmentByGameboardAndGroup(final String gameboardId, final Long groupId)
            throws SegueDatabaseException {
        List<AssignmentDTO> assignments = this.assignmentPersistenceManager
                .getAssignmentsByGameboardAndGroup(gameboardId, groupId);

        if (assignments.size() == 0) {
            return null;
        } else if (assignments.size() == 1) {
            return assignments.get(0);
        }

        throw new SegueDatabaseException(
                String.format("Duplicate Assignment (group: %s) (gameboard: %s) Exception: %s", groupId,
                        gameboardId, assignments));
    }

    /**
     * findGroupsByGameboard.
     * 
     * @param user
     *            - owner of assignments (teacher)
     * @param gameboardId
     *            - the gameboard id to query
     * @return Empty List if none or a List or groups.
     * @throws SegueDatabaseException
     *             - If something goes wrong with database access.
     */
    public List<UserGroupDTO> findGroupsByGameboard(final RegisteredUserDTO user, final String gameboardId)
            throws SegueDatabaseException {
        Validate.notNull(user);
        Validate.notBlank(gameboardId);

        List<AssignmentDTO> allAssignments = this.getAllAssignmentsSetByUser(user);
        List<UserGroupDTO> groups = Lists.newArrayList();

        for (AssignmentDTO assignment : allAssignments) {
            if (assignment.getGameboardId().equals(gameboardId)) {
                try {
                    groups.add(groupManager.getGroupById(assignment.getGroupId()));
                } catch (ResourceNotFoundException e) {
                    // skip group as it no longer exists.
                    log.warn(String.format(
                            "Group (%s) that no longer exists referenced by assignment (%s). Skipping.",
                            assignment.getGroupId(), assignment.getId()));
                }
            }
        }

        return groups;
    }

    @Override
    public void onGroupMembershipRemoved(final UserGroupDTO group, final RegisteredUserDTO user) {
        // do nothing
    }

    @Override
    public void onMemberAddedToGroup(final UserGroupDTO group, final RegisteredUserDTO user) {
        Validate.notNull(group);
        Validate.notNull(user);

        // Try to email user to let them know
        try {
            RegisteredUserDTO groupOwner = this.userManager.getUserDTOById(group.getOwnerId());

            List<AssignmentDTO> existingAssignments = this.getAllAssignmentsSetByUserToGroup(groupOwner, group);

            emailManager.sendTemplatedEmailToUser(user,
                    emailManager.getEmailTemplateDTO("email-template-group-welcome"),
                    this.prepareGroupWelcomeEmailTokenMap(user, group, groupOwner, existingAssignments),
                    EmailType.SYSTEM);

        } catch (ContentManagerException e) {
            log.info(String.format("Could not send group welcome email "), e);
        } catch (NoUserException e) {
            log.info(String.format("Could not find owner user object of group %s", group.getId()), e);
        } catch (SegueDatabaseException e) {
            log.error("Unable to send group welcome e-mail due to a database error. Failing silently.", e);
        }
    }

    /**
     * Helper to build up the list of tokens for addToGroup email.
     *
     * @param userDTO - identity of user
     * @param userGroup - group being added to.
     * @param groupOwner - Owner of the group
     * @param existingAssignments - Any existing assignments that have been set.
     * @return a map of string to string, with some values that may want to be shown in the email.
     * @throws SegueDatabaseException if we can't get the gameboard details.
     */
    private Map<String, Object> prepareGroupWelcomeEmailTokenMap(final RegisteredUserDTO userDTO,
            final UserGroupDTO userGroup, final RegisteredUserDTO groupOwner,
            final List<AssignmentDTO> existingAssignments) throws SegueDatabaseException {
        Validate.notNull(userDTO);
        String groupOwnerName = "Unknown";

        if (groupOwner != null && groupOwner.getFamilyName() != null) {
            groupOwnerName = groupOwner.getFamilyName();
        }

        if (groupOwner != null && groupOwner.getGivenName() != null && !groupOwner.getGivenName().isEmpty()) {
            groupOwnerName = groupOwner.getGivenName().substring(0, 1) + ". " + groupOwnerName;
        }

        if (existingAssignments != null) {
            Collections.sort(existingAssignments, Comparator.comparing(AssignmentDTO::getCreationDate));
        }

        final DateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yy HH:mm");
        StringBuilder htmlSB = new StringBuilder();
        StringBuilder plainTextSB = new StringBuilder();
        final String accountURL = String.format("https://%s/account", properties.getProperty(HOST_NAME));

        if (existingAssignments != null && existingAssignments.size() > 0) {
            htmlSB.append("Your teacher has assigned the following assignments:<br>");
            plainTextSB.append("Your teacher has assigned the following assignments:\n");

            for (int i = 0; i < existingAssignments.size(); i++) {
                GameboardDTO gameboard = gameManager.getGameboard(existingAssignments.get(i).getGameboardId());
                String gameboardName = existingAssignments.get(i).getGameboardId();
                if (gameboard != null && gameboard.getTitle() != null && !gameboard.getTitle().isEmpty()) {
                    gameboardName = gameboard.getTitle();
                }

                String gameboardUrl = String.format("https://%s/#%s", properties.getProperty(HOST_NAME),
                        existingAssignments.get(i).getGameboardId());

                htmlSB.append(String.format("%d. <a href='%s'>%s</a> (set on %s)<br>", i + 1, gameboardUrl,
                        gameboardName, DATE_FORMAT.format(existingAssignments.get(i).getCreationDate())));

                plainTextSB.append(String.format("%d. %s (set on %s)\n", i + 1, gameboardName,
                        DATE_FORMAT.format(existingAssignments.get(i).getCreationDate())));
            }
        } else if (existingAssignments != null && existingAssignments.size() == 0) {
            htmlSB.append("No assignments have been set yet.<br>");
            plainTextSB.append("No assignments have been set yet.\n");
        }

        return new ImmutableMap.Builder<String, Object>()
                .put("teacherName", groupOwnerName == null ? "" : groupOwnerName).put("accountURL", accountURL)
                .put("assignmentsInfo", plainTextSB.toString()).put("assignmentsInfo_HTML", htmlSB.toString())
                .build();
    }
}