/** * 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.spring.controller.teacher; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.Stream.Builder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.ws.rs.core.UriBuilder; import org.fenixedu.academic.domain.Attends; import org.fenixedu.academic.domain.Attends.StudentAttendsStateType; import org.fenixedu.academic.domain.Mark; import org.fenixedu.academic.domain.Professorship; import org.fenixedu.academic.domain.Shift; import org.fenixedu.academic.domain.StudentGroup; import org.fenixedu.academic.domain.student.registrationStates.RegistrationState; import org.fenixedu.academic.domain.util.email.ExecutionCourseSender; import org.fenixedu.academic.domain.util.email.Recipient; import org.fenixedu.academic.dto.student.StudentStatuteBean; import org.fenixedu.academic.ui.struts.action.teacher.ManageExecutionCourseDA; import org.fenixedu.academic.util.Bundle; import org.fenixedu.bennu.core.domain.User; import org.fenixedu.bennu.core.groups.Group; import org.fenixedu.bennu.core.i18n.BundleUtil; import org.fenixedu.bennu.spring.security.CSRFTokenBean; import org.fenixedu.commons.spreadsheet.SheetData; import org.fenixedu.commons.spreadsheet.SpreadsheetBuilder; import org.fenixedu.commons.spreadsheet.WorkbookExportFormat; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; 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.ResponseBody; import org.springframework.web.servlet.view.RedirectView; import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import pt.ist.fenixWebFramework.servlets.filters.contentRewrite.GenericChecksumRewriter; import pt.ist.fenixframework.FenixFramework; @Controller @RequestMapping("/teacher/{executionCourse}/attends/") public class AttendsSearchController extends ExecutionCourseController { // hack @Autowired CSRFTokenBean csrfTokenBean; @ModelAttribute("csrf") public CSRFTokenBean getCSRF(){ return csrfTokenBean; } @Autowired StudentGroupService studentGroupService; @Override protected Class<?> getFunctionalityType() { return ManageExecutionCourseDA.class; } @Override Boolean getPermission(Professorship prof) { return prof.getPermissions().getStudents(); } @RequestMapping(value = "/show", method = RequestMethod.GET) public TeacherView searchAttends(Model model) { JsonArray studentAttendsStateTypes = new JsonArray(); for (StudentAttendsStateType type : StudentAttendsStateType.values()) { JsonObject typeJson = new JsonObject(); typeJson.addProperty("type", BundleUtil.getString(Bundle.ENUMERATION, type.getQualifiedName())); studentAttendsStateTypes.add(typeJson); } model.addAttribute("attendsStates", studentAttendsStateTypes); model.addAttribute("groupings", view(executionCourse.getGroupings())); model.addAttribute("curricularPlans", view(executionCourse.getAttendsDegreeCurricularPlans())); model.addAttribute("shifts", view(executionCourse.getShiftsOrderedByLessons())); model.addAttribute("shiftTypes", view(executionCourse.getShiftTypes())); return new TeacherView("executionCourse/attendsSearch/viewStudentList"); } @RequestMapping(value = "/list", method = RequestMethod.GET) public @ResponseBody ResponseEntity<String> listAttends() { return new ResponseEntity<>(view(executionCourse.getAttendsSet().stream() .filter(attendee -> attendee.getRegistration() != null)).toString(), HttpStatus.OK); } @RequestMapping(value = "/studentSpreadsheet", method = RequestMethod.POST) public void generateSpreadsheet(@RequestParam String filteredAttendsJson, HttpServletResponse response) throws IOException { Set<Attends> attends = new TreeSet<Attends>(Attends.COMPARATOR_BY_STUDENT_NUMBER); for (JsonElement elem : new JsonParser().parse(filteredAttendsJson).getAsJsonArray()) { JsonObject object = elem.getAsJsonObject(); attends.add((Attends) FenixFramework.getDomainObject(object.get("id").getAsString())); } final SpreadsheetBuilder builder = new SpreadsheetBuilder(); builder.addSheet(executionCourse.getPrettyAcronym().concat(BundleUtil.getString(Bundle.APPLICATION, "label.students")), new SheetData<Attends>(attends) { protected String getLabel(final String key) { return BundleUtil.getString(Bundle.APPLICATION, key); } @Override protected void makeLine(final Attends attends) { addCell(getLabel("label.username"), attends.getRegistration().getPerson().getUsername()); addCell(getLabel("label.number"), attends.getRegistration().getNumber()); addCell(getLabel("label.name"), attends.getRegistration().getPerson().getName()); addCell(getLabel("label.email"), attends.getRegistration().getPerson().getDefaultEmailAddressValue()); executionCourse.getGroupings().forEach( gr -> addCell(getLabel("label.projectGroup") + " " + gr.getName(), attends.getStudentGroupsSet() .stream().filter(sg -> sg.getGrouping().equals(gr)).map(StudentGroup::getGroupNumber) .map(gn -> gn.toString()).findAny().orElse(""))); executionCourse.getShiftTypes().forEach( shiftType -> addCell( getLabel("label.shift") + " " + shiftType.getFullNameTipoAula(), Optional.ofNullable( attends.getRegistration().getShiftFor(attends.getExecutionCourse(), shiftType)) .map(Shift::getNome).orElse(""))); if (attends.getEnrolment() != null) { addCell(getLabel("label.numberOfEnrollments"), attends.getEnrolment() .getNumberOfTotalEnrolmentsInThisCourse(attends.getEnrolment().getExecutionPeriod())); } else { addCell(getLabel("label.numberOfEnrollments"), "--"); } addCell(getLabel("label.attends.enrollmentState"), BundleUtil.getString(Bundle.ENUMERATION, attends.getAttendsStateType().getQualifiedName())); RegistrationState registrationState = attends.getRegistration().getLastRegistrationState(attends.getExecutionYear()); addCell(getLabel("label.registration.state"), registrationState == null ? "" : registrationState .getStateType().getDescription()); addCell(getLabel("label.Degree"), attends.getStudentCurricularPlanFromAttends().getDegreeCurricularPlan() .getPresentationName()); Collection<StudentStatuteBean> studentStatutes = attends.getRegistration().getStudent().getStatutes(executionCourse.getExecutionPeriod()); if (studentStatutes.size() > 0) { addCell(getLabel("label.studentStatutes"), studentStatutes.stream() .map(st -> st.getStatuteType().getName().getContent() + (Strings.isNullOrEmpty(st.getStudentStatute().getComment()) ? "" : " (" + st.getStudentStatute().getComment() + ")")) .collect(Collectors.joining(" | "))); } } }); response.setContentType("application/vnd.ms-excel"); response.setHeader( "Content-disposition", String.format( "attachment; filename=%s.xls", Joiner.on(" - ") .join(executionCourse.getSigla(), BundleUtil.getString("resources.ApplicationResources", "label.students")) .replace(" ", "_"))); try (OutputStream outputStream = response.getOutputStream()) { builder.build(WorkbookExportFormat.EXCEL, response.getOutputStream()); } } @RequestMapping(value = "/studentEvaluationsSpreadsheet", method = RequestMethod.POST) public void generateSpreadsheet(HttpServletResponse response) throws IOException { Set<Attends> attends = executionCourse.getAttendsSet(); final SpreadsheetBuilder builder = new SpreadsheetBuilder(); builder.addSheet(executionCourse.getPrettyAcronym().concat(BundleUtil.getString(Bundle.APPLICATION, "label.grades")), new SheetData<Attends>(attends) { protected String getLabel(final String key) { return BundleUtil.getString(Bundle.APPLICATION, key); } @Override protected void makeLine(final Attends attends) { addCell(getLabel("label.username"), attends.getRegistration().getPerson().getUsername()); addCell(getLabel("label.number"), attends.getRegistration().getNumber()); addCell(getLabel("label.name"), attends.getRegistration().getPerson().getPresentationName()); addCell(getLabel("label.Degree"), attends.getStudentCurricularPlanFromAttends().getDegreeCurricularPlan() .getPresentationName()); addCell(getLabel("label.attends.enrollmentState"), BundleUtil.getString(Bundle.ENUMERATION, attends.getAttendsStateType().getQualifiedName())); executionCourse.getAssociatedEvaluationsSet().forEach( ev -> addCell( ev.getPresentationName(), attends.getAssociatedMarksSet().stream().filter(mark -> mark.getEvaluation() == ev) .map(Mark::getMark).findAny().orElse(""))); } }); response.setContentType("application/vnd.ms-excel"); response.setHeader("Content-disposition", String.format( "attachment; filename=%s.xls", Joiner.on(" - ") .join(executionCourse.getSigla(), BundleUtil.getString("resources.ApplicationResources", "label.grades")) .replace(" ", "_"))); try (OutputStream outputStream = response.getOutputStream()) { builder.build(WorkbookExportFormat.EXCEL, response.getOutputStream()); } } @RequestMapping(value = "/sendEmail", method = RequestMethod.POST) public RedirectView sendEmail(Model model, HttpServletRequest request, HttpSession session, @RequestParam("filteredAttendsJson") String filteredAttendsJson, @RequestParam("filtersJson") String filtersJson) { String attendTypeValues = "", degreeNameValues = "", shiftsValues = "", studentStatuteTypesValues = ""; JsonObject filters = new JsonParser().parse(filtersJson).getAsJsonObject(); for (JsonElement elem : filters.get("attendsStates").getAsJsonArray()) { JsonObject object = elem.getAsJsonObject(); if (object.get("value").getAsBoolean()) { if (!attendTypeValues.isEmpty()) { attendTypeValues += ", "; } attendTypeValues += object.get("type"); } } for (JsonElement elem : filters.get("curricularPlans").getAsJsonArray()) { JsonObject object = elem.getAsJsonObject(); if (object.get("value").getAsBoolean()) { if (!degreeNameValues.isEmpty()) { degreeNameValues += ", "; } degreeNameValues += object.get("name"); } } for (JsonElement elem : filters.get("shifts").getAsJsonArray()) { JsonObject object = elem.getAsJsonObject(); if (object.get("value").getAsBoolean()) { if (!shiftsValues.isEmpty()) { shiftsValues += ", "; } shiftsValues += object.get("name"); } } JsonObject noStatuteObject = filters.get("noStudentStatuteTypes").getAsJsonObject(); if (noStatuteObject.get("value").getAsBoolean()) { studentStatuteTypesValues += noStatuteObject.get("shortName"); } for (JsonElement elem : filters.get("studentStatuteTypes").getAsJsonArray()) { JsonObject object = elem.getAsJsonObject(); if (object.get("value").getAsBoolean()) { if (!studentStatuteTypesValues.isEmpty()) { studentStatuteTypesValues += ", "; } studentStatuteTypesValues += object.get("name"); } } String label = String.format("%s : %s \n%s : %s \n%s : %s \n%s : %s", BundleUtil.getString(Bundle.APPLICATION, "label.selectStudents"), attendTypeValues, BundleUtil.getString(Bundle.APPLICATION, "label.attends.courses"), degreeNameValues, BundleUtil.getString(Bundle.APPLICATION, "label.selectShift"), shiftsValues, BundleUtil.getString(Bundle.APPLICATION, "label.studentStatutes"), studentStatuteTypesValues); Builder<Attends> builder = Stream.builder(); for (JsonElement elem : new JsonParser().parse(filteredAttendsJson).getAsJsonArray()) { JsonObject object = elem.getAsJsonObject(); builder.accept(FenixFramework.getDomainObject(object.get("id").getAsString())); } Group users = Group.users(builder.build().map(a -> a.getRegistration().getPerson().getUser()).filter(Objects::nonNull) .sorted(User.COMPARATOR_BY_NAME)); ArrayList<Recipient> recipients = new ArrayList<Recipient>(); recipients.add(Recipient.newInstance(label, users)); String sendEmailUrl = UriBuilder .fromUri("/messaging/emails.do") .queryParam("method", "newEmail") .queryParam("sender", ExecutionCourseSender.newInstance(executionCourse).getExternalId()) .queryParam("recipient", recipients.stream().filter(r -> r != null).map(r -> r.getExternalId()).toArray()) .build().toString(); String sendEmailWithChecksumUrl = GenericChecksumRewriter.injectChecksumInUrl(request.getContextPath(), sendEmailUrl, session); return new RedirectView(sendEmailWithChecksumUrl, true); } }