/** * Licensed to Apereo under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Apereo licenses this file to you 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 the following location: * * 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 org.jasig.portlet.courses.mvc.portlet; import com.fasterxml.jackson.databind.ObjectMapper; import org.jasig.portlet.courses.dao.ICoursesSectionDao; import org.jasig.portlet.courses.model.xml.*; import org.jasig.portlet.courses.model.xml.personal.Course; import org.jasig.portlet.courses.model.xml.personal.CoursesByTerm; import org.jasig.portlet.courses.mvc.wrapper.CourseSectionMeetingWrapper; import org.jasig.portlet.courses.mvc.wrapper.CourseSectionWrapper; import org.jasig.portlet.courses.service.IURLService; import org.jasig.portlet.utils.mvc.IViewSelector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.portlet.bind.annotation.ActionMapping; import org.springframework.web.portlet.bind.annotation.ResourceMapping; import javax.portlet.*; import java.io.IOException; import java.util.*; @Controller @RequestMapping("VIEW") public class UWCoursesPortletController{ public static final String DEFAULT_VIEW_PREFERENCE = "defaultView"; public static final String COURSE_LIST_VIEW = "courseList"; public static final String CLASS_SCHEDULE_VIEW = "classSchedule"; public static final String GRADES_LIST_VIEW = "grades"; public static final String TERMCODE = "termCode"; public static final String VIEW = "view"; public static final String PRINTVIEW = "printView"; public static final String COURSECODE = "courseCode"; public static final String CATALOGNBR = "catalogNbr"; public static final String SUBJECTCODE = "subjectCode"; public static final String CLASSNBR = "classNbr"; public static final String COURSEID = "courseId"; public static final String STANDALONE_SCHEDULE_PREFERENCE = "standaloneSchedule"; private static final String DISPLAY_COURSE_UPDATES_PREFERENCE = "displayCourseUpdates"; private static final String DISPLAY_COURSE_BOOKS_PREFERENCE = "displayCourseBooks"; public static final String FINALGRADESFNAME_PREF = "finalGradesFname"; public static final String FINALGRADESWINDOWSTATE_PREF = "finalGradesWindowState"; public static final String FINALGRADESFIXEDPARAM_PREF = "finalGradesWindowFixedParameterString"; private ICoursesSectionDao coursesSectionDao; protected final Logger logger = LoggerFactory.getLogger(getClass()); @Autowired @Qualifier("coursesSectionDao") public void setCoursesSectionDao(ICoursesSectionDao coursesSectionDao) { this.coursesSectionDao = coursesSectionDao; } /*@Autowired @Qualifier("finalGradesServiceDao") public void setCoursesDao(ICoursesDao coursesDao) { this.coursesDao = coursesDao; } */ private IURLService urlService; @Autowired public void setUrlService(IURLService urlService) { this.urlService = urlService; } private IViewSelector viewSelector; @Autowired public void setViewSelector(IViewSelector viewSelector) { this.viewSelector = viewSelector; } @RequestMapping public String defaultView(PortletRequest request, MimeResponse mimeResponse,ModelMap model) { final PortletPreferences preferences = request.getPreferences(); final String defaultView = preferences.getValue(DEFAULT_VIEW_PREFERENCE, COURSE_LIST_VIEW); logger.info("Calling defaultView....."); if (CLASS_SCHEDULE_VIEW.equals(defaultView)) { request.getPortletSession().setAttribute("helpDeskURL",preferences.getValue("helpDeskURL", "https://kb.wisc.edu/helpdesk/page.php?id=35501")); return viewClassSchedule(request, mimeResponse,model, null,"grid",false); } request.getPortletSession().setAttribute("helpDeskURL",preferences.getValue("helpDeskURL", "https://kb.wisc.edu/helpdesk/page.php?id=35501")); return viewCourseList(request, model, null); } @RequestMapping(params = "action=" + COURSE_LIST_VIEW) public String viewCourseList(PortletRequest request, ModelMap model, @RequestParam(value = TERMCODE, required = false) String termCode) { TermList termList = coursesSectionDao.getTermList(request); model.put("termList", termList); //Determine the current term code and term termCode = this.getSelectedTermCode(request, termCode); final Term selectedTerm = this.getSelectedTerm(termCode, termList); //Grab the coursesByTerm information if a selectedTerm is set if (selectedTerm != null) { final CoursesByTerm coursesByTerm = coursesSectionDao.getCoursesByTerm(request, selectedTerm.getCode(),termList); model.put("coursesByTerm", coursesByTerm); model.put("selectedTerm", selectedTerm); } final boolean isMobile = viewSelector.isMobile(request); model.put("isMobile", isMobile); final String viewName = isMobile ? "myuwcourses/courseList-jQM" : "myuwcourses/courseList"; return viewName; } @RequestMapping(params = "action=showCourse") public String viewCourse(PortletRequest request, ModelMap model, @RequestParam(TERMCODE) String termCode, @RequestParam(CATALOGNBR) String catalogNbr, @RequestParam(SUBJECTCODE) String subjectCode, @RequestParam(CLASSNBR) String classNbr, @RequestParam(COURSEID) String courseId) { final boolean isMobile = viewSelector.isMobile(request); PortletPreferences prefs = request.getPreferences(); TermList termList = coursesSectionDao.getTermList(request); final Term selectedTerm = this.getSelectedTerm(termCode, termList); model.put("selectedTerm", selectedTerm); CoursesByTerm summary = coursesSectionDao.getCoursesByTerm(request, termCode, termList); model.put("coursesByTerm", summary); logger.debug("selectedCourse code is ....."+catalogNbr+subjectCode); Course course= coursesSectionDao. getCoursesBySection(request,termCode, catalogNbr, subjectCode,courseId,classNbr,termList); Map<String, String> instructorUrls = new HashMap<String, String>(); for (final CourseSection courseSection: course.getCourseSections()) { //Instructors for (final Instructor instructor : courseSection.getInstructors()) { logger.debug("instructor.getIdentifier()........" + instructor.getIdentifier()); logger.debug("instructor.getFullName()......." + instructor.getFullName()); logger.debug("instructor.getAbbreviation()........." + instructor.getAbbreviation()); logger.debug("instructor.getInstructorAdditionalInfos()........." + instructor.getInstructorAdditionalInfos()); instructorUrls.put(instructor.getIdentifier(), urlService.getInstructorUrl(instructor, request)); if (logger.isDebugEnabled()) { logger.debug("instructorUrls......." + instructorUrls); } } } //Setting finalGrades URL Map<String,String> params=new HashMap<String,String>(); params.put("pP_termCode",termCode); String fgBaseUrl = urlService.getOtherPortletURL(prefs, FINALGRADESFNAME_PREF, FINALGRADESWINDOWSTATE_PREF, FINALGRADESFIXEDPARAM_PREF, params); model.put("finalGradeUrl", fgBaseUrl); model.put("instructorUrls", instructorUrls); model.put("courseSectionMeetingList",getCourseMeetingsWrapperList(course,prefs,isMobile,termCode)); model.put("course", course); final String viewName = isMobile ? "myuwcourses/courseDetail-jQM" : "myuwcourses/courseDetail"; return viewName; } @RequestMapping(params = "action=showExams") public String viewExam(PortletRequest request, MimeResponse response, ModelMap model, @RequestParam(TERMCODE) String termCode, @RequestParam(VIEW) String view, @RequestParam(value = PRINTVIEW, required = false, defaultValue = "false") Boolean printView) { final TermList termList = coursesSectionDao.getTermList(request); model.put("termList", termList); model.put(PRINTVIEW, printView); model.put("isStandaloneSchedule", Boolean.parseBoolean(request.getPreferences().getValue(STANDALONE_SCHEDULE_PREFERENCE, "false"))); //Determine the current term code and term termCode = this.getSelectedTermCode(request, termCode); final Term selectedTerm = this.getSelectedTerm(termCode, termList); //Grab the coursesByTerm information if a selectedTerm is set if (selectedTerm != null) { final CoursesByTerm coursesByTerm = coursesSectionDao.getCoursesByTerm(request, selectedTerm.getCode(),termList); model.put("coursesByTerm", coursesByTerm); model.put("selectedTerm", selectedTerm); } logger.debug("Calling getFinalExams....."+termCode); List<Course> courseList= coursesSectionDao.getFinalExams(request, termCode,termList); List<CourseSectionWrapper> finalExamsList=new ArrayList<CourseSectionWrapper>(); for (Course course : courseList) { for (CourseSection courseSection: course.getCourseSections()) { PortletURL url = createCourseDetailUrl(course, courseSection, response, termCode); for (CourseMeeting courseMeeting: courseSection.getCourseMeetings()) { CourseSectionWrapper finalExam = new CourseSectionWrapper( course, courseSection, courseMeeting, url.toString() ); finalExamsList.add(finalExam); } } } Collections.sort(finalExamsList, CourseSectionWrapper.FinalExamComparator); model.put("finalExamsList", finalExamsList); if( finalExamsList.isEmpty() ) { model.put("startDateSunday", false); } else { model.put("startMonthDescr", finalExamsList.get(0).getMonthDescrOfStart()); model.put("startDateSunday", finalExamsList.get(0).getExamStartSunday()); } final boolean isMobile = viewSelector.isMobile(request); String viewName=""; if (view.equals("list")) { viewName = isMobile ? "myuwcourses/examList-jQM" : "myuwcourses/examList"; } else { ObjectMapper mapper = new ObjectMapper(); try { model.put("finalExamsListJson", mapper.writeValueAsString((List<CourseSectionWrapper>)model.get("finalExamsList"))); } catch (IOException e) { String msg = "Failed to return jsonClassSchedule response"; logger.error(msg, e); throw new RuntimeException(msg); } viewName = isMobile ? "myuwcourses/examGrid-jQM" : "myuwcourses/examGrid"; } return viewName; } /** * Sets "otherCourses" and "classScheduleList" on the model * <p/> * Both are a List<{@link CourseSectionWrapper}>, defining the lists of classes which are to be displayed * * @param request The {@link PortletRequest} * @param response Required for generating {@link PortletURL}s for the front end * @param model The model * @param termCode Required for getting the list of courses and generating URLs */ private void getClassScheduleList(PortletRequest request, MimeResponse response, ModelMap model, String termCode) { final TermList termList = coursesSectionDao.getTermList(request); model.put("termList", termList); //Determine the current term code and term termCode = this.getSelectedTermCode(request, termCode); final Term selectedTerm = this.getSelectedTerm(termCode, termList); //Grab the coursesByTerm information if a selectedTerm is set if (selectedTerm == null) return; logger.info("FOUND SELECTED TERM !!!!"+selectedTerm.getCode()); final CoursesByTerm coursesByTerm = coursesSectionDao.getCoursesByTerm(request, selectedTerm.getCode(),termList); model.put("coursesByTerm", coursesByTerm); model.put("selectedTerm", selectedTerm); List<Course> courseList= coursesSectionDao.getClassSchedule(request, selectedTerm.getCode(), termList); List<CourseSectionWrapper> classScheduleList=new ArrayList<CourseSectionWrapper>(); List<CourseSectionWrapper> otherCourses=new ArrayList<CourseSectionWrapper>(); for (Course course : courseList) { for (CourseSection courseSection: course.getCourseSections()) { PortletURL url = createCourseDetailUrl(course, courseSection, response, selectedTerm.getCode()); if( courseSection.getCourseMeetings().size() > 0 && !courseSection.getCourseMeetings().get(0).getLocation().getDisplayName().equals("ONLINE")) { for (CourseMeeting courseMeeting: courseSection.getCourseMeetings()) { if (courseMeeting.getDayIds()!=null) { for (String day : courseMeeting.getDayIds()) { CourseSectionWrapper classSchedule = new CourseSectionWrapper(course, courseSection, courseMeeting, day, url.toString()); classScheduleList.add(classSchedule); } } } } else { CourseSectionWrapper classSchedule = new CourseSectionWrapper(course, courseSection, url.toString()); otherCourses.add(classSchedule); } } } Collections.sort(classScheduleList, CourseSectionWrapper.ClassScheduleComparator); Collections.sort(otherCourses,CourseSectionWrapper.OtherCourseComparator); model.put("otherCourses", otherCourses); model.put("classScheduleList", classScheduleList); } @ResourceMapping("jsonClassSchedule") public String jsonClassSchedule(PortletRequest request, MimeResponse response, ModelMap model, @RequestParam(TERMCODE) String termCode) { getClassScheduleList(request, response, model, termCode); return "json"; } @ResourceMapping("jsonCurrentClassSchedule") public String jsonCurrentClassSchedule(PortletRequest request, MimeResponse response, ModelMap model) { final TermList termList = coursesSectionDao.getTermList(request); if(termList != null) { model.put("termList", termList); if(termList.getCurrentTerm() != null) { final CoursesByTerm currentTermCourses = coursesSectionDao.getCoursesByTerm(request, termList.getCurrentTerm().getCode(), termList); model.put("currentTermCourses", currentTermCourses); } else { model.put("currentTermCourses", null); } } return "json"; } @RequestMapping(params = "action=showClassSchedule") public String viewClassSchedule(PortletRequest request, MimeResponse response, ModelMap model, @RequestParam(TERMCODE) String termCode, @RequestParam(VIEW) String view, @RequestParam(value = PRINTVIEW, required = false, defaultValue = "false") Boolean printView) { getClassScheduleList(request, response, model, termCode); final boolean isMobile = viewSelector.isMobile(request); String viewName=""; model.put(PRINTVIEW, printView); model.put("isStandaloneSchedule", Boolean.parseBoolean(request.getPreferences().getValue(STANDALONE_SCHEDULE_PREFERENCE, "false"))); if (view.equals("list")) { viewName = isMobile ? "myuwcourses/classScheduleList-jQM" : "myuwcourses/classScheduleList"; } else { ObjectMapper mapper = new ObjectMapper(); try { model.put("classScheduleListJson", mapper.writeValueAsString((List<CourseSectionWrapper>)model.get("classScheduleList"))); } catch (IOException e) { String msg = "Failed to return jsonClassSchedule response"; logger.error(msg, e); throw new RuntimeException(msg); } viewName = isMobile ? "myuwcourses/classScheduleGrid-jQM" : "myuwcourses/classScheduleGrid"; } return viewName; } /** * Action request handler that simply copies all parameters from action to render */ @ActionMapping public void copyActionParameters(ActionRequest actionRequest, ActionResponse actionResponse) { actionResponse.setRenderParameters(actionRequest.getParameterMap()); } @ModelAttribute("displayCourseUpdates") public Boolean getDisplayCourseUpdates(PortletRequest req) { String val = req.getPreferences().getValue(DISPLAY_COURSE_UPDATES_PREFERENCE, Boolean.TRUE.toString()); return Boolean.valueOf(val); } @ModelAttribute("displayCourseBooks") public Boolean getDisplayCourseBooks(PortletRequest req) { String val = req.getPreferences().getValue(DISPLAY_COURSE_BOOKS_PREFERENCE, Boolean.TRUE.toString()); return Boolean.valueOf(val); } /** * Determine the term code to use. If a term code is specified on the request it is returned and stored * in the portlet session. If no term code is specified on the request the session is checked for a stored * term code. */ protected String getSelectedTermCode(PortletRequest portletRequest, String requestTermCode) { final PortletSession portletSession = portletRequest.getPortletSession(); if (requestTermCode != null) { portletSession.setAttribute(TERMCODE, requestTermCode); return requestTermCode; } return (String)portletSession.getAttribute(TERMCODE); } /** * If termCode is null {@link TermList#getCurrentTerm()} is used, if not {@link TermList#getTerm(String)} is used */ protected Term getSelectedTerm(String termCode, final TermList termList) { if (termCode == null) { return termList.getCurrentTerm(); } return termList.getTerm(termCode); } private String getPVI(List<AdditionalInfo> addInfoList) { for (AdditionalInfo addInfo : addInfoList) { if("pvi".equals(addInfo.getKey())) return addInfo.getValue(); } return null; } /** * Generate a link to the Course Detail View for the given course parameters * <p/> * These are subject to change, as <pre>courseCode</pre> isn't necessary and * <pre>classNbr</pre> shouldn't be necessary. * * @param course The course to get the detail view link for * @param section Provides the <pre>courseId</pre> parameter. * Should be removed. * @param response Required to create the {@link PortletURL} object * @param term Term code for the <pre>termCode</pre> url parameter * (obviously) * * @return A PortletURL with all the parameters defined to link to the students * course detail page for the specified course and term */ private PortletURL createCourseDetailUrl(Course course, CourseSection section, MimeResponse response, String term) { PortletURL url = response.createRenderURL(); url.setParameter("classNbr", section.getId()); url.setParameter("action", "showCourse"); url.setParameter("courseId", course.getId()); url.setParameter("subjectCode", course.getCourseDepartment().getCode()); url.setParameter("termCode", term); url.setParameter("catalogNbr", course.getCode()); url.setParameter("courseCode", course.getCode()); return url; } private List<CourseSectionMeetingWrapper> getCourseMeetingsWrapperList(Course course,PortletPreferences prefs,boolean isMobile,String termCode) { List<CourseSectionMeetingWrapper> courseSectionMeetingWrapperList =new ArrayList<CourseSectionMeetingWrapper>(); for (CourseSection courseSection:course.getCourseSections()) { logger.debug("DUMPING COURSE MEETINGS >>>>>>>>>>>"+courseSection.getCode()); logger.debug("DUMPING COURSE MEETINGS SIZE>>>>>>>>>>>"+courseSection.getCourseMeetings().size()); courseSectionMeetingWrapperList.add(new CourseSectionMeetingWrapper(courseSection,prefs,isMobile,termCode,urlService)); } if (logger.isDebugEnabled()) { logger.debug("DUMPING COURSE MEETINGS>>>>>>>>>>>"); new CourseSectionMeetingWrapper().printCourseSectionWrapperList(courseSectionMeetingWrapperList); } return courseSectionMeetingWrapperList; } }