uk.org.rbc1b.roms.controller.volunteer.interview.InterviewSessionsController.java Source code

Java tutorial

Introduction

Here is the source code for uk.org.rbc1b.roms.controller.volunteer.interview.InterviewSessionsController.java

Source

/*
 * The MIT License
 *
 * Copyright 2014 RBC1B.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package uk.org.rbc1b.roms.controller.volunteer.interview;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import uk.org.rbc1b.roms.controller.ResourceNotFoundException;
import uk.org.rbc1b.roms.controller.common.DataConverterUtil;
import uk.org.rbc1b.roms.controller.common.model.PersonModelFactory;
import uk.org.rbc1b.roms.db.Congregation;
import uk.org.rbc1b.roms.db.CongregationContact;
import uk.org.rbc1b.roms.db.CongregationDao;
import uk.org.rbc1b.roms.db.Person;
import uk.org.rbc1b.roms.db.PersonDao;
import uk.org.rbc1b.roms.db.application.User;
import uk.org.rbc1b.roms.db.application.UserDao;
import uk.org.rbc1b.roms.db.email.Email;
import uk.org.rbc1b.roms.db.email.EmailDao;
import uk.org.rbc1b.roms.db.kingdomhall.KingdomHall;
import uk.org.rbc1b.roms.db.kingdomhall.KingdomHallDao;
import uk.org.rbc1b.roms.db.reference.ReferenceDao;
import uk.org.rbc1b.roms.db.volunteer.Volunteer;
import uk.org.rbc1b.roms.db.volunteer.VolunteerDao;
import uk.org.rbc1b.roms.db.volunteer.VolunteerSearchCriteria;
import uk.org.rbc1b.roms.db.volunteer.interview.InterviewSession;
import uk.org.rbc1b.roms.db.volunteer.interview.InterviewSessionDao;
import uk.org.rbc1b.roms.db.volunteer.interview.VolunteerInterviewSession;
import freemarker.template.Configuration;
import freemarker.template.TemplateException;

/**
 * Handler the volunteer interview session and invitations.
 */
@Controller
@RequestMapping(value = "/interview-sessions")
public class InterviewSessionsController {

    private static final Logger LOGGER = LoggerFactory.getLogger(InterviewSessionsController.class);
    private static final String INVITATION_EMAIL_TEMPLATE = "volunteer-interview-session-invitation.ftl";
    private static final String INVITATION_EMAIL_SUBJECT = "RBC induction interview";
    private static final Logger LOG = LoggerFactory.getLogger(InterviewSessionsController.class);
    @Autowired
    private InterviewSessionDao interviewSessionDao;
    @Autowired
    private InterviewSessionModelFactory interviewSessionModelFactory;
    @Autowired
    private VolunteerDao volunteerDao;
    @Autowired
    private CongregationDao congregationDao;
    @Autowired
    private PersonModelFactory personModelFactory;
    @Autowired
    private ReferenceDao referenceDao;
    @Autowired
    private KingdomHallDao kingdomHallDao;
    @Autowired
    private FreeMarkerConfigurer emailFreemarkerConfigurer;
    @Autowired
    private EmailDao emailDao;
    @Autowired
    private PersonDao personDao;
    @Autowired
    private UserDao userDao;

    /**
     * Display a list of volunteer interview sessions.
     *
     * @param model mvc model
     * @return view
     */
    @RequestMapping(method = RequestMethod.GET)
    @PreAuthorize("hasPermission('VOLUNTEER', 'READ')")
    public String showInterviewSessionList(ModelMap model) {

        List<InterviewSession> sessions = interviewSessionDao.findInterviewSessions();
        Map<Integer, Map<String, Integer>> sessionVolunteerCounts = interviewSessionDao
                .findInterviewSessionVolunteerCounts();

        List<InterviewSessionModel> modelList = new ArrayList<InterviewSessionModel>(sessions.size());
        for (InterviewSession session : sessions) {
            modelList.add(interviewSessionModelFactory.generateInterviewSessionModel(session,
                    sessionVolunteerCounts.get(session.getInterviewSessionId())));
        }

        model.addAttribute("interviewSessions", modelList);
        model.addAttribute("newUri", InterviewSessionModelFactory.generateUri(null) + "new");
        return "volunteers/interview-sessions/list";
    }

