Index: lams_central/src/java/org/lamsfoundation/lams/web/outcome/OutcomeController.java =================================================================== diff -u -rfdbc571c3083fb0966a3fb4556ed7c21d0315fc1 -r50f84b60c632e10ccc6981f1ce142e28b23eb44c --- lams_central/src/java/org/lamsfoundation/lams/web/outcome/OutcomeController.java (.../OutcomeController.java) (revision fdbc571c3083fb0966a3fb4556ed7c21d0315fc1) +++ lams_central/src/java/org/lamsfoundation/lams/web/outcome/OutcomeController.java (.../OutcomeController.java) (revision 50f84b60c632e10ccc6981f1ce142e28b23eb44c) @@ -93,7 +93,7 @@ @RequestMapping("/outcomeManage") public String outcomeManage(HttpServletRequest request, HttpServletResponse response) throws Exception { - UserDTO user = getUserDTO(); + UserDTO user = OutcomeController.getUserDTO(); securityService.isSysadmin(user.getUserID(), "import outcomes", true); List outcomes = outcomeService.getOutcomes(); @@ -104,7 +104,7 @@ @RequestMapping("/outcomeEdit") public String outcomeEdit(@ModelAttribute OutcomeForm outcomeForm, HttpServletRequest request, HttpServletResponse response) throws Exception { - UserDTO user = getUserDTO(); + UserDTO user = OutcomeController.getUserDTO(); securityService.isSysadmin(user.getUserID(), "import outcomes", true); Long outcomeId = WebUtil.readLongParam(request, "outcomeId", true); @@ -131,7 +131,7 @@ @RequestMapping(path = "/outcomeSave", method = RequestMethod.POST) public String outcomeSave(@ModelAttribute OutcomeForm outcomeForm, HttpServletRequest request, HttpServletResponse response) throws Exception { - Integer userId = getUserDTO().getUserID(); + Integer userId = OutcomeController.getUserDTO().getUserID(); Long outcomeId = outcomeForm.getOutcomeId(); Outcome outcome = outcomeId == null ? null : (Outcome) userManagementService.findById(Outcome.class, outcomeId); @@ -176,7 +176,7 @@ @RequestMapping(path = "/outcomeRemove", method = RequestMethod.POST) public String outcomeRemove(HttpServletRequest request, HttpServletResponse response) throws Exception { - UserDTO user = getUserDTO(); + UserDTO user = OutcomeController.getUserDTO(); securityService.isSysadmin(user.getUserID(), "import outcomes", true); Long outcomeId = WebUtil.readLongParam(request, "outcomeId", false); @@ -237,32 +237,8 @@ if (!addEnabled) { throw new SecurityException("Adding Learning Outcomes on the fly is disabled"); } - // create a new outcome on the fly - String code = null; - // check if name contains code part - String[] nameParts = name.split("\\("); - if (nameParts.length > 1) { - name = nameParts[0].trim(); - code = nameParts[1].replaceFirst("\\)", "").trim(); - } - outcome = new Outcome(); + outcome = outcomeService.createOutcome(name, OutcomeController.getUserDTO().getUserID()); - Integer userId = getUserDTO().getUserID(); - User user = (User) userManagementService.findById(User.class, userId); - outcome.setCreateBy(user); - outcome.setCreateDateTime(new Date()); - - outcome.setName(name); - outcome.setCode(code); - OutcomeScale scale = (OutcomeScale) userManagementService.findById(OutcomeScale.class, - IOutcomeService.DEFAULT_SCALE_ID); - outcome.setScale(scale); - userManagementService.save(outcome); - - if (log.isDebugEnabled()) { - log.debug("Saved outcome " + outcome.getOutcomeId()); - } - } else { outcome = (Outcome) userManagementService.findById(Outcome.class, outcomeId); } @@ -302,7 +278,7 @@ throw new IllegalArgumentException( "Either lesson ID or tool content ID or QB question ID must not be null when fetching outcome mappings"); } - Integer userId = getUserDTO().getUserID(); + Integer userId = OutcomeController.getUserDTO().getUserID(); if (!request.isUserInRole(Role.SYSADMIN) && !request.isUserInRole(Role.AUTHOR)) { String error = "User " + userId + " is not sysadmin nor an author and can not map outcome"; log.error(error); @@ -353,7 +329,7 @@ if (lessonId == null) { lessonId = lessonService.getLessonByToolContentId(outcomeMapping.getToolContentId()).getLessonId(); } - Integer userId = getUserDTO().getUserID(); + Integer userId = OutcomeController.getUserDTO().getUserID(); securityService.isLessonMonitor(lessonId, userId, "set outcome result", true); OutcomeResult result = outcomeService.getOutcomeResult(userId, mappingId); @@ -403,7 +379,7 @@ @RequestMapping("/outcomeExport") public void outcomeExport(HttpServletRequest request, HttpServletResponse response) throws Exception { - UserDTO user = getUserDTO(); + UserDTO user = OutcomeController.getUserDTO(); securityService.isSysadmin(user.getUserID(), "export outcomes", true); List sheets = outcomeService.exportOutcomes(); @@ -428,7 +404,7 @@ @RequestMapping("/outcomeImport") public String outcomeImport(@RequestParam("file") MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception { - UserDTO user = getUserDTO(); + UserDTO user = OutcomeController.getUserDTO(); securityService.isSysadmin(user.getUserID(), "import outcomes", true); try { @@ -498,7 +474,7 @@ @RequestMapping("/scaleSave") public String scaleSave(@ModelAttribute("scaleForm") OutcomeScaleForm scaleForm, HttpServletRequest request, HttpServletResponse response) throws Exception { - Integer userId = getUserDTO().getUserID(); + Integer userId = OutcomeController.getUserDTO().getUserID(); Long scaleId = scaleForm.getScaleId(); OutcomeScale scale = scaleId == null ? null : (OutcomeScale) userManagementService.findById(OutcomeScale.class, scaleId); @@ -576,7 +552,7 @@ @RequestMapping("/scaleExport") public void scaleExport(HttpServletRequest request, HttpServletResponse response) throws Exception { - UserDTO user = getUserDTO(); + UserDTO user = OutcomeController.getUserDTO(); securityService.isSysadmin(user.getUserID(), "export outcome scales", true); List sheets = outcomeService.exportScales(); @@ -601,7 +577,7 @@ @RequestMapping("/scaleImport") public String scaleImport(@RequestParam("file") MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception { - UserDTO user = getUserDTO(); + UserDTO user = OutcomeController.getUserDTO(); securityService.isSysadmin(user.getUserID(), "import outcome scales", true); try { @@ -617,7 +593,7 @@ return scaleManage(request, response); } - private UserDTO getUserDTO() { + private static UserDTO getUserDTO() { HttpSession ss = SessionManager.getSession(); return (UserDTO) ss.getAttribute(AttributeNames.USER); } Index: lams_central/src/java/org/lamsfoundation/lams/web/qb/ImsQtiController.java =================================================================== diff -u -r717b74bffccda68d3a0a65d6bdb9b6356091cc08 -r50f84b60c632e10ccc6981f1ce142e28b23eb44c --- lams_central/src/java/org/lamsfoundation/lams/web/qb/ImsQtiController.java (.../ImsQtiController.java) (revision 717b74bffccda68d3a0a65d6bdb9b6356091cc08) +++ lams_central/src/java/org/lamsfoundation/lams/web/qb/ImsQtiController.java (.../ImsQtiController.java) (revision 50f84b60c632e10ccc6981f1ce142e28b23eb44c) @@ -12,9 +12,13 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.lamsfoundation.lams.outcome.Outcome; +import org.lamsfoundation.lams.outcome.OutcomeMapping; +import org.lamsfoundation.lams.outcome.service.IOutcomeService; import org.lamsfoundation.lams.qb.model.QbCollection; import org.lamsfoundation.lams.qb.model.QbOption; import org.lamsfoundation.lams.qb.model.QbQuestion; @@ -23,9 +27,12 @@ import org.lamsfoundation.lams.questions.Question; import org.lamsfoundation.lams.questions.QuestionExporter; import org.lamsfoundation.lams.questions.QuestionParser; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.FileUtil; import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; @@ -56,9 +63,13 @@ @Autowired private IUserManagementService userManagementService; + @Autowired + private IOutcomeService outcomeService; + /** * Parses questions extracted from IMS QTI file and adds them as new QB questions. */ + @SuppressWarnings("unchecked") @RequestMapping(path = "/saveQTI", produces = "text/plain", method = RequestMethod.POST) @ResponseBody public String saveQTI(HttpServletRequest request, @RequestParam long collectionUid, @@ -339,6 +350,26 @@ qbQuestion.setMaxMark(questionMark); userManagementService.save(qbQuestion); + if (question.getLearningOutcomes() != null && !question.getLearningOutcomes().isEmpty()) { + for (String learningOutcomeText : question.getLearningOutcomes()) { + learningOutcomeText = learningOutcomeText.strip(); + List learningOutcomes = userManagementService.findByProperty(Outcome.class, "name", + learningOutcomeText); + Outcome learningOutcome = null; + if (learningOutcomes.isEmpty()) { + learningOutcome = outcomeService.createOutcome(learningOutcomeText, + ImsQtiController.getUserDTO().getUserID()); + } else { + learningOutcome = learningOutcomes.get(0); + } + + OutcomeMapping outcomeMapping = new OutcomeMapping(); + outcomeMapping.setOutcome(learningOutcome); + outcomeMapping.setQbQuestionId(questionId); + userManagementService.save(outcomeMapping); + } + } + qbService.addQuestionToCollection(collectionUid, qbQuestion.getQuestionId(), false); qbQuestionUidsString.append(qbQuestion.getUid()).append(','); @@ -549,4 +580,9 @@ QuestionExporter exporter = new QuestionExporter(fileTitle, questions.toArray(Question.QUESTION_ARRAY_TYPE)); exporter.exportQTIPackage(request, response); } -} + + private static UserDTO getUserDTO() { + HttpSession ss = SessionManager.getSession(); + return (UserDTO) ss.getAttribute(AttributeNames.USER); + } +} \ No newline at end of file Index: lams_central/web/questions/questionChoice.jsp =================================================================== diff -u -r05c00f92856ef13cd90d6fce06acb069418c2512 -r50f84b60c632e10ccc6981f1ce142e28b23eb44c --- lams_central/web/questions/questionChoice.jsp (.../questionChoice.jsp) (revision 05c00f92856ef13cd90d6fce06acb069418c2512) +++ lams_central/web/questions/questionChoice.jsp (.../questionChoice.jsp) (revision 50f84b60c632e10ccc6981f1ce142e28b23eb44c) @@ -263,6 +263,16 @@ + + <%-- Learning Outcomes, if required and exist --%> + + + + + +
Index: lams_common/src/java/org/lamsfoundation/lams/outcome/service/IOutcomeService.java =================================================================== diff -u -r95a88e5e56253d7007ebf634b6969cb353d7cf1e -r50f84b60c632e10ccc6981f1ce142e28b23eb44c --- lams_common/src/java/org/lamsfoundation/lams/outcome/service/IOutcomeService.java (.../IOutcomeService.java) (revision 95a88e5e56253d7007ebf634b6969cb353d7cf1e) +++ lams_common/src/java/org/lamsfoundation/lams/outcome/service/IOutcomeService.java (.../IOutcomeService.java) (revision 50f84b60c632e10ccc6981f1ce142e28b23eb44c) @@ -47,4 +47,6 @@ int importScales(MultipartFile fileItem) throws IOException; int importOutcomes(MultipartFile fileItem) throws IOException; + + Outcome createOutcome(String name, int creatorId); } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/outcome/service/OutcomeService.java =================================================================== diff -u -r89279cb44b252167269043889b3c3c0a4164e0bb -r50f84b60c632e10ccc6981f1ce142e28b23eb44c --- lams_common/src/java/org/lamsfoundation/lams/outcome/service/OutcomeService.java (.../OutcomeService.java) (revision 89279cb44b252167269043889b3c3c0a4164e0bb) +++ lams_common/src/java/org/lamsfoundation/lams/outcome/service/OutcomeService.java (.../OutcomeService.java) (revision 50f84b60c632e10ccc6981f1ce142e28b23eb44c) @@ -6,7 +6,6 @@ import java.util.Date; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -28,7 +27,6 @@ import org.lamsfoundation.lams.usermanagement.User; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.util.MessageService; -import org.lamsfoundation.lams.util.excel.ExcelCell; import org.lamsfoundation.lams.util.excel.ExcelRow; import org.lamsfoundation.lams.util.excel.ExcelSheet; import org.lamsfoundation.lams.web.session.SessionManager; @@ -115,15 +113,15 @@ @Override public List exportScales() { - List sheets = new LinkedList(); + List sheets = new LinkedList<>(); ExcelSheet scalesSheet = new ExcelSheet(messageService.getMessage("scale.title")); - sheets.add(scalesSheet); + sheets.add(scalesSheet); - ExcelRow headerRow = scalesSheet.initRow(); - headerRow.addCell(messageService.getMessage("outcome.manage.add.name"), true); - headerRow.addCell(messageService.getMessage("outcome.manage.add.code"), true); - headerRow.addCell(messageService.getMessage("outcome.manage.add.description"), true); - headerRow.addCell(messageService.getMessage("scale.manage.add.value"), true); + ExcelRow headerRow = scalesSheet.initRow(); + headerRow.addCell(messageService.getMessage("outcome.manage.add.name"), true); + headerRow.addCell(messageService.getMessage("outcome.manage.add.code"), true); + headerRow.addCell(messageService.getMessage("outcome.manage.add.description"), true); + headerRow.addCell(messageService.getMessage("scale.manage.add.value"), true); List scales = getScales(); for (OutcomeScale scale : scales) { @@ -136,12 +134,11 @@ return sheets; } - @Override public List exportOutcomes() { - List sheets = new LinkedList(); + List sheets = new LinkedList<>(); ExcelSheet outcomeSheet = new ExcelSheet(messageService.getMessage("index.outcome.manage")); - sheets.add(outcomeSheet); + sheets.add(outcomeSheet); // The entire data list ExcelRow headerRow = outcomeSheet.initRow(); @@ -290,6 +287,35 @@ return counter; } + @Override + public Outcome createOutcome(String name, int creatorId) { + // create a new outcome on the fly + String code = null; + // check if name contains code part + String[] nameParts = name.split("\\("); + if (nameParts.length > 1) { + name = nameParts[0].trim(); + code = nameParts[1].replaceFirst("\\)", "").trim(); + } + Outcome outcome = new Outcome(); + + User user = outcomeDAO.find(User.class, creatorId); + outcome.setCreateBy(user); + outcome.setCreateDateTime(new Date()); + + outcome.setName(name); + outcome.setCode(code); + OutcomeScale scale = outcomeDAO.find(OutcomeScale.class, IOutcomeService.DEFAULT_SCALE_ID); + outcome.setScale(scale); + outcomeDAO.insert(outcome); + + if (log.isDebugEnabled()) { + log.debug("Saved outcome " + outcome.getOutcomeId()); + } + + return outcome; + } + /** * There can be duplicates in mappings, if one comes from activity and the other comes from a QB question that the * activity imported. Index: lams_common/src/java/org/lamsfoundation/lams/questions/Question.java =================================================================== diff -u -r17f106d9b03871e7278c6eb87f793193d8ff0908 -r50f84b60c632e10ccc6981f1ce142e28b23eb44c --- lams_common/src/java/org/lamsfoundation/lams/questions/Question.java (.../Question.java) (revision 17f106d9b03871e7278c6eb87f793193d8ff0908) +++ lams_common/src/java/org/lamsfoundation/lams/questions/Question.java (.../Question.java) (revision 50f84b60c632e10ccc6981f1ce142e28b23eb44c) @@ -54,6 +54,7 @@ private List answers; private List matchAnswers; private Map matchMap; + private List learningOutcomes; private String resourcesFolderPath; // UUID in QTI question label is LAMS custom idea @@ -126,6 +127,14 @@ this.matchMap = matchMap; } + public List getLearningOutcomes() { + return learningOutcomes; + } + + public void setLearningOutcomes(List learningOutcomes) { + this.learningOutcomes = learningOutcomes; + } + public String getResourcesFolderPath() { return resourcesFolderPath; } Index: lams_common/src/java/org/lamsfoundation/lams/questions/QuestionParser.java =================================================================== diff -u -r15b63adc56c9ce3121aa02108c25834fe9b41d3e -r50f84b60c632e10ccc6981f1ce142e28b23eb44c --- lams_common/src/java/org/lamsfoundation/lams/questions/QuestionParser.java (.../QuestionParser.java) (revision 15b63adc56c9ce3121aa02108c25834fe9b41d3e) +++ lams_common/src/java/org/lamsfoundation/lams/questions/QuestionParser.java (.../QuestionParser.java) (revision 50f84b60c632e10ccc6981f1ce142e28b23eb44c) @@ -467,6 +467,20 @@ } } + // extract learning outcomes + String learningOutcomeCountParam = request.getParameter("learningOutcomeCount" + questionIndex); + int learningOutcomeCount = learningOutcomeCountParam == null ? 0 + : Integer.parseInt(learningOutcomeCountParam); + if (learningOutcomeCount > 0) { + question.setLearningOutcomes(new ArrayList()); + for (int learningOutcomeIndex = 0; learningOutcomeIndex < learningOutcomeCount; learningOutcomeIndex++) { + String learningOutcomeId = "question" + questionIndex + "learningOutcome" + + learningOutcomeIndex; + String learningOutcomeText = request.getParameter(learningOutcomeId); + question.getLearningOutcomes().add(learningOutcomeText); + } + } + result.add(question); } } Index: lams_common/src/java/org/lamsfoundation/lams/questions/QuestionWordParser.java =================================================================== diff -u -red3241c811186aed12304c1118973dd87467d79d -r50f84b60c632e10ccc6981f1ce142e28b23eb44c --- lams_common/src/java/org/lamsfoundation/lams/questions/QuestionWordParser.java (.../QuestionWordParser.java) (revision ed3241c811186aed12304c1118973dd87467d79d) +++ lams_common/src/java/org/lamsfoundation/lams/questions/QuestionWordParser.java (.../QuestionWordParser.java) (revision 50f84b60c632e10ccc6981f1ce142e28b23eb44c) @@ -142,8 +142,9 @@ String title = null; String description = null; - List answers = new ArrayList<>(); String feedback = null; + List answers = new ArrayList<>(); + List learningOutcomes = new ArrayList<>(); boolean optionsStarted = false; boolean isMultipleResponse = false; @@ -197,9 +198,18 @@ if (text.startsWith(FEEDBACK_TAG)) { optionsStarted = true; - feedback = feedback == null ? formattedText : feedback + formattedText; + feedback = feedback == null ? formattedText.substring(FEEDBACK_TAG.length()).strip() + : feedback + formattedText; } + if (text.startsWith(LEARNING_OUTCOME_TAG)) { + optionsStarted = true; + + String learningOutcome = WebUtil.removeHTMLtags(formattedText).strip() + .substring(LEARNING_OUTCOME_TAG.length()).strip(); + learningOutcomes.add(learningOutcome); + } + // if we are still before all options and no answers section started, // then interpret it as question title or description if (!optionsStarted) { @@ -238,6 +248,8 @@ question.setTitle(title); question.setText(description); question.setFeedback(feedback); + question.setLearningOutcomes(learningOutcomes); + if (answers.isEmpty()) { question.setType(Question.QUESTION_TYPE_ESSAY); } else {