Index: lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java =================================================================== diff -u -r2a60aefd13ef4aac8e67f7e23ff837062aa837d9 -r59044e7541aada72fb2b0c82589b55c61379106a --- lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision 2a60aefd13ef4aac8e67f7e23ff837062aa837d9) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision 59044e7541aada72fb2b0c82589b55c61379106a) @@ -88,6 +88,8 @@ import org.lamsfoundation.lams.monitoring.service.IMonitoringService; import org.lamsfoundation.lams.monitoring.service.MonitoringServiceException; import org.lamsfoundation.lams.outcome.service.IOutcomeService; +import org.lamsfoundation.lams.rest.RestTags; +import org.lamsfoundation.lams.rest.ToolRestManager; import org.lamsfoundation.lams.tool.SystemTool; import org.lamsfoundation.lams.tool.Tool; import org.lamsfoundation.lams.tool.ToolContentIDGenerator; @@ -118,6 +120,8 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -1407,6 +1411,27 @@ return newToolContentID; } + @Override + public Long createToolContent(UserDTO user, String toolSignature, ObjectNode toolContentJSON) throws IOException { + try { + Tool tool = toolDAO.getToolBySignature(toolSignature); + Long toolContentID = insertToolContentID(tool.getToolId()); + + // Tools' services implement an interface for processing REST requests + ToolRestManager toolRestService = (ToolRestManager) lamsCoreToolService.findToolService(tool); + toolRestService.createRestToolContent(user.getUserID(), toolContentID, toolContentJSON); + + return toolContentID; + } catch (Exception e) { + log.error("Unable to create tool content for " + toolSignature + " with details " + toolContentJSON + + ". \nThe tool probably threw an exception - check the server logs for more details.\n" + + "If the exception is \"Servlet.service() for servlet ToolContentRestServlet threw exception java.lang.ClassCastException: com.sun.proxy.$ProxyXXX cannot be cast to org.lamsfoundation.lams.rest.ToolRestManager)\"" + + " then the tool has not implemented the ToolRestManager interface / createRestToolContent() method."); + throw new ToolException( + "Unable to create tool content for " + toolSignature + " with details " + toolContentJSON); + } + } + /** * @see org.lamsfoundation.lams.authoring.service.IAuthoringFullService#getAvailableLicenses() */ @@ -1574,4 +1599,86 @@ public FolderContentDTO getUserWorkspaceFolder(Integer userID) throws IOException { return workspaceManagementService.getUserWorkspaceFolder(userID); } + + /** + * Helper method to create a Assessment tool content. Assessment is one of the unusuals tool in that it caches + * user's login names and + * first/last names Mandatory fields in toolContentJSON: title, instructions, resources, user fields firstName, + * lastName and loginName. + * + * Required fields in toolContentJSON: "title", "instructions", "questions", "firstName", "lastName", "lastName", + * "questions" and "references". + * + * The questions entry should be ArrayNode containing JSON objects, which in turn must contain + * "questionTitle", "questionText", "displayOrder" (Integer), "type" (Integer). If the type is Multiple Choice, + * Numerical or Matching Pairs + * then a ArrayNode "answers" is required. + * + * The answers entry should be ArrayNode + * containing JSON objects, which in turn must contain "answerText" or "answerFloat", "displayOrder" (Integer), + * "grade" (Integer). + * + * For the templates, all the questions that are created will be set up as references, therefore the questions in + * the assessment == the bank of questions. + * So references entry will be a ArrayNode containing JSON objects, which in turn must contain "displayOrder" + * (Integer), + * "questionDisplayOrder" (Integer - to match to the question). If default grade or random questions are needed then + * this method needs + * to be expanded. + */ + public Long createTblAssessmentToolContent(UserDTO user, String title, String instructions, + String reflectionInstructions, boolean selectLeaderToolOutput, boolean enableNumbering, + boolean enableConfidenceLevels, boolean allowDiscloseAnswers, boolean allowAnswerJustification, + ArrayNode questions) throws IOException { + + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, + reflectionInstructions, null, null, user); + toolContentJSON.put(RestTags.USE_SELECT_LEADER_TOOL_OUTPUT, selectLeaderToolOutput); + toolContentJSON.put(RestTags.ENABLE_CONFIDENCE_LEVELS, enableConfidenceLevels); + toolContentJSON.put("numbered", enableNumbering); + toolContentJSON.put("displaySummary", Boolean.TRUE); + toolContentJSON.put("allowDiscloseAnswers", allowDiscloseAnswers); + toolContentJSON.put("allowAnswerJustification", allowAnswerJustification); + + if (questions != null) { + toolContentJSON.set(RestTags.QUESTIONS, questions); + + ArrayNode references = JsonNodeFactory.instance.arrayNode(); + for (int i = 0; i < questions.size(); i++) { + ObjectNode question = (ObjectNode) questions.get(i); + question.put("answerRequired", true); + + Integer questionDisplayOrder = question.get(RestTags.DISPLAY_ORDER).asInt(); + Integer defaultGrade = JsonUtil.optInt(question, "defaultGrade", 1); + references.add(JsonNodeFactory.instance.objectNode().put(RestTags.DISPLAY_ORDER, questionDisplayOrder) + .put("questionDisplayOrder", questionDisplayOrder).put("defaultGrade", defaultGrade)); + } + toolContentJSON.set("references", references); + } + + return createToolContent(user, "laasse10", toolContentJSON); + } + + /** Sets up the standard fields that are used by many TBL template tools */ + public static ObjectNode createStandardToolContent(String title, String instructions, String reflectionInstructions, + Boolean lockWhenFinished, Boolean allowRichTextEditor, UserDTO user) { + ObjectNode toolContentJSON = JsonNodeFactory.instance.objectNode(); + toolContentJSON.put(RestTags.TITLE, title != null ? title : ""); + toolContentJSON.put(RestTags.INSTRUCTIONS, instructions != null ? instructions : ""); + + if (reflectionInstructions != null) { + toolContentJSON.put(RestTags.REFLECT_ON_ACTIVITY, true); + toolContentJSON.put(RestTags.REFLECT_INSTRUCTIONS, reflectionInstructions); + } + + toolContentJSON.put(RestTags.LOCK_WHEN_FINISHED, lockWhenFinished); + toolContentJSON.put(RestTags.ALLOW_RICH_TEXT_EDITOR, allowRichTextEditor); + + if (user != null) { + toolContentJSON.put("firstName", user.getFirstName()); + toolContentJSON.put("lastName", user.getLastName()); + toolContentJSON.put("loginName", user.getLogin()); + } + return toolContentJSON; + } } \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/authoring/service/IAuthoringFullService.java =================================================================== diff -u -re3bdd10ab88fbb1a570a9a79de64df6dbfef2922 -r59044e7541aada72fb2b0c82589b55c61379106a --- lams_central/src/java/org/lamsfoundation/lams/authoring/service/IAuthoringFullService.java (.../IAuthoringFullService.java) (revision e3bdd10ab88fbb1a570a9a79de64df6dbfef2922) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/service/IAuthoringFullService.java (.../IAuthoringFullService.java) (revision 59044e7541aada72fb2b0c82589b55c61379106a) @@ -36,9 +36,11 @@ import org.lamsfoundation.lams.learningdesign.dto.ValidationErrorDTO; import org.lamsfoundation.lams.learningdesign.exception.LearningDesignException; import org.lamsfoundation.lams.tool.dto.ToolOutputDefinitionDTO; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.usermanagement.exception.UserException; import org.lamsfoundation.lams.usermanagement.exception.WorkspaceFolderException; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -109,6 +111,8 @@ */ Long copyToolContent(Long toolContentID, String customCSV) throws IOException; + Long createToolContent(UserDTO user, String toolSignature, ObjectNode toolContentJSON) throws IOException; + /** * Get the available licenses. This will include our supported Creative Common licenses and an "OTHER" license which * may be used for user entered license details. The picture url supplied should be a full URL i.e. if it was a @@ -141,4 +145,8 @@ List updateLearningDesignAccessByUser(Integer userId); void storeLearningDesignAccess(Long learningDesignId, Integer userId); + + Long createTblAssessmentToolContent(UserDTO user, String title, String instructions, String reflectionInstructions, + boolean selectLeaderToolOutput, boolean enableNumbering, boolean enableConfidenceLevels, + boolean allowDiscloseAnswers, boolean allowAnswerJustification, ArrayNode questions) throws IOException; } \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/LdTemplateController.java =================================================================== diff -u -r2a60aefd13ef4aac8e67f7e23ff837062aa837d9 -r59044e7541aada72fb2b0c82589b55c61379106a --- lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/LdTemplateController.java (.../LdTemplateController.java) (revision 2a60aefd13ef4aac8e67f7e23ff837062aa837d9) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/LdTemplateController.java (.../LdTemplateController.java) (revision 59044e7541aada72fb2b0c82589b55c61379106a) @@ -41,6 +41,7 @@ import javax.servlet.http.HttpSession; import org.apache.log4j.Logger; +import org.lamsfoundation.lams.authoring.service.AuthoringService; import org.lamsfoundation.lams.authoring.service.IAuthoringFullService; import org.lamsfoundation.lams.authoring.template.AssessMCAnswer; import org.lamsfoundation.lams.authoring.template.Assessment; @@ -58,10 +59,8 @@ import org.lamsfoundation.lams.questions.Question; import org.lamsfoundation.lams.questions.QuestionParser; import org.lamsfoundation.lams.rest.RestTags; -import org.lamsfoundation.lams.rest.ToolRestManager; import org.lamsfoundation.lams.tool.Tool; import org.lamsfoundation.lams.tool.dao.IToolDAO; -import org.lamsfoundation.lams.tool.exception.ToolException; import org.lamsfoundation.lams.tool.service.ILamsCoreToolService; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.util.AuthoringJsonTags; @@ -665,29 +664,6 @@ return activityJSON; } - /* ************************************** Tool related methods ********************************************** */ - /** General method to create a tool content. All calls to create tool content should go through this method */ - protected Long createToolContent(UserDTO user, String toolSignature, ObjectNode toolContentJSON) - throws IOException { - try { - Tool tool = getTool(toolSignature); - Long toolContentID = authoringService.insertToolContentID(tool.getToolId()); - - // Tools' services implement an interface for processing REST requests - ToolRestManager toolRestService = (ToolRestManager) lamsCoreToolService.findToolService(tool); - toolRestService.createRestToolContent(user.getUserID(), toolContentID, toolContentJSON); - - return toolContentID; - } catch (Exception e) { - log.error("Unable to create tool content for " + toolSignature + " with details " + toolContentJSON - + ". \nThe tool probably threw an exception - check the server logs for more details.\n" - + "If the exception is \"Servlet.service() for servlet ToolContentRestServlet threw exception java.lang.ClassCastException: com.sun.proxy.$ProxyXXX cannot be cast to org.lamsfoundation.lams.rest.ToolRestManager)\"" - + " then the tool doesn't support the LDTemplate service calls (ie has not implemented the ToolRestManager interface / createRestToolContent() method."); - throw new ToolException( - "Unable to create tool content for " + toolSignature + " with details " + toolContentJSON); - } - } - /** * General method to create tool activity. All calls to create an activity relating to a tool should go through this * method @@ -735,87 +711,7 @@ return activityJSON; } - /** Sets up the standard fields that are used by many tools! */ - protected ObjectNode createStandardToolContent(String title, String instructions, String reflectionInstructions, - Boolean lockWhenFinished, Boolean allowRichTextEditor, UserDTO user) { - ObjectNode toolContentJSON = JsonNodeFactory.instance.objectNode(); - toolContentJSON.put(RestTags.TITLE, title != null ? title : ""); - toolContentJSON.put(RestTags.INSTRUCTIONS, instructions != null ? instructions : ""); - - if (reflectionInstructions != null) { - toolContentJSON.put(RestTags.REFLECT_ON_ACTIVITY, true); - toolContentJSON.put(RestTags.REFLECT_INSTRUCTIONS, reflectionInstructions); - } - - toolContentJSON.put(RestTags.LOCK_WHEN_FINISHED, lockWhenFinished); - toolContentJSON.put(RestTags.ALLOW_RICH_TEXT_EDITOR, allowRichTextEditor); - - if (user != null) { - toolContentJSON.put("firstName", user.getFirstName()); - toolContentJSON.put("lastName", user.getLastName()); - toolContentJSON.put("loginName", user.getLogin()); - } - return toolContentJSON; - } - /** - * Helper method to create a Assessment tool content. Assessment is one of the unusuals tool in that it caches - * user's login names and - * first/last names Mandatory fields in toolContentJSON: title, instructions, resources, user fields firstName, - * lastName and loginName. - * - * Required fields in toolContentJSON: "title", "instructions", "questions", "firstName", "lastName", "lastName", - * "questions" and "references". - * - * The questions entry should be ArrayNode containing JSON objects, which in turn must contain - * "questionTitle", "questionText", "displayOrder" (Integer), "type" (Integer). If the type is Multiple Choice, - * Numerical or Matching Pairs - * then a ArrayNode "answers" is required. - * - * The answers entry should be ArrayNode - * containing JSON objects, which in turn must contain "answerText" or "answerFloat", "displayOrder" (Integer), - * "grade" (Integer). - * - * For the templates, all the questions that are created will be set up as references, therefore the questions in - * the assessment == the bank of questions. - * So references entry will be a ArrayNode containing JSON objects, which in turn must contain "displayOrder" - * (Integer), - * "questionDisplayOrder" (Integer - to match to the question). If default grade or random questions are needed then - * this method needs - * to be expanded. - */ - protected Long createAssessmentToolContent(UserDTO user, String title, String instructions, - String reflectionInstructions, boolean selectLeaderToolOutput, boolean enableNumbering, - boolean enableConfidenceLevels, boolean allowDiscloseAnswers, boolean allowAnswerJustification, - ArrayNode questions) throws IOException { - - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, reflectionInstructions, null, null, - user); - toolContentJSON.put(RestTags.USE_SELECT_LEADER_TOOL_OUTPUT, selectLeaderToolOutput); - toolContentJSON.put(RestTags.ENABLE_CONFIDENCE_LEVELS, enableConfidenceLevels); - toolContentJSON.put("numbered", enableNumbering); - toolContentJSON.put("displaySummary", Boolean.TRUE); - toolContentJSON.put("allowDiscloseAnswers", allowDiscloseAnswers); - toolContentJSON.put("allowAnswerJustification", allowAnswerJustification); - - toolContentJSON.set(RestTags.QUESTIONS, questions); - - ArrayNode references = JsonNodeFactory.instance.arrayNode(); - for (int i = 0; i < questions.size(); i++) { - ObjectNode question = (ObjectNode) questions.get(i); - question.put("answerRequired", true); - - Integer questionDisplayOrder = question.get(RestTags.DISPLAY_ORDER).asInt(); - Integer defaultGrade = JsonUtil.optInt(question, "defaultGrade", 1); - references.add(JsonNodeFactory.instance.objectNode().put(RestTags.DISPLAY_ORDER, questionDisplayOrder) - .put("questionDisplayOrder", questionDisplayOrder).put("defaultGrade", defaultGrade)); - } - toolContentJSON.set("references", references); - - return createToolContent(user, LdTemplateController.ASSESSMENT_TOOL_SIGNATURE, toolContentJSON); - } - - /** * Creates a forum activity's JSON details. */ protected ObjectNode createAssessmentActivity(AtomicInteger uiid, int order, Integer[] layoutCoords, @@ -836,10 +732,10 @@ protected Long createChatToolContent(UserDTO user, String title, String instructions, boolean lockWhenFinished, String filterKeywords, String reflectionInstructions) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, reflectionInstructions, - lockWhenFinished, null, null); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, + reflectionInstructions, lockWhenFinished, null, null); toolContentJSON.put("filterKeywords", filterKeywords); - return createToolContent(user, LdTemplateController.CHAT_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.CHAT_TOOL_SIGNATURE, toolContentJSON); } /** @@ -875,8 +771,8 @@ boolean allowRichTextEditor, boolean allowNewTopic, boolean allowRateMessages, boolean allowUpload, boolean limitedMaxCharacters, Integer maxCharacters, ArrayNode topics) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, lockWhenFinished, - allowRichTextEditor, user); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, + lockWhenFinished, allowRichTextEditor, user); toolContentJSON.set("topics", topics); toolContentJSON.put("allowNewTopic", allowNewTopic); toolContentJSON.put("allowRateMessages", allowRateMessages); @@ -885,7 +781,7 @@ if (limitedMaxCharacters && maxCharacters != null) { toolContentJSON.put("maxCharacters", maxCharacters); } - return createToolContent(user, LdTemplateController.FORUM_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.FORUM_TOOL_SIGNATURE, toolContentJSON); } /** @@ -906,8 +802,9 @@ */ protected Long createLeaderSelectionToolContent(UserDTO user, String title, String instructions) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, null, null, null); - return createToolContent(user, LdTemplateController.LEADER_TOOL_SIGNATURE, toolContentJSON); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, null, null, + null); + return authoringService.createToolContent(user, LdTemplateController.LEADER_TOOL_SIGNATURE, toolContentJSON); } /** @@ -929,9 +826,9 @@ protected Long createNotebookToolContent(UserDTO user, String title, String instructions, boolean lockWhenFinished, boolean allowRichTextEditor) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, lockWhenFinished, - allowRichTextEditor, null); - return createToolContent(user, LdTemplateController.NOTEBOOK_TOOL_SIGNATURE, toolContentJSON); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, + lockWhenFinished, allowRichTextEditor, null); + return authoringService.createToolContent(user, LdTemplateController.NOTEBOOK_TOOL_SIGNATURE, toolContentJSON); } /** @@ -953,9 +850,11 @@ protected Long createNoticeboardToolContent(UserDTO user, String title, String content, String reflectionInstructions) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, null, reflectionInstructions, null, null, null); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, null, reflectionInstructions, + null, null, null); toolContentJSON.put("content", content != null ? content : ""); - return createToolContent(user, LdTemplateController.NOTICEBOARD_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.NOTICEBOARD_TOOL_SIGNATURE, + toolContentJSON); } /** @@ -978,13 +877,13 @@ boolean allowRichTextEditor, boolean oneQuestionPerPage, boolean showOtherLearnersAnswers, boolean showOtherLearnersNames, ArrayNode questions) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, lockWhenFinished, - allowRichTextEditor, null); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, + lockWhenFinished, allowRichTextEditor, null); toolContentJSON.set(RestTags.QUESTIONS, questions); toolContentJSON.put("questionsSequenced", oneQuestionPerPage); toolContentJSON.put("showOtherAnswers", showOtherLearnersAnswers); toolContentJSON.put("usernameVisible", showOtherLearnersNames); - return createToolContent(user, LdTemplateController.QA_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.QA_TOOL_SIGNATURE, toolContentJSON); } /** @@ -1007,12 +906,13 @@ boolean useSelectLeaderToolOuput, boolean enableConfidenceLevel, boolean prefixAnswersWithLetters, ArrayNode questions) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, null, null, null); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, null, null, + null); toolContentJSON.put(RestTags.USE_SELECT_LEADER_TOOL_OUTPUT, useSelectLeaderToolOuput); toolContentJSON.set(RestTags.QUESTIONS, questions); toolContentJSON.put(RestTags.ENABLE_CONFIDENCE_LEVELS, enableConfidenceLevel); toolContentJSON.put("prefixAnswersWithLetters", prefixAnswersWithLetters); - return createToolContent(user, LdTemplateController.MCQ_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.MCQ_TOOL_SIGNATURE, toolContentJSON); } /** @@ -1034,9 +934,10 @@ protected Long createMindmapToolContent(UserDTO user, String title, String instructions, boolean lockWhenFinished, boolean multiUserMode, String reflectionInstruction) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, lockWhenFinished, null, null); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, + lockWhenFinished, null, null); toolContentJSON.put("multiUserMode", multiUserMode); - return createToolContent(user, LdTemplateController.MINDMAP_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.MINDMAP_TOOL_SIGNATURE, toolContentJSON); } /** @@ -1063,8 +964,8 @@ boolean notifyInstructors, Integer minResourcesToView, String reflectionInstructions, ArrayNode resources) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, reflectionInstructions, - lockWhenFinished, null, user); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, + reflectionInstructions, lockWhenFinished, null, user); toolContentJSON.put("allowAddFiles", allowLearnerAddFile); toolContentJSON.put("allowAddUrls", allowLearnerAddURL); toolContentJSON.put("notifyTeachersOnAssigmentSumbit", notifyInstructors); @@ -1073,7 +974,8 @@ toolContentJSON.put("minViewResourceNumber", minResourcesToView); } toolContentJSON.set("resources", resources); - return createToolContent(user, LdTemplateController.SHARE_RESOURCES_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.SHARE_RESOURCES_TOOL_SIGNATURE, + toolContentJSON); } // resource type - copied from ResourceConstants @@ -1157,7 +1059,8 @@ boolean useSelectLeaderToolOuput, Integer confidenceLevelsActivityUiid, ArrayNode questions) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, null, null, null); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, null, null, + null); toolContentJSON.set(RestTags.QUESTIONS, questions); if (confidenceLevelsActivityUiid != null) { toolContentJSON.put(RestTags.CONFIDENCE_LEVELS_ACTIVITY_UIID, confidenceLevelsActivityUiid); @@ -1168,7 +1071,7 @@ question.put("answerRequired", true); } - return createToolContent(user, LdTemplateController.SCRATCHIE_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.SCRATCHIE_TOOL_SIGNATURE, toolContentJSON); } /** @@ -1192,12 +1095,12 @@ boolean autoSelectScribe, boolean showAggregatedReports, String reflectionInstructions, ArrayNode questions) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, reflectionInstructions, - lockWhenFinished, null, null); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, + reflectionInstructions, lockWhenFinished, null, null); toolContentJSON.set(RestTags.QUESTIONS, questions); toolContentJSON.put("autoSelectScribe", autoSelectScribe); toolContentJSON.put("showAggregatedReports", showAggregatedReports); - return createToolContent(user, LdTemplateController.SCRIBE_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.SCRIBE_TOOL_SIGNATURE, toolContentJSON); } /** @@ -1220,13 +1123,13 @@ protected Long createSubmitToolContent(UserDTO user, String title, String instructions, boolean lockWhenFinished, Boolean limitUpload, Integer limitUploadNumber, String reflectionInstructions) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, reflectionInstructions, - lockWhenFinished, null, user); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, + reflectionInstructions, lockWhenFinished, null, user); if (limitUploadNumber != null) { toolContentJSON.put("limitUpload", limitUpload != null ? limitUpload : true); toolContentJSON.put("limitUploadNumber", limitUploadNumber); } - return createToolContent(user, LdTemplateController.SUBMIT_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.SUBMIT_TOOL_SIGNATURE, toolContentJSON); } /** @@ -1248,9 +1151,10 @@ protected Long createSurveyToolContent(UserDTO user, String title, String instructions, Boolean lockWhenFinished, ArrayNode questions) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, lockWhenFinished, null, user); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, + lockWhenFinished, null, user); toolContentJSON.set("questions", questions); - return createToolContent(user, LdTemplateController.SURVEY_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.SURVEY_TOOL_SIGNATURE, toolContentJSON); } /** @@ -1272,10 +1176,11 @@ protected Long createVoteToolContent(UserDTO user, String title, String instructions, ArrayNode answers, Boolean showResults) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, null, null, null); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, null, null, + null); toolContentJSON.set(RestTags.ANSWERS, answers); toolContentJSON.put("showResults", showResults); - return createToolContent(user, LdTemplateController.VOTE_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.VOTE_TOOL_SIGNATURE, toolContentJSON); } /** @@ -1296,9 +1201,10 @@ protected Long createWikiToolContent(UserDTO user, String title, String instructions, boolean lockWhenFinished, String reflectionInstruction, ArrayNode pages) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, null, lockWhenFinished, null, null); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, null, + lockWhenFinished, null, null); toolContentJSON.set("pages", pages); - return createToolContent(user, LdTemplateController.WIKI_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.WIKI_TOOL_SIGNATURE, toolContentJSON); } /** @@ -1323,10 +1229,11 @@ protected Long createPeerReviewToolContent(UserDTO user, String title, String instructions, String reflectionInstructions, ArrayNode criterias) throws IOException { - ObjectNode toolContentJSON = createStandardToolContent(title, instructions, reflectionInstructions, null, null, - user); + ObjectNode toolContentJSON = AuthoringService.createStandardToolContent(title, instructions, + reflectionInstructions, null, null, user); toolContentJSON.set("criterias", criterias); - return createToolContent(user, LdTemplateController.PEER_REVIEW_TOOL_SIGNATURE, toolContentJSON); + return authoringService.createToolContent(user, LdTemplateController.PEER_REVIEW_TOOL_SIGNATURE, + toolContentJSON); } /** Index: lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/TBLTemplateController.java =================================================================== diff -u -rb0aa5ff530f717d8edb5a08bc52336837c1e83c8 -r59044e7541aada72fb2b0c82589b55c61379106a --- lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/TBLTemplateController.java (.../TBLTemplateController.java) (revision b0aa5ff530f717d8edb5a08bc52336837c1e83c8) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/template/web/TBLTemplateController.java (.../TBLTemplateController.java) (revision 59044e7541aada72fb2b0c82589b55c61379106a) @@ -153,7 +153,7 @@ activityTitle = data.getText("boilerplate.ira.title"); ArrayNode testQuestionsArray = JsonUtil.readArray(data.testQuestions.values()); - Long iRAToolContentId = createAssessmentToolContent(userDTO, activityTitle, + Long iRAToolContentId = authoringService.createTblAssessmentToolContent(userDTO, activityTitle, data.getText("boilerplate.ira.instructions"), null, false, true, data.confidenceLevelEnable, false, false, testQuestionsArray); ObjectNode iraActivityJSON = createAssessmentActivity(maxUIID, order++, currentActivityPosition, @@ -227,9 +227,9 @@ questionsJSONArray.add(exerciseQuestion.getAsObjectNode(assessmentNumber)); assessmentNumber++; } - Long aetoolContentId = createAssessmentToolContent(userDTO, applicationExerciseTitle, - data.getText("boilerplate.ae.instructions"), null, true, false, false, true, true, - questionsJSONArray); + Long aetoolContentId = authoringService.createTblAssessmentToolContent(userDTO, + applicationExerciseTitle, data.getText("boilerplate.ae.instructions"), null, true, false, false, + true, true, questionsJSONArray); activities.add(createAssessmentActivity(maxUIID, order++, currentActivityPosition, aetoolContentId, data.contentFolderID, groupingUIID, null, null, applicationExerciseTitle)); Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== diff -u -r7526ca9885157455bb66079b6cc8a3571f819de9 -r59044e7541aada72fb2b0c82589b55c61379106a --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 7526ca9885157455bb66079b6cc8a3571f819de9) +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java (.../AssessmentServiceImpl.java) (revision 59044e7541aada72fb2b0c82589b55c61379106a) @@ -3476,167 +3476,172 @@ .collect(Collectors.mapping(q -> q.getUuid().toString(), Collectors.toSet())); ArrayNode questions = JsonUtil.optArray(toolContentJSON, "questions"); Set newQuestionSet = assessment.getQuestions(); // the Assessment constructor will set up the collection - for (JsonNode questionJSONData : questions) { - boolean addToCollection = collection != null; + if (questions != null) { + for (JsonNode questionJSONData : questions) { - AssessmentQuestion question = new AssessmentQuestion(); - Integer type = JsonUtil.optInt(questionJSONData, "type"); - question.setToolContentId(toolContentID); - question.setDisplayOrder(JsonUtil.optInt(questionJSONData, RestTags.DISPLAY_ORDER)); - question.setAnswerRequired(JsonUtil.optBoolean(questionJSONData, "answerRequired", Boolean.FALSE)); + boolean addToCollection = collection != null; - QbQuestion oldQbQuestion = null; - QbQuestion qbQuestion = null; - String uuid = JsonUtil.optString(questionJSONData, RestTags.QUESTION_UUID); + AssessmentQuestion question = new AssessmentQuestion(); + Integer type = JsonUtil.optInt(questionJSONData, "type"); + question.setToolContentId(toolContentID); + question.setDisplayOrder(JsonUtil.optInt(questionJSONData, RestTags.DISPLAY_ORDER)); + question.setAnswerRequired(JsonUtil.optBoolean(questionJSONData, "answerRequired", Boolean.FALSE)); - // try to match the question to an existing QB question in DB - if (StringUtils.isNotBlank(uuid)) { - oldQbQuestion = qbService.getQuestionByUUID(UUID.fromString(uuid)); - } - boolean isModification = oldQbQuestion != null; + QbQuestion oldQbQuestion = null; + QbQuestion qbQuestion = null; + String uuid = JsonUtil.optString(questionJSONData, RestTags.QUESTION_UUID); - // are we modifying an existing question or creating a new one - if (isModification) { - qbQuestion = oldQbQuestion.clone(); - qbService.releaseFromCache(oldQbQuestion); - } else { - qbQuestion = new QbQuestion(); - qbQuestion.setQuestionId(qbService.generateNextQuestionId()); - qbQuestion.setContentFolderId(FileUtil.generateUniqueContentFolderID()); - } + // try to match the question to an existing QB question in DB + if (StringUtils.isNotBlank(uuid)) { + oldQbQuestion = qbService.getQuestionByUUID(UUID.fromString(uuid)); + } + boolean isModification = oldQbQuestion != null; - qbQuestion.setType(type); - qbQuestion.setName(JsonUtil.optString(questionJSONData, RestTags.QUESTION_TITLE)); - qbQuestion.setDescription(JsonUtil.optString(questionJSONData, RestTags.QUESTION_TEXT)); + // are we modifying an existing question or creating a new one + if (isModification) { + qbQuestion = oldQbQuestion.clone(); + qbService.releaseFromCache(oldQbQuestion); + } else { + qbQuestion = new QbQuestion(); + qbQuestion.setQuestionId(qbService.generateNextQuestionId()); + qbQuestion.setContentFolderId(FileUtil.generateUniqueContentFolderID()); + } - qbQuestion.setAllowRichEditor( - JsonUtil.optBoolean(questionJSONData, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); - qbQuestion.setCaseSensitive(JsonUtil.optBoolean(questionJSONData, "caseSensitive", Boolean.FALSE)); - qbQuestion.setCorrectAnswer(JsonUtil.optBoolean(questionJSONData, "correctAnswer", Boolean.FALSE)); - qbQuestion.setMaxMark(JsonUtil.optInt(questionJSONData, "defaultGrade", 1)); - qbQuestion.setFeedback(JsonUtil.optString(questionJSONData, "feedback")); - qbQuestion.setFeedbackOnCorrect(JsonUtil.optString(questionJSONData, "feedbackOnCorrect")); - qbQuestion.setFeedbackOnIncorrect(JsonUtil.optString(questionJSONData, "feedbackOnIncorrect")); - qbQuestion - .setFeedbackOnPartiallyCorrect(JsonUtil.optString(questionJSONData, "feedbackOnPartiallyCorrect")); - qbQuestion.setMaxWordsLimit(JsonUtil.optInt(questionJSONData, "maxWordsLimit", 0)); - qbQuestion.setMinWordsLimit(JsonUtil.optInt(questionJSONData, "minWordsLimit", 0)); - qbQuestion.setMultipleAnswersAllowed( - JsonUtil.optBoolean(questionJSONData, "multipleAnswersAllowed", Boolean.FALSE)); - qbQuestion.setIncorrectAnswerNullifiesMark( - JsonUtil.optBoolean(questionJSONData, "incorrectAnswerNullifiesMark", Boolean.FALSE)); - qbQuestion.setPenaltyFactor(JsonUtil.optDouble(questionJSONData, "penaltyFactor", 0.0).floatValue()); + qbQuestion.setType(type); + qbQuestion.setName(JsonUtil.optString(questionJSONData, RestTags.QUESTION_TITLE)); + qbQuestion.setDescription(JsonUtil.optString(questionJSONData, RestTags.QUESTION_TEXT)); - if (!isModification) { - // UUID normally gets generated in the DB, but we need it immediately, - // so we generate it programmatically. - // Re-reading the QbQuestion we just saved does not help as it is read from Hibernate cache, - // not from DB where UUID is filed - qbQuestion.setUuid(UUID.randomUUID()); - assessmentDao.insert(qbQuestion); - } + qbQuestion.setAllowRichEditor( + JsonUtil.optBoolean(questionJSONData, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); + qbQuestion.setCaseSensitive(JsonUtil.optBoolean(questionJSONData, "caseSensitive", Boolean.FALSE)); + qbQuestion.setCorrectAnswer(JsonUtil.optBoolean(questionJSONData, "correctAnswer", Boolean.FALSE)); + qbQuestion.setMaxMark(JsonUtil.optInt(questionJSONData, "defaultGrade", 1)); + qbQuestion.setFeedback(JsonUtil.optString(questionJSONData, "feedback")); + qbQuestion.setFeedbackOnCorrect(JsonUtil.optString(questionJSONData, "feedbackOnCorrect")); + qbQuestion.setFeedbackOnIncorrect(JsonUtil.optString(questionJSONData, "feedbackOnIncorrect")); + qbQuestion.setFeedbackOnPartiallyCorrect( + JsonUtil.optString(questionJSONData, "feedbackOnPartiallyCorrect")); + qbQuestion.setMaxWordsLimit(JsonUtil.optInt(questionJSONData, "maxWordsLimit", 0)); + qbQuestion.setMinWordsLimit(JsonUtil.optInt(questionJSONData, "minWordsLimit", 0)); + qbQuestion.setMultipleAnswersAllowed( + JsonUtil.optBoolean(questionJSONData, "multipleAnswersAllowed", Boolean.FALSE)); + qbQuestion.setIncorrectAnswerNullifiesMark( + JsonUtil.optBoolean(questionJSONData, "incorrectAnswerNullifiesMark", Boolean.FALSE)); + qbQuestion.setPenaltyFactor(JsonUtil.optDouble(questionJSONData, "penaltyFactor", 0.0).floatValue()); - if ((type == QbQuestion.TYPE_MATCHING_PAIRS) || (type == QbQuestion.TYPE_MULTIPLE_CHOICE) - || (type == QbQuestion.TYPE_NUMERICAL) || (type == QbQuestion.TYPE_MARK_HEDGING)) { - - if (!questionJSONData.has(RestTags.ANSWERS)) { - throw new IOException("REST Authoring is missing answers for a question of type " + type + ". Data:" - + toolContentJSON); + if (!isModification) { + // UUID normally gets generated in the DB, but we need it immediately, + // so we generate it programmatically. + // Re-reading the QbQuestion we just saved does not help as it is read from Hibernate cache, + // not from DB where UUID is filed + qbQuestion.setUuid(UUID.randomUUID()); + assessmentDao.insert(qbQuestion); } - List optionList = new ArrayList<>(); - ArrayNode optionsData = JsonUtil.optArray(questionJSONData, RestTags.ANSWERS); - for (JsonNode answerData : optionsData) { - int displayOrder = JsonUtil.optInt(answerData, RestTags.DISPLAY_ORDER); - QbOption option = null; - // check if existing question gets modified or do we create a new one - for (QbOption existingOption : qbQuestion.getQbOptions()) { - if (existingOption.getDisplayOrder() == displayOrder) { - option = existingOption; - break; - } + if ((type == QbQuestion.TYPE_MATCHING_PAIRS) || (type == QbQuestion.TYPE_MULTIPLE_CHOICE) + || (type == QbQuestion.TYPE_NUMERICAL) || (type == QbQuestion.TYPE_MARK_HEDGING)) { + + if (!questionJSONData.has(RestTags.ANSWERS)) { + throw new IOException("REST Authoring is missing answers for a question of type " + type + + ". Data:" + toolContentJSON); } - if (option == null) { - option = new QbOption(); - option.setDisplayOrder(displayOrder); - option.setQbQuestion(qbQuestion); - } - Boolean correct = JsonUtil.optBoolean(answerData, RestTags.CORRECT, null); - if (correct == null) { - Double grade = JsonUtil.optDouble(answerData, "grade"); - option.setMaxMark(grade == null ? 0 : grade.floatValue()); - } else { - option.setMaxMark(correct ? 1 : 0); + List optionList = new ArrayList<>(); + ArrayNode optionsData = JsonUtil.optArray(questionJSONData, RestTags.ANSWERS); + for (JsonNode answerData : optionsData) { + int displayOrder = JsonUtil.optInt(answerData, RestTags.DISPLAY_ORDER); + QbOption option = null; + // check if existing question gets modified or do we create a new one + for (QbOption existingOption : qbQuestion.getQbOptions()) { + if (existingOption.getDisplayOrder() == displayOrder) { + option = existingOption; + break; + } + } + if (option == null) { + option = new QbOption(); + option.setDisplayOrder(displayOrder); + option.setQbQuestion(qbQuestion); + } + + Boolean correct = JsonUtil.optBoolean(answerData, RestTags.CORRECT, null); + if (correct == null) { + Double grade = JsonUtil.optDouble(answerData, "grade"); + option.setMaxMark(grade == null ? 0 : grade.floatValue()); + } else { + option.setMaxMark(correct ? 1 : 0); + } + option.setAcceptedError(JsonUtil.optDouble(answerData, "acceptedError", 0.0).floatValue()); + option.setFeedback(JsonUtil.optString(answerData, "feedback")); + option.setName(JsonUtil.optString(answerData, RestTags.ANSWER_TEXT)); + option.setNumericalOption(JsonUtil.optDouble(answerData, "answerFloat", 0.0).floatValue()); + // option.setQuestion(question); can't find the use for this field yet! + optionList.add(option); } - option.setAcceptedError(JsonUtil.optDouble(answerData, "acceptedError", 0.0).floatValue()); - option.setFeedback(JsonUtil.optString(answerData, "feedback")); - option.setName(JsonUtil.optString(answerData, RestTags.ANSWER_TEXT)); - option.setNumericalOption(JsonUtil.optDouble(answerData, "answerFloat", 0.0).floatValue()); - // option.setQuestion(question); can't find the use for this field yet! - optionList.add(option); + qbQuestion.setQbOptions(optionList); } - qbQuestion.setQbOptions(optionList); - } - if (isModification) { - addToCollection &= !collectionUUIDs.contains(uuid); + if (isModification) { + addToCollection &= !collectionUUIDs.contains(uuid); - int isModified = qbQuestion.isQbQuestionModified(oldQbQuestion); - if (isModified == IQbService.QUESTION_MODIFIED_VERSION_BUMP) { - qbQuestion.clearID(); - qbQuestion.setVersion(qbService.getMaxQuestionVersion(qbQuestion.getQuestionId()) + 1); - qbQuestion.setCreateDate(new Date()); - qbQuestion.setUuid(UUID.randomUUID()); - assessmentDao.insert(qbQuestion); - } else if (isModified == IQbService.QUESTION_MODIFIED_NONE) { - // Changes to question and option content does not count as version bump, - // but rather as update of the original question - // They should probably be marked as "update" rather than "none" - assessmentDao.update(qbQuestion); - } else { - throw new IllegalArgumentException( - "Implement other Question Bank modification levels in Assessment tool"); + int isModified = qbQuestion.isQbQuestionModified(oldQbQuestion); + if (isModified == IQbService.QUESTION_MODIFIED_VERSION_BUMP) { + qbQuestion.clearID(); + qbQuestion.setVersion(qbService.getMaxQuestionVersion(qbQuestion.getQuestionId()) + 1); + qbQuestion.setCreateDate(new Date()); + qbQuestion.setUuid(UUID.randomUUID()); + assessmentDao.insert(qbQuestion); + } else if (isModified == IQbService.QUESTION_MODIFIED_NONE) { + // Changes to question and option content does not count as version bump, + // but rather as update of the original question + // They should probably be marked as "update" rather than "none" + assessmentDao.update(qbQuestion); + } else { + throw new IllegalArgumentException( + "Implement other Question Bank modification levels in Assessment tool"); + } } - } - // Store it back into JSON so Scratchie can read it - // and use the same questions, not create new ones - uuid = qbQuestion.getUuid().toString(); - ObjectNode questionData = (ObjectNode) questionJSONData; - questionData.put(RestTags.QUESTION_UUID, uuid); + // Store it back into JSON so Scratchie can read it + // and use the same questions, not create new ones + uuid = qbQuestion.getUuid().toString(); + ObjectNode questionData = (ObjectNode) questionJSONData; + questionData.put(RestTags.QUESTION_UUID, uuid); - // question.setUnits(units); Needed for numerical type question - question.setQbQuestion(qbQuestion); - checkType(question.getType()); - newQuestionSet.add(question); + // question.setUnits(units); Needed for numerical type question + question.setQbQuestion(qbQuestion); + checkType(question.getType()); + newQuestionSet.add(question); - // all questions need to end up in user's private collection - if (addToCollection) { - // qbService.addQuestionToCollection(collection.getUid(), qbQuestion.getQuestionId(), false); - collectionUUIDs.add(uuid); + // all questions need to end up in user's private collection + if (addToCollection) { + // qbService.addQuestionToCollection(collection.getUid(), qbQuestion.getQuestionId(), false); + collectionUUIDs.add(uuid); + } } } // **************************** Now set up the references to the questions in the bank ********************* ArrayNode references = JsonUtil.optArray(toolContentJSON, "references"); - Set newReferenceSet = assessment.getQuestionReferences(); // the Assessment constructor will set up the + if (references != null) { + Set newReferenceSet = assessment.getQuestionReferences(); // the Assessment constructor will set up the - // collection - for (JsonNode referenceJSONData : references) { - QuestionReference reference = new QuestionReference(); - reference.setMaxMark(JsonUtil.optInt(referenceJSONData, "maxMark", 1)); - reference.setSequenceId(JsonUtil.optInt(referenceJSONData, RestTags.DISPLAY_ORDER)); - AssessmentQuestion matchingQuestion = matchQuestion(newQuestionSet, - JsonUtil.optInt(referenceJSONData, "questionDisplayOrder")); - if (matchingQuestion == null) { - throw new IOException("Unable to find matching question for displayOrder " - + referenceJSONData.get("questionDisplayOrder") + ". Data:" + toolContentJSON); + // collection + for (JsonNode referenceJSONData : references) { + QuestionReference reference = new QuestionReference(); + reference.setMaxMark(JsonUtil.optInt(referenceJSONData, "maxMark", 1)); + reference.setSequenceId(JsonUtil.optInt(referenceJSONData, RestTags.DISPLAY_ORDER)); + AssessmentQuestion matchingQuestion = matchQuestion(newQuestionSet, + JsonUtil.optInt(referenceJSONData, "questionDisplayOrder")); + if (matchingQuestion == null) { + throw new IOException("Unable to find matching question for displayOrder " + + referenceJSONData.get("questionDisplayOrder") + ". Data:" + toolContentJSON); + } + reference.setQuestion(matchingQuestion); + reference.setRandomQuestion(JsonUtil.optBoolean(referenceJSONData, "randomQuestion", Boolean.FALSE)); + newReferenceSet.add(reference); } - reference.setQuestion(matchingQuestion); - reference.setRandomQuestion(JsonUtil.optBoolean(referenceJSONData, "randomQuestion", Boolean.FALSE)); - newReferenceSet.add(reference); } saveOrUpdateAssessment(assessment);