    /**
     * Show an individual interview session details.
     *
     * @param interviewSessionId id
     * @param model model
     * @return view name
     * interview session
     */
    @RequestMapping(value = "{interviewSessionId}", method = RequestMethod.GET)
    @PreAuthorize("hasPermission('VOLUNTEER', 'READ')")
    public String showInterviewSession(@PathVariable Integer interviewSessionId, ModelMap model) {
        InterviewSession session = interviewSessionDao.findInterviewSession(interviewSessionId);
        if (session == null) {
            throw new ResourceNotFoundException("No session with id [" + interviewSessionId + "]");
        }

        Map<String, Integer> sessionVolunteerCounts = interviewSessionDao
                .findInterviewSessionVolunteerCounts(interviewSessionId);

        InterviewSessionModel sessionModel = interviewSessionModelFactory.generateInterviewSessionModel(session,
                sessionVolunteerCounts);

        model.addAttribute("interviewSession", sessionModel);
        model.addAttribute("volunteers", generateVolunterList(interviewSessionId));
        model.addAttribute("interviewStatusValues", referenceDao.findVolunteerInterviewStatusValues());
        model.addAttribute("listUri", InterviewSessionModelFactory.generateUri(null));
        return "volunteers/interview-sessions/show";
    }

    private List<VolunteerInterviewSessionModel> generateVolunterList(Integer interviewSessionId) {

        List<VolunteerInterviewSession> volunteerInterviewSessions = interviewSessionDao
                .findVolunteerInterviewSessions(interviewSessionId);
        if (volunteerInterviewSessions.isEmpty()) {
            return Collections.emptyList();
        }

        VolunteerSearchCriteria volunteerSearchCriteria = new VolunteerSearchCriteria();
        volunteerSearchCriteria.setInterviewSessionId(interviewSessionId);
        volunteerSearchCriteria.setMaxResults(null);
        List<Volunteer> volunteers = volunteerDao.findVolunteers(volunteerSearchCriteria);

        Map<Integer, Volunteer> volunteerMap = new HashMap<Integer, Volunteer>();
        for (Volunteer volunteer : volunteers) {
            volunteerMap.put(volunteer.getPersonId(), volunteer);
        }

        Map<String, String> interviewStatusValues = referenceDao.findVolunteerInterviewStatusValues();
        Map<Integer, String> rbcSubRegionValues = referenceDao.findRbcSubRegionValues();

        List<VolunteerInterviewSessionModel> modelList = new ArrayList<VolunteerInterviewSessionModel>();
        for (VolunteerInterviewSession volunteerInterviewSession : volunteerInterviewSessions) {
            Volunteer volunteer = volunteerMap.get(volunteerInterviewSession.getVolunteer().getPersonId());
            if (volunteer == null) {
                LOG.error("Failed to look up Volunteer #{}, linked to InterviewSession #{}",
                        volunteerInterviewSession.getVolunteer().getPersonId(), interviewSessionId);
                continue;
            }

            modelList.add(interviewSessionModelFactory.generateVolunteerInterviewSessionModel(volunteer,
                    volunteerInterviewSession, interviewStatusValues, rbcSubRegionValues));
        }
        return modelList;
    }

