/**
* Copyright © 2002 Instituto Superior Técnico
*
* This file is part of FenixEdu Academic.
*
* FenixEdu Academic is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FenixEdu Academic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FenixEdu Academic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fenixedu.academic.ui.struts.action.administrativeOffice.student;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.comparators.ComparatorChain;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import org.apache.struts.util.LabelValueBean;
import org.fenixedu.academic.domain.DegreeCurricularPlan;
import org.fenixedu.academic.domain.ExecutionSemester;
import org.fenixedu.academic.domain.StudentCurricularPlan;
import org.fenixedu.academic.domain.student.Registration;
import org.fenixedu.academic.domain.student.Student;
import org.fenixedu.academic.dto.InfoStudentCurricularPlan;
import org.fenixedu.academic.dto.student.ExecutionPeriodStatisticsBean;
import org.fenixedu.academic.predicate.AcademicPredicates;
import org.fenixedu.academic.predicate.AccessControl;
import org.fenixedu.academic.service.services.commons.student.ReadStudentCurricularPlan;
import org.fenixedu.academic.service.services.commons.student.ReadStudentCurriculum;
import org.fenixedu.academic.service.services.exceptions.ExistingServiceException;
import org.fenixedu.academic.service.services.exceptions.FenixServiceException;
import org.fenixedu.academic.service.services.exceptions.NotAuthorizedException;
import org.fenixedu.academic.ui.renderers.student.curriculum.StudentCurricularPlanRenderer.EnrolmentStateFilterType;
import org.fenixedu.academic.ui.renderers.student.curriculum.StudentCurricularPlanRenderer.OrganizationType;
import org.fenixedu.academic.ui.renderers.student.curriculum.StudentCurricularPlanRenderer.ViewType;
import org.fenixedu.academic.ui.struts.action.base.FenixDispatchAction;
import org.fenixedu.academic.ui.struts.action.coordinator.DegreeCoordinatorIndex;
import org.fenixedu.academic.ui.struts.action.exceptions.ExistingActionException;
import org.fenixedu.academic.ui.struts.action.resourceAllocationManager.utils.PresentationConstants;
import org.fenixedu.academic.util.Bundle;
import org.fenixedu.academic.util.StudentCurricularPlanIDDomainType;
import org.fenixedu.bennu.core.i18n.BundleUtil;
import org.fenixedu.bennu.struts.annotations.Forward;
import org.fenixedu.bennu.struts.annotations.Forwards;
import org.fenixedu.bennu.struts.annotations.Mapping;
import org.fenixedu.bennu.struts.portal.EntryPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pt.ist.fenixWebFramework.renderers.utils.RenderUtils;
import pt.ist.fenixframework.FenixFramework;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
/**
* @author Nuno Nunes (nmsn@rnl.ist.utl.pt) Joana Mota (jccm@rnl.ist.utl.pt)
* @author David Santos
* @author André Fernandes / João Brito
*/
@Mapping(path = "/viewStudentCurriculum", module = "academicAdministration",
formBean = "studentCurricularPlanAndEnrollmentsSelectionForm", functionality = SearchForStudentsDA.class)
@Forwards({ @Forward(name = "ShowStudentCurriculum", path = "/student/curriculum/displayStudentCurriculum_bd.jsp"),
@Forward(name = "ShowStudentCurriculumForCoordinator", path = "/student/curriculum/displayStudentCurriculum_bd.jsp"),
@Forward(name = "NotAuthorized", path = "/student/notAuthorized_bd.jsp") })
public class CurriculumDispatchAction extends FenixDispatchAction {
private static final Logger logger = LoggerFactory.getLogger(CurriculumDispatchAction.class);
@Override
public ActionForward execute(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request,
HttpServletResponse response) throws Exception {
DegreeCoordinatorIndex.setCoordinatorContext(request);
return super.execute(mapping, actionForm, request, response);
}
@EntryPoint
public ActionForward prepare(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) {
RenderUtils.invalidateViewState();
Registration registration = null;
final String registrationOID = getRegistrationOID(request);
final Student loggedStudent = getUserView(request).getPerson().getStudent();
if (registrationOID != null) {
registration = FenixFramework.getDomainObject(registrationOID);
} else if (loggedStudent != null) {
/**
* We no longer want to filter students with 1 registration only.
* All taskflows are now forced to render "chooseRegistration.jsp"
* in order to make it possible to present the
* ExtraCurricularActivities information. This old block of code is
* kept commented only for legacy purpose.
*/
// if (loggedStudent.getRegistrations().size() == 1) {
// registration = loggedStudent.getRegistrations().iterator().next();
// } else {
request.setAttribute("student", loggedStudent);
List<Registration> validRegistrations = getValidRegistrations(loggedStudent);
request.setAttribute("validRegistrations", validRegistrations);
return mapping.findForward("chooseRegistration");
// }
}
if (registration == null) {
return mapping.findForward("NotAuthorized");
} else {
return getStudentCP(registration, mapping, (DynaActionForm) form, request);
}
}
private List<Registration> getValidRegistrations(Student loggedStudent) {
List<Registration> result = new ArrayList<Registration>();
for (Registration registration : loggedStudent.getRegistrationsSet()) {
if (!registration.isCanceled()) {
result.add(registration);
}
}
return result;
}
private String getRegistrationOID(HttpServletRequest request) {
String registrationOID = request.getParameter("registrationOID");
if (registrationOID == null) {
registrationOID = (String) request.getAttribute("registrationOID");
}
return (registrationOID == null || registrationOID.equals("")) ? null : registrationOID;
}
protected Registration getStudentRegistration(Student student, String degreeCurricularPlanId) {
DegreeCurricularPlan degreeCurricularPlan = FenixFramework.getDomainObject(degreeCurricularPlanId);
return student.readRegistrationByDegreeCurricularPlan(degreeCurricularPlan);
}
public ActionForward prepareReadByStudentNumber(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
RenderUtils.invalidateViewState();
DynaActionForm actionForm = (DynaActionForm) form;
Registration registration = null;
final String degreeCurricularPlanId = (String) actionForm.get("degreeCurricularPlanID");
Student student = getStudent(actionForm);
if (student != null) {
if (!StringUtils.isEmpty(degreeCurricularPlanId)) {
registration = getStudentRegistration(student, degreeCurricularPlanId);
} else {
final Collection<Registration> registrations = student.getRegistrationsSet();
if (!registrations.isEmpty()) {
registration = registrations.iterator().next();
}
}
}
if (registration == null) {
return mapping.findForward("NotAuthorized");
} else {
return getStudentCP(registration, mapping, actionForm, request);
}
}
private Student getStudent(DynaActionForm form) {
final Integer studentNumber = Integer.valueOf((String) form.get("studentNumber"));
Student student = Student.readStudentByNumber(studentNumber);
// if (student != null) {
// Teacher teacher = AccessControl.getPerson().getTeacher();
// for (Tutorship tutorship : student.getTutorships()) {
// if (tutorship.getTeacher().equals(teacher))
// return student;
// }
// for (Coordinator coordinator :
// AccessControl.getPerson().getCoordinators()) {
// DegreeCurricularPlan dcp =
// coordinator.getExecutionDegree().getDegreeCurricularPlan();
// for (Registration registration : student.getRegistrations()) {
// if (registration.getStudentCurricularPlan(dcp) != null)
// return student;
// }
// }
// }
// return null;
return student;
}
protected ActionForward getStudentCPForSupervisor(final Registration registration, final ActionMapping mapping,
DynaActionForm actionForm, final HttpServletRequest request) {
return getStudentCP(registration, mapping, actionForm, request);
}
private ActionForward getStudentCP(final Registration registration, final ActionMapping mapping, DynaActionForm actionForm,
final HttpServletRequest request) {
request.setAttribute("registration", registration);
String studentCPID = getStudentCPID(request, actionForm);
if (StringUtils.isEmpty(studentCPID)) {
studentCPID = getDefaultStudentCPID(registration).getId().toString();
actionForm.set("studentCPID", studentCPID);
}
request.setAttribute("selectedStudentCurricularPlans", getSelectedStudentCurricularPlans(registration, studentCPID));
request.setAttribute("scpsLabelValueBeanList", getSCPsLabelValueBeanList(registration.getStudentCurricularPlansSet()));
if (StringUtils.isEmpty(actionForm.getString("viewType"))) {
actionForm.set("viewType", ViewType.ALL.name());
}
if (StringUtils.isEmpty(actionForm.getString("select"))) {
actionForm
.set("select",
AcademicPredicates.VIEW_FULL_STUDENT_CURRICULUM.evaluate(AccessControl.getPerson()) ? EnrolmentStateFilterType.ALL
.name() : EnrolmentStateFilterType.APPROVED_OR_ENROLED.name());
}
if (StringUtils.isEmpty(actionForm.getString("organizedBy"))) {
String organizedBy =
registration.getDegreeType().isPreBolonhaMasterDegree() ? OrganizationType.EXECUTION_YEARS.name() : OrganizationType.GROUPS
.name();
actionForm.set("organizedBy", organizedBy);
}
computeCurricularInfo(request, registration);
if (StringUtils.isEmpty(request.getParameter("degreeCurricularPlanID"))) {
return mapping.findForward("ShowStudentCurriculum");
} else {
request.setAttribute("degreeCurricularPlanID", request.getParameter("degreeCurricularPlanID"));
return mapping.findForward("ShowStudentCurriculumForCoordinator");
}
}
private List<StudentCurricularPlan> getSelectedStudentCurricularPlans(final Registration registration,
final String studentCPID) {
final List<StudentCurricularPlan> result;
final StudentCurricularPlanIDDomainType scpIdType = new StudentCurricularPlanIDDomainType(studentCPID);
if (scpIdType.isNewest()) {
result = Collections.singletonList(registration.getLastStudentCurricularPlan());
} else if (scpIdType.isAll()) {
result = getSortedStudentCurricularPlans(registration);
} else {
result = Collections.singletonList(getStudentCurricularPlan(registration, studentCPID));
}
return result;
}
private StudentCurricularPlanIDDomainType getDefaultStudentCPID(final Registration registration) {
return registration.isBolonha() ? StudentCurricularPlanIDDomainType.NEWEST : StudentCurricularPlanIDDomainType.ALL;
}
private String getStudentCPID(HttpServletRequest request, DynaActionForm actionForm) {
String result = request.getParameter("studentCPID");
if (result == null) {
result = (String) request.getAttribute("studentCPID");
}
if (result == null) {
result = (String) actionForm.get("studentCPID");
}
return result;
}
private static List<StudentCurricularPlan> getSortedStudentCurricularPlans(final Registration registration) {
final List<StudentCurricularPlan> result = new ArrayList<StudentCurricularPlan>();
result.addAll(registration.getStudentCurricularPlansSet());
Collections.sort(result, new BeanComparator("startDateYearMonthDay"));
return result;
}
private StudentCurricularPlan getStudentCurricularPlan(final Registration registration, final String scpId) {
for (final StudentCurricularPlan studentCurricularPlan : registration.getStudentCurricularPlansSet()) {
if (studentCurricularPlan.getExternalId().equals(scpId)) {
return studentCurricularPlan;
}
}
return null;
}
private List<LabelValueBean> getSCPsLabelValueBeanList(Collection<StudentCurricularPlan> studentCurricularPlans) {
final List<LabelValueBean> result = new ArrayList<LabelValueBean>();
result.add(new LabelValueBean(StudentCurricularPlanIDDomainType.NEWEST_STRING, StudentCurricularPlanIDDomainType.NEWEST
.toString()));
result.add(new LabelValueBean(StudentCurricularPlanIDDomainType.ALL_STRING, StudentCurricularPlanIDDomainType.ALL
.toString()));
for (final StudentCurricularPlan studentCurricularPlan : studentCurricularPlans) {
final StringBuilder label = new StringBuilder();
label.append(studentCurricularPlan.getRegistration().getDegreeNameWithDescription());
label.append(", ").append(studentCurricularPlan.getDegreeCurricularPlan().getName());
if (studentCurricularPlan.getSpecialization() != null) {
label.append(" - ").append(
BundleUtil.getString(Bundle.ENUMERATION, studentCurricularPlan.getSpecialization().name()));
}
label.append(" - ").append(studentCurricularPlan.getStartDateYearMonthDay());
result.add(new LabelValueBean(label.toString(), String.valueOf(studentCurricularPlan.getExternalId())));
}
return result;
}
public ActionForward getCurriculumForCoordinator(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws ExistingActionException, FenixServiceException {
// get and set the degreeCurricularPlanID from the request and onto the
// request
String degreeCurricularPlanID = null;
if (request.getParameter("degreeCurricularPlanID") != null) {
degreeCurricularPlanID = request.getParameter("degreeCurricularPlanID");
request.setAttribute("degreeCurricularPlanID", degreeCurricularPlanID);
}
final String studentCurricularPlanID = getStudentCPID(request, (DynaActionForm) form);
String executionDegreeID = getExecutionDegree(request);
List result = null;
try {
// TODO check
result = ReadStudentCurriculum.runReadStudentCurriculum(executionDegreeID, studentCurricularPlanID);
} catch (NotAuthorizedException e) {
return mapping.findForward("NotAuthorized");
}
// TODO Remove this exception! It returns null and it is not supposed!
catch (Exception exp) {
logger.error(exp.getMessage(), exp);
return null;
}
BeanComparator courseName = new BeanComparator("infoCurricularCourse.name");
BeanComparator executionYear = new BeanComparator("infoExecutionPeriod.infoExecutionYear.year");
ComparatorChain chainComparator = new ComparatorChain();
chainComparator.addComparator(courseName);
chainComparator.addComparator(executionYear);
Collections.sort(result, chainComparator);
InfoStudentCurricularPlan infoStudentCurricularPlan = null;
try {
infoStudentCurricularPlan = ReadStudentCurricularPlan.run(studentCurricularPlanID);
} catch (ExistingServiceException e) {
throw new ExistingActionException(e);
}
request.setAttribute(PresentationConstants.CURRICULUM, result);
request.setAttribute(PresentationConstants.STUDENT_CURRICULAR_PLAN, infoStudentCurricularPlan);
return mapping.findForward("ShowStudentCurriculum");
}
private String getExecutionDegree(HttpServletRequest request) {
String executionDegreeIdString = request.getParameter("executionDegreeId");
if (executionDegreeIdString == null) {
executionDegreeIdString = (String) request.getAttribute("executionDegreeId");
}
request.setAttribute("executionDegreeId", executionDegreeIdString);
return executionDegreeIdString;
}
public static JsonObject computeCurricularInfo(HttpServletRequest request, Registration registration) {
/* Make a 'studentStatistics' Array of ExecutionPeriodStatisticsBean that has info on # enrolments, etc */
List<ExecutionPeriodStatisticsBean> studentStatistics = new ArrayList<ExecutionPeriodStatisticsBean>();
Map<ExecutionSemester, ExecutionPeriodStatisticsBean> enrolmentsByExecutionPeriod =
new HashMap<ExecutionSemester, ExecutionPeriodStatisticsBean>();
for (StudentCurricularPlan studentCurricularPlan : getSortedStudentCurricularPlans(registration)) {
for (ExecutionSemester executionSemester : studentCurricularPlan.getEnrolmentsExecutionPeriods()) {
if (enrolmentsByExecutionPeriod.containsKey(executionSemester)) {
ExecutionPeriodStatisticsBean executionPeriodStatisticsBean =
enrolmentsByExecutionPeriod.get(executionSemester);
executionPeriodStatisticsBean.addEnrolmentsWithinExecutionPeriod(studentCurricularPlan
.getEnrolmentsByExecutionPeriod(executionSemester));
enrolmentsByExecutionPeriod.put(executionSemester, executionPeriodStatisticsBean);
} else {
ExecutionPeriodStatisticsBean executionPeriodStatisticsBean =
new ExecutionPeriodStatisticsBean(executionSemester);
executionPeriodStatisticsBean.addEnrolmentsWithinExecutionPeriod(studentCurricularPlan
.getEnrolmentsByExecutionPeriod(executionSemester));
enrolmentsByExecutionPeriod.put(executionSemester, executionPeriodStatisticsBean);
}
}
}
studentStatistics.addAll(enrolmentsByExecutionPeriod.values());
Collections.sort(studentStatistics, new BeanComparator("executionPeriod"));
/* Put all the info in the required JSON format */
JsonObject curricularInfoJSONObject = new JsonObject();
JsonArray periodsJSONArray = new JsonArray();
for (ExecutionPeriodStatisticsBean executionPeriodStatisticsBean : studentStatistics) {
JsonArray jsonArray = new JsonArray();
jsonArray.add(new JsonPrimitive(executionPeriodStatisticsBean.getExecutionPeriod().getExecutionYear().getYear()
+ " - " + executionPeriodStatisticsBean.getExecutionPeriod().getSemester().toString() + "º sem"));
jsonArray.add(new JsonPrimitive(executionPeriodStatisticsBean.getTotalEnrolmentsNumber()));
jsonArray.add(new JsonPrimitive(executionPeriodStatisticsBean.getApprovedEnrolmentsNumber()));
periodsJSONArray.add(jsonArray);
}
curricularInfoJSONObject.add("periods", periodsJSONArray);
/* Serve the JSON object */
request.setAttribute("registrationApprovalRateJSON", curricularInfoJSONObject);
return curricularInfoJSONObject;
}
}