    /**
     * Show the list of those who may be invited to the interview session.
     *
     * @param interviewSessionId session id
     * @param model model
     * @return view name
     */
    @RequestMapping(value = "{interviewSessionId}/invitations", method = RequestMethod.GET)
    @PreAuthorize("hasPermission('VOLUNTEER', 'READ')")
    public String showInvitationList(@PathVariable Integer interviewSessionId, ModelMap model) {

        InterviewSession session = interviewSessionDao.findInterviewSession(interviewSessionId);
        if (session == null) {
            throw new ResourceNotFoundException("No session with id [" + interviewSessionId + "]");
        }

        // we can't invite more people if the session has already happened
        if (session.isInPast()) {
            return "redirect:" + InterviewSessionModelFactory.generateUri(interviewSessionId);
        }

        Map<String, Integer> sessionVolunteerCounts = interviewSessionDao
                .findInterviewSessionVolunteerCounts(interviewSessionId);

        InterviewSessionModel sessionModel = interviewSessionModelFactory.generateInterviewSessionModel(session,
                sessionVolunteerCounts);

        List<Volunteer> volunteers = interviewSessionDao.findInterviewSessionEligibleVolunteers();
        Map<String, String> interviewStatusValues = referenceDao.findVolunteerInterviewStatusValues();
        Map<Integer, String> rbcSubRegionValues = referenceDao.findRbcSubRegionValues();

        List<VolunteerInterviewSessionModel> volunteerModeList = new ArrayList<VolunteerInterviewSessionModel>();
        for (Volunteer volunteer : volunteers) {
            volunteerModeList.add(interviewSessionModelFactory.generateVolunteerInterviewSessionModel(volunteer,
                    null, interviewStatusValues, rbcSubRegionValues));
        }

        model.addAttribute("interviewSession", sessionModel);
        model.addAttribute("volunteers", volunteerModeList);
        model.addAttribute("listUri", InterviewSessionModelFactory.generateUri(null));
        model.addAttribute("viewUri", InterviewSessionModelFactory.generateUri(interviewSessionId));
        return "volunteers/interview-sessions/invitations";
    }

    /**
     * Submit a list of volunteers to be invited to the session.
     *
     * @param interviewSessionId session id
     * @param volunteerIdsParam volunteer ids to be invited
     * @return redirect
     * session
     */
    @RequestMapping(value = "{interviewSessionId}/invitations", method = RequestMethod.POST)
    @PreAuthorize("hasPermission('VOLUNTEER', 'READ')")
    public String submitInvitationList(@PathVariable Integer interviewSessionId,
            @RequestParam(value = "volunteerIds") String volunteerIdsParam) {

        Set<Integer> volunteerIds = new HashSet<Integer>();
        for (String volunteerId : volunteerIdsParam.split(",")) {
            volunteerIds.add(DataConverterUtil.toInteger(volunteerId));
        }

        InterviewSession session = interviewSessionDao.findInterviewSession(interviewSessionId);
        if (session == null) {
            throw new ResourceNotFoundException("No session with id [" + interviewSessionId + "]");
        }

        // we can't invite more people if the session has already happened
        if (session.isInPast()) {
            throw new IllegalStateException("Interview session #" + interviewSessionId + " is in the past.");
        }

        if (session.getKingdomHall() == null || session.getKingdomHall().getKingdomHallId() == null) {
            throw new IllegalStateException(
                    "Interview session #" + interviewSessionId + " does not have a kingdom hall defined.");
        }

        List<VolunteerInterviewSession> existingInterviewSessions = interviewSessionDao
                .findVolunteerInterviewSessions(interviewSessionId);

        Set<Integer> existingVolunteerIds = new HashSet<Integer>();
        for (VolunteerInterviewSession existingInterviewSession : existingInterviewSessions) {
            existingVolunteerIds.add(existingInterviewSession.getVolunteer().getPersonId());
        }

        volunteerIds.removeAll(existingVolunteerIds);

        interviewSessionDao.addVolunteerInterviewSessions(volunteerIds, interviewSessionId);

        KingdomHall kingdomHall = kingdomHallDao.findKingdomHall(session.getKingdomHall().getKingdomHallId());

        for (Integer volunteerId : volunteerIds) {
            scheduleInterviewInvitationEmail(session, kingdomHall, volunteerId);
        }

        return "redirect:" + InterviewSessionModelFactory.generateUri(interviewSessionId);

    }

    private void scheduleInterviewInvitationEmail(InterviewSession session, KingdomHall kingdomHall,
            Integer volunteerId) {

        Volunteer volunteer = volunteerDao.findVolunteer(volunteerId, null);
        if (volunteer.getPerson().getEmail() == null) {
            LOGGER.error("Volunteer #{} does not have an email address defined", volunteer.getPersonId());
            return;
        }

        Person me = getMyDetails();

        Configuration conf = emailFreemarkerConfigurer.getConfiguration();

        Map<String, Object> model = new HashMap<String, Object>();

        model.put("sessionDate", session.getDate());
        model.put("sessionTime", InterviewSessionModelFactory.formatDisplayTime(session.getTime()));
        model.put("kingdomHallName", kingdomHall.getName());
        model.put("kingdomHallAddress", kingdomHall.getAddress());
        model.put("volunteer", volunteer);
        model.put("person", me);

        Congregation congregation = null;
        if (volunteer.getPerson().getCongregation() != null
                && volunteer.getPerson().getCongregation().getCongregationId() != null) {
            congregation = congregationDao
                    .findCongregation(volunteer.getPerson().getCongregation().getCongregationId());
        }

        Person coordinator = null;
        if (congregation != null) {
            model.put("volunteerCongregationName", congregation.getName());

            CongregationContact coordinatorContact = congregation.findContact(CongregationContact.COORDINATOR_ROLE);
            if (coordinatorContact != null) {
                coordinator = personDao.findPerson(coordinatorContact.getPerson().getPersonId());
            }
        }

        try {
            String text = FreeMarkerTemplateUtils
                    .processTemplateIntoString(conf.getTemplate(INVITATION_EMAIL_TEMPLATE), model);
            // send one email to the volunteer
            Email email = new Email();
            email.setRecipient(volunteer.getPerson().getEmail());

            if (coordinator != null && coordinator.getEmail() != null) {
                email.setCc(coordinator.getEmail());
            }
            email.setReplyTo(me.getEmail());
            email.setSubject(INVITATION_EMAIL_SUBJECT);
            email.setText(text);
            emailDao.save(email);
        } catch (IOException e) {
            LOGGER.error("Failed to volunteer interview invitation email", e);
        } catch (TemplateException e) {
            LOGGER.error("Failed to volunteer interview invitation email", e);
        }

    }

    /**
     * Update information about an individual volunteer invitation.
     *
     * @param interviewSessionId session id
     * @param volunteerInterviewSessionId volunteer invitation id
     * @param interviewStatusCode updated status code
     * @param comments comments
     * session or invitation
     */
    @RequestMapping(value = "{interviewSessionId}/invitations/{volunteerInterviewSessionId}", method = RequestMethod.PUT)
    @PreAuthorize("hasPermission('VOLUNTEER', 'EDIT')")
    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    public void updateVolunteerInvitation(@PathVariable Integer interviewSessionId,
            @PathVariable Integer volunteerInterviewSessionId, @RequestParam String interviewStatusCode,
            @RequestParam String comments) {

        InterviewSession session = interviewSessionDao.findInterviewSession(interviewSessionId);
        if (session == null) {
            throw new ResourceNotFoundException("No session with id [" + interviewSessionId + "]");
        }

        VolunteerInterviewSession volunteerInterviewSession = interviewSessionDao
                .findVolunteerInterviewSession(volunteerInterviewSessionId);
        if (volunteerInterviewSession == null) {
            throw new ResourceNotFoundException(
                    "No volunteer interview session with id [" + volunteerInterviewSessionId + "]");
        }

        if (!volunteerInterviewSession.getInterviewSession().getInterviewSessionId().equals(interviewSessionId)) {
            throw new ResourceNotFoundException("Volunteer interview session #" + volunteerInterviewSessionId
                    + " is not linked ot interview session #" + interviewSessionId);
        }

        volunteerInterviewSession.setComments(comments);
        volunteerInterviewSession.setVolunteerInterviewStatusCode(interviewStatusCode);

        interviewSessionDao.updateVolunteerInterviewSession(volunteerInterviewSession);
    }

    /**
     * Show form to create a new interview session.
     *
     * @param model model
     * @return view
     */
    @RequestMapping(value = "new", method = RequestMethod.GET)
    @PreAuthorize("hasPermission('VOLUNTEER', 'EDIT')")
    public String showEditInterviewSessionForm(ModelMap model) {

        InterviewSessionForm form = new InterviewSessionForm();

        model.addAttribute("interviewSessionForm", form);
        model.addAttribute("listUri", InterviewSessionModelFactory.generateUri(null));
        model.addAttribute("submitUri", InterviewSessionModelFactory.generateUri(null));
        model.addAttribute("submitMethod", "POST");
        return "volunteers/interview-sessions/edit";

    }

    /**
     * Create a new session.
     *
     * @param interviewSessionForm updated session data
     * @return redirect
     */
    @RequestMapping(method = RequestMethod.POST)
    @PreAuthorize("hasPermission('VOLUNTEER', 'EDIT')")
    public String createInterviewSession(@Valid InterviewSessionForm interviewSessionForm) {
        InterviewSession session = new InterviewSession();

        session.setComments(interviewSessionForm.getComments());
        session.setDate(DataConverterUtil.toSqlDate(interviewSessionForm.getDate()));
        session.setKingdomHall(kingdomHallDao.findKingdomHall(interviewSessionForm.getKingdomHallId()));
        session.setTime(InterviewSessionModelFactory.parseDisplayTime(interviewSessionForm.getTime()));

        interviewSessionDao.createInterviewSession(session);

        return "redirect:" + InterviewSessionModelFactory.generateUri(session.getInterviewSessionId());

    }

    /**
     * @param interviewSessionId primary key
     * @param model model
     * @return view
     * session
     */
    @RequestMapping(value = "{interviewSessionId}/edit", method = RequestMethod.GET)
    @PreAuthorize("hasPermission('VOLUNTEER', 'EDIT')")
    public String showEditInterviewSessionForm(@PathVariable Integer interviewSessionId, ModelMap model) {
        InterviewSession session = interviewSessionDao.findInterviewSession(interviewSessionId);
        if (session == null) {
            throw new ResourceNotFoundException("No session with id [" + interviewSessionId + "]");
        }

        InterviewSessionForm form = new InterviewSessionForm();
        form.setComments(session.getComments());
        form.setDate(DataConverterUtil.toDateTime(session.getDate()));
        form.setTime(InterviewSessionModelFactory.formatDisplayTime(session.getTime()));

        if (session.getKingdomHall() != null && session.getKingdomHall().getKingdomHallId() != null) {
            KingdomHall kingdomHall = kingdomHallDao.findKingdomHall(session.getKingdomHall().getKingdomHallId());
            form.setKingdomHallId(kingdomHall.getKingdomHallId());
            form.setKingdomHallName(kingdomHall.getName());
        }

        model.addAttribute("interviewSessionForm", form);
        model.addAttribute("listUri", InterviewSessionModelFactory.generateUri(null));
        model.addAttribute("submitUri", InterviewSessionModelFactory.generateUri(interviewSessionId));
        model.addAttribute("submitMethod", "PUT");
        return "volunteers/interview-sessions/edit";

    }

    /**
     * Update an existing session.
     *
     * @param interviewSessionId session id
     * @param interviewSessionForm updated session data
     * @return redirect
     * session
     */
    @RequestMapping(value = "{interviewSessionId}", method = RequestMethod.PUT)
    @PreAuthorize("hasPermission('VOLUNTEER', 'EDIT')")
    public String updateInterviewSession(@PathVariable Integer interviewSessionId,
            @Valid InterviewSessionForm interviewSessionForm) {
        InterviewSession session = interviewSessionDao.findInterviewSession(interviewSessionId);
        if (session == null) {
            throw new ResourceNotFoundException("No session with id [" + interviewSessionId + "]");
        }

        session.setComments(interviewSessionForm.getComments());
        session.setDate(DataConverterUtil.toSqlDate(interviewSessionForm.getDate()));
        session.setKingdomHall(kingdomHallDao.findKingdomHall(interviewSessionForm.getKingdomHallId()));
        session.setTime(InterviewSessionModelFactory.parseDisplayTime(interviewSessionForm.getTime()));

        interviewSessionDao.updateInterviewSession(session);

        return "redirect:" + InterviewSessionModelFactory.generateUri(interviewSessionId);

    }

    /**
     * Gets the current user's logged in person object.
     *
     * @return person the user's person object
     */
    private Person getMyDetails() {
        UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication()
                .getPrincipal();
        String myUserName = userDetails.getUsername();
        User me = userDao.findUser(myUserName);
        Person myDetails = personDao.findPerson(me.getPersonId());
        return myDetails;
    }
}