Index: lams_tool_assessment/conf/xdoclet/struts-actions.xml =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/conf/xdoclet/struts-actions.xml,v diff -u -r1.12.6.2 -r1.12.6.3 --- lams_tool_assessment/conf/xdoclet/struts-actions.xml 13 Apr 2011 20:11:54 -0000 1.12.6.2 +++ lams_tool_assessment/conf/xdoclet/struts-actions.xml 16 Sep 2011 16:59:54 -0000 1.12.6.3 @@ -126,6 +126,46 @@ parameter="downQuestion"> + + + + + + + + + + + + + + + + + + + + + + + + + + Index: lams_tool_assessment/db/sql/create_lams_tool_assessment.sql =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/db/sql/create_lams_tool_assessment.sql,v diff -u -r1.12.2.2.2.5 -r1.12.2.2.2.6 --- lams_tool_assessment/db/sql/create_lams_tool_assessment.sql 2 Jun 2011 02:14:29 -0000 1.12.2.2.2.5 +++ lams_tool_assessment/db/sql/create_lams_tool_assessment.sql 16 Sep 2011 16:59:54 -0000 1.12.2.2.2.6 @@ -72,6 +72,17 @@ session_uid bigint, primary key (uid) )type=innodb; +create table tl_laasse10_question_reference ( + uid bigint not null auto_increment, + question_uid bigint, + question_type smallint, + title varchar(255), + sequence_id integer, + default_grade integer DEFAULT 1, + random_question tinyint DEFAULT 0, + assessment_uid bigint, + primary key (uid) +)type=innodb; create table tl_laasse10_question_option ( uid bigint not null unique auto_increment, question_uid bigint, @@ -158,6 +169,8 @@ alter table tl_laasse10_assessment_question add index FK_NEW_1720029621_F52D1F93758092FB (create_by), add constraint FK_NEW_1720029621_F52D1F93758092FB foreign key (create_by) references tl_laasse10_user (uid); alter table tl_laasse10_assessment_question add index FK_NEW_1720029621_F52D1F9330E79035 (assessment_uid), add constraint FK_NEW_1720029621_F52D1F9330E79035 foreign key (assessment_uid) references tl_laasse10_assessment (uid); alter table tl_laasse10_assessment_question add index FK_NEW_1720029621_F52D1F93EC0D3147 (session_uid), add constraint FK_NEW_1720029621_F52D1F93EC0D3147 foreign key (session_uid) references tl_laasse10_session (uid); +alter table tl_laasse10_question_reference add index FK_tl_laasse10_question_reference_1 (question_uid), add constraint FK_tl_laasse10_question_reference_1 foreign key (question_uid) references tl_laasse10_assessment_question (uid); +alter table tl_laasse10_question_reference add index FK_tl_laasse10_question_reference_2 (assessment_uid), add constraint FK_tl_laasse10_question_reference_2 foreign key (assessment_uid) references tl_laasse10_assessment (uid); alter table tl_laasse10_question_option add index FK_tl_laasse10_question_option_1 (question_uid), add constraint FK_tl_laasse10_question_option_1 foreign key (question_uid) references tl_laasse10_assessment_question (uid); alter table tl_laasse10_assessment_overall_feedback add index FK_tl_laasse10_assessment_overall_feedback_1 (assessment_uid), add constraint FK_tl_laasse10_assessment_overall_feedback_1 foreign key (assessment_uid) references tl_laasse10_assessment (uid); alter table tl_laasse10_assessment_unit add index FK_tl_laasse10_assessment_unit_1 (question_uid), add constraint FK_tl_laasse10_assessment_unit_1 foreign key (question_uid) references tl_laasse10_assessment_question (uid); Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java,v diff -u -r1.16.6.1 -r1.16.6.2 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java 13 Apr 2011 20:11:54 -0000 1.16.6.1 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/AssessmentConstants.java 16 Sep 2011 16:59:54 -0000 1.16.6.2 @@ -37,6 +37,8 @@ public static final int INITIAL_UNITS_NUMBER = 2; public static final int INITIAL_OVERALL_FEEDBACK_NUMBER = 3; + + public static final String EXPORT_QUESTIONS_FILENAME = "questions.xml"; // question type; public static final short QUESTION_TYPE_MULTIPLE_CHOICE = 1; @@ -70,6 +72,8 @@ public static final String PARAM_FILE_UUID = "fileUuid"; public static final String PARAM_QUESTION_INDEX = "questionIndex"; + + public static final String PARAM_QUESTION_REFERENCE_INDEX = "questionReferenceIndex"; public static final String PARAM_QUESTION_UID = "questionUid"; @@ -117,10 +121,16 @@ public static final String ATTR_QUESTION_TYPE = "questionType"; public static final String ATTR_QUESTION_LIST = "questionList"; + + public static final String ATTR_QUESTION_REFERENCES = "questionReferences"; + + public static final String ATTR_AVAILABLE_QUESTIONS = "availableQuestions"; public static final String ATT_ATTACHMENT_LIST = "instructionAttachmentList"; public static final String ATTR_DELETED_QUESTION_LIST = "deleteAssessmentList"; + + public static final String ATTR_DELETED_QUESTION_REFERENCES = "deleteQuestionReferences"; public static final String ATTR_DELETED_ATTACHMENT_LIST = "deletedAttachmmentList"; Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20110413_updateTo236.sql =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20110413_updateTo236.sql,v diff -u -r1.1.2.2 -r1.1.2.3 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20110413_updateTo236.sql 2 Jun 2011 02:14:29 -0000 1.1.2.2 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/dbupdates/patch20110413_updateTo236.sql 16 Sep 2011 16:59:54 -0000 1.1.2.3 @@ -12,6 +12,20 @@ ALTER TABLE tl_laasse10_assessment ADD COLUMN display_summary tinyint DEFAULT false; +-- LDEV-2714 Pool of questions for assessment tool +create table tl_laasse10_question_reference ( + uid bigint not null auto_increment, + question_uid bigint, + question_type smallint, + title varchar(255), + sequence_id integer, + default_grade integer DEFAULT 1, + random_question tinyint DEFAULT 0, + assessment_uid bigint, + primary key (uid) +)type=innodb; + + ----------------------Put all sql statements above here------------------------- -- If there were no errors, commit and restore autocommit to on Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/Assessment.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/Assessment.java,v diff -u -r1.5.6.4 -r1.5.6.5 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/Assessment.java 2 Jun 2011 02:14:29 -0000 1.5.6.4 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/Assessment.java 16 Sep 2011 16:59:53 -0000 1.5.6.5 @@ -107,9 +107,12 @@ private AssessmentUser createdBy; - // assessment questions + // assessment questions from the pool private Set questions; + // assessment questions references that form question list + private Set questionReferences; + private Set overallFeedbacks; // *************** NON Persist Fields ******************** @@ -126,6 +129,7 @@ public Assessment() { attachments = new TreeSet(); questions = new TreeSet(new SequencableComparator()); + questionReferences = new TreeSet(new SequencableComparator()); overallFeedbacks = new TreeSet(new SequencableComparator()); } @@ -157,6 +161,8 @@ try { assessment = (Assessment) super.clone(); assessment.setUid(null); + + // clone questions if (questions != null) { Iterator iter = questions.iterator(); Set set = new TreeSet(new SequencableComparator()); @@ -168,6 +174,20 @@ } assessment.questions = set; } + + // clone questionReferences + if (questionReferences != null) { + Iterator iter = questionReferences.iterator(); + Set set = new TreeSet(new SequencableComparator()); + while (iter.hasNext()) { + QuestionReference questionReference = (QuestionReference) iter.next(); + QuestionReference newQuestionReference = (QuestionReference) questionReference.clone(); + // just clone old file without duplicate it in repository + set.add(newQuestionReference); + } + assessment.questionReferences = set; + } + // clone OverallFeedbacks if (overallFeedbacks != null) { Iterator iter = overallFeedbacks.iterator(); @@ -469,12 +489,28 @@ return questions; } - public void setQuestions(Set assessmentQuestions) { - this.questions = assessmentQuestions; + public void setQuestions(Set questions) { + this.questions = questions; } /** * + * @hibernate.set lazy="true" inverse="false" cascade="all" order-by="sequence_id asc" + * @hibernate.collection-key column="assessment_uid" + * @hibernate.collection-one-to-many class="org.lamsfoundation.lams.tool.assessment.model.QuestionReference" + * + * @return + */ + public Set getQuestionReferences() { + return questionReferences; + } + + public void setQuestionReferences(Set questionReferences) { + this.questionReferences = questionReferences; + } + + /** + * * @hibernate.set cascade="all" order-by="sequence_id asc" * @hibernate.collection-key column="assessment_uid" * @hibernate.collection-one-to-many class="org.lamsfoundation.lams.tool.assessment.model.AssessmentOverallFeedback" @@ -599,7 +635,6 @@ this.allowHistoryResponses = allowHistoryResponses; } - /** * @hibernate.property column="display_summary" * @return Fisheye: Tag 1.1 refers to a dead (removed) revision in file `lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/QuestionReference.hbm.xml'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/model/QuestionReference.java'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java,v diff -u -r1.15.2.1.2.3 -r1.15.2.1.2.4 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java 13 Feb 2011 20:30:48 -0000 1.15.2.1.2.3 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/AssessmentServiceImpl.java 16 Sep 2011 16:59:54 -0000 1.15.2.1.2.4 @@ -87,6 +87,7 @@ import org.lamsfoundation.lams.tool.assessment.model.AssessmentSession; import org.lamsfoundation.lams.tool.assessment.model.AssessmentUnit; import org.lamsfoundation.lams.tool.assessment.model.AssessmentUser; +import org.lamsfoundation.lams.tool.assessment.model.QuestionReference; import org.lamsfoundation.lams.tool.assessment.util.AssessmentQuestionResultComparator; import org.lamsfoundation.lams.tool.assessment.util.AssessmentSessionComparator; import org.lamsfoundation.lams.tool.assessment.util.AssessmentToolContentHandler; @@ -295,6 +296,10 @@ public void deleteAssessmentQuestion(Long uid) { assessmentQuestionDao.removeObject(AssessmentQuestion.class, uid); } + + public void deleteQuestionReference(Long uid) { + assessmentQuestionDao.removeObject(QuestionReference.class, uid); + } public List getAssessmentQuestionsBySessionId(Long sessionId) { AssessmentSession session = assessmentSessionDao.getSessionBySessionId(sessionId); Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java,v diff -u -r1.10.2.1 -r1.10.2.1.2.1 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java 15 Jun 2009 00:42:50 -0000 1.10.2.1 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/service/IAssessmentService.java 16 Sep 2011 16:59:54 -0000 1.10.2.1.2.1 @@ -134,6 +134,8 @@ * @param uid */ void deleteAssessmentQuestion(Long uid); + + void deleteQuestionReference(Long uid); /** * Return all reource questions within the given toolSessionID. Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java,v diff -u -r1.16.6.3 -r1.16.6.4 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java 15 Dec 2010 17:30:31 -0000 1.16.6.3 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/AuthoringAction.java 16 Sep 2011 16:59:54 -0000 1.16.6.4 @@ -24,6 +24,10 @@ package org.lamsfoundation.lams.tool.assessment.web.action; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.sql.Timestamp; @@ -45,6 +49,9 @@ import javax.servlet.http.HttpSession; import org.apache.commons.beanutils.PropertyUtils; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.fileupload.DiskFileUpload; +import org.apache.commons.fileupload.FileItem; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; @@ -56,6 +63,7 @@ import org.apache.struts.upload.FormFile; import org.lamsfoundation.lams.authoring.web.AuthoringConstants; import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; +import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; import org.lamsfoundation.lams.tool.ToolAccessMode; import org.lamsfoundation.lams.tool.assessment.AssessmentConstants; import org.lamsfoundation.lams.tool.assessment.model.Assessment; @@ -65,13 +73,15 @@ import org.lamsfoundation.lams.tool.assessment.model.AssessmentQuestionOption; import org.lamsfoundation.lams.tool.assessment.model.AssessmentUnit; import org.lamsfoundation.lams.tool.assessment.model.AssessmentUser; +import org.lamsfoundation.lams.tool.assessment.model.QuestionReference; import org.lamsfoundation.lams.tool.assessment.service.AssessmentApplicationException; import org.lamsfoundation.lams.tool.assessment.service.IAssessmentService; import org.lamsfoundation.lams.tool.assessment.service.UploadAssessmentFileException; import org.lamsfoundation.lams.tool.assessment.util.SequencableComparator; import org.lamsfoundation.lams.tool.assessment.web.form.AssessmentForm; import org.lamsfoundation.lams.tool.assessment.web.form.AssessmentQuestionForm; import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.FileUtil; import org.lamsfoundation.lams.util.FileValidatorUtil; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.session.SessionManager; @@ -80,6 +90,8 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import com.thoughtworks.xstream.XStream; + /** * @author Andrey Balan */ @@ -149,7 +161,30 @@ } if (param.equals("downQuestion")) { return downQuestion(mapping, form, request, response); + } + // ----------------------- Question Reference functions --------------------------- + if (param.equals("addQuestionReference")) { + return addQuestionReference(mapping, form, request, response); + } + if (param.equals("removeQuestionReference")) { + return removeQuestionReference(mapping, form, request, response); + } + if (param.equals("upQuestionReference")) { + return upQuestionReference(mapping, form, request, response); + } + if (param.equals("downQuestionReference")) { + return downQuestionReference(mapping, form, request, response); } + // ----------------------- Import/Export Questions functions --------------------------- + if (param.equals("importInit")) { + return importInit(mapping, form, request, response); + } + if (param.equals("importQuestions")) { + return importQuestions(mapping, form, request, response); + } + if (param.equals("exportQuestions")) { + return exportQuestions(mapping, form, request, response); + } // -----------------------Assessment Answer Option functions --------------------------- if (param.equals("addOption")) { return addOption(mapping, form, request, response); @@ -177,8 +212,171 @@ return mapping.findForward(AssessmentConstants.ERROR); } + + /** + * + * + * @param mapping + * @param form + * @param request + * @param response + * @return + * @throws ServletException + */ + private ActionForward importInit(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws ServletException { + String sessionMapID = WebUtil.readStrParam(request, AssessmentConstants.ATTR_SESSION_MAP_ID); + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); + + return mapping.findForward(AssessmentConstants.SUCCESS); + } + + private ActionForward importQuestions(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws ServletException { + String sessionMapID = WebUtil.readStrParam(request, AssessmentConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); + AssessmentForm assessmentForm = (AssessmentForm) sessionMap.get(AssessmentConstants.ATTR_ASSESSMENT_FORM); + Set oldQuestions = getQuestionList(sessionMap); + + + List ldErrorMsgs = new ArrayList(); + List toolsErrorMsgs = new ArrayList(); + try { + File designFile = null; + Map params = new HashMap(); + String filename = null; + String uploadPath = FileUtil.createTempDirectory("_uploaded_2questions_xml"); + + DiskFileUpload fu = new DiskFileUpload(); + // maximum size that will be stored in memory + fu.setSizeThreshold(4096); + // the location for saving data that is larger than getSizeThreshold() + // fu.setRepositoryPath(uploadPath); + + List fileItems = fu.parseRequest(request); + Iterator iter = fileItems.iterator(); + while (iter.hasNext()) { + FileItem fi = (FileItem) iter.next(); + // UPLOAD_FILE is input field from HTML page + if (!fi.getFieldName().equalsIgnoreCase("UPLOAD_FILE")) + params.put(fi.getFieldName(), fi.getString()); + else { + // filename on the client + filename = FileUtil.getFileName(fi.getName()); + designFile = new File(uploadPath + filename); + fi.write(designFile); + } + } + + String filename2 = designFile.getName(); + String fileExtension = filename2 != null && filename2.length() >= 4 ? filename2 + .substring(filename2.length() - 4) : ""; + if (! fileExtension.equalsIgnoreCase(".xml")) { + throw new RuntimeException("Wrong file extension. Xml is expected"); + } + //String learningDesignPath = ZipFileUtil.expandZip(new FileInputStream(designFile), filename2); + + // import learning design + String fullFilePath = designFile.getAbsolutePath();//FileUtil.getFullPath(learningDesignPath, ExportToolContentService.LEARNING_DESIGN_FILE_NAME); + Set questions = (Set) FileUtil.getObjectFromXML(null, fullFilePath); + if (questions != null) { + oldQuestions.addAll(questions); + } + + } catch (Exception e) { + log.error("Error occured during import", e); + toolsErrorMsgs.add(e.getClass().getName() + " " + e.getMessage()); + } + + if (toolsErrorMsgs.size() > 0) { + request.setAttribute("toolsErrorMessages", toolsErrorMsgs); + } + + reinitializeAvailableQuestions(sessionMap); + + return mapping.findForward(AssessmentConstants.SUCCESS); + + } + /** + * Export Excel format survey data. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward exportQuestions(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + String sessionMapID = request.getParameter(AssessmentConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + AssessmentForm assessmentForm = (AssessmentForm) sessionMap.get(AssessmentConstants.ATTR_ASSESSMENT_FORM); + Assessment assessment = assessmentForm.getAssessment(); + + String errors = null; + if (assessment != null) { + try { + Set questions = assessment.getQuestions(); + // exporting XML + XStream designXml = new XStream(); + String resultedXml = designXml.toXML(questions); + + response.setContentType("application/x-download"); + response.setHeader("Content-Disposition", "attachment;filename=" + AssessmentConstants.EXPORT_QUESTIONS_FILENAME); + log.debug("Exporting assessment questions to an xml: " + assessment.getContentId()); + + + + OutputStream out = null; + try { + out = response.getOutputStream(); + out.write(resultedXml.getBytes()); + int count = resultedXml.getBytes().length; +// +// int ch; +// while ((ch = in.read()) != -1) { +// out.write((char) ch); +// count++; +// } + log.debug("Wrote out " + count + " bytes"); + response.setContentLength(count); + out.flush(); + } catch (Exception e) { + log.error("Exception occured writing out file:" + e.getMessage()); + throw new ExportToolContentException(e); + } finally { + try { + if (out != null) { + out.close(); + } + } catch (Exception e) { + log.error("Error Closing file. File already written out - no exception being thrown.", e); + } + } + + + } catch (Exception e) { + errors = "Unable to export tool content: " + e.toString(); + log.error(errors); + } + + } + if (errors != null) { + try { + PrintWriter out = response.getWriter(); + out.write(errors); + out.flush(); + } catch (IOException e) { + } + } + return null; + } + + /** * Read assessment data from database and put them into HttpSession. It will redirect to init.do directly after this * method run successfully. * @@ -256,10 +454,20 @@ questionList.clear(); questionList.addAll(questions); + // init question references + SortedSet references = getQuestionReferences(sessionMap); + references.clear(); + if (assessment.getQuestionReferences() != null) { + references.addAll(assessment.getQuestionReferences()); + } + + // init available questions + reinitializeAvailableQuestions(sessionMap); + sessionMap.put(AssessmentConstants.ATTR_ASSESSMENT_FORM, assessmentForm); return mapping.findForward(AssessmentConstants.SUCCESS); } - + /** * Display same entire authoring page content from HttpSession variable. * @@ -383,18 +591,19 @@ assessmentPO.setAttachments(attPOSet); // ************************* Handle assessment questions ******************* // Handle assessment questions - Set questionList = new LinkedHashSet(); + Set questions = new LinkedHashSet(); SortedSet topics = getQuestionList(sessionMap); iter = topics.iterator(); while (iter.hasNext()) { AssessmentQuestion question = (AssessmentQuestion) iter.next(); if (question != null) { // This flushs user UID info to message if this user is a new user. question.setCreateBy(assessmentUser); - questionList.add(question); + questions.add(question); } } - assessmentPO.setQuestions(questionList); + assessmentPO.setQuestions(questions); + // delete instructino file from database. List deletedQuestionList = getDeletedQuestionList(sessionMap); iter = deletedQuestionList.iterator(); @@ -404,6 +613,29 @@ if (question.getUid() != null) service.deleteAssessmentQuestion(question.getUid()); } + + // Handle question references + SortedSet questionReferences = getQuestionReferences(sessionMap); + for (QuestionReference questionReference : questionReferences) { + try { + int grade = (int) WebUtil.readLongParam(request, AssessmentConstants.PARAM_GRADE + questionReference.getSequenceId()); + questionReference.setDefaultGrade(grade); + } catch (Exception e) { + log.debug(e.getMessage()); + } + } + assessmentPO.setQuestionReferences(questionReferences); + + // delete instructino file from database. + List deletedReferences = getDeletedQuestionReferences(sessionMap); + iter = deletedReferences.iterator(); + while (iter.hasNext()) { + QuestionReference reference = (QuestionReference) iter.next(); + iter.remove(); + if (reference.getUid() != null) + service.deleteQuestionReference(reference.getUid()); + } + // handle assessment question attachment file: List delQuestionAttList = getDeletedQuestionAttachmentList(sessionMap); iter = delQuestionAttList.iterator(); @@ -693,6 +925,9 @@ AssessmentQuestionForm questionForm = (AssessmentQuestionForm) form; extractFormToAssessmentQuestion(request, questionForm); + + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(questionForm.getSessionMapID()); + reinitializeAvailableQuestions(sessionMap); // set session map ID so that questionlist.jsp can get sessionMAP request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, questionForm.getSessionMapID()); @@ -727,6 +962,8 @@ List delList = getDeletedQuestionList(sessionMap); delList.add(question); } + + reinitializeAvailableQuestions(sessionMap); request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); return mapping.findForward(AssessmentConstants.SUCCESS); @@ -784,12 +1021,161 @@ questionList.clear(); questionList.addAll(rList); } + + reinitializeAvailableQuestions(sessionMap); request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); return mapping.findForward(AssessmentConstants.SUCCESS); } /** + * Remove assessment question from HttpSession list and update page display. As authoring rule, all persist only happen + * when user submit whole page. So this remove is just impact HttpSession values. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward addQuestionReference(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, AssessmentConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + SortedSet references = getQuestionReferences(sessionMap); + int questionIdx = NumberUtils.stringToInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_INDEX), -1); + + //set SequenceId + QuestionReference reference = new QuestionReference(); + int maxSeq = 1; + if (references != null && references.size() > 0) { + QuestionReference last = references.last(); + maxSeq = last.getSequenceId() + 1; + } + reference.setSequenceId(maxSeq); + + //set isRandomQuestion + boolean isRandomQuestion = (questionIdx == -1); + reference.setRandomQuestion(isRandomQuestion); + + if (isRandomQuestion) { + reference.setDefaultGrade(1); + } else { + SortedSet questionList = getQuestionList(sessionMap); + AssessmentQuestion question = null; + for (AssessmentQuestion questionFromList : questionList) { + if (questionFromList.getSequenceId() == questionIdx) { + question = questionFromList; + break; + } + } + reference.setQuestion(question); + + reference.setDefaultGrade(question.getDefaultGrade()); + } + references.add(reference); + + reinitializeAvailableQuestions(sessionMap); + + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return mapping.findForward(AssessmentConstants.SUCCESS); + } + + /** + * Remove assessment question from HttpSession list and update page display. As authoring rule, all persist only happen + * when user submit whole page. So this remove is just impact HttpSession values. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward removeQuestionReference(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, AssessmentConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + int questionReferenceIdx = NumberUtils.stringToInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_REFERENCE_INDEX), -1); + if (questionReferenceIdx != -1) { + SortedSet questionReferences = getQuestionReferences(sessionMap); + List rList = new ArrayList(questionReferences); + QuestionReference questionReference = rList.remove(questionReferenceIdx); + questionReferences.clear(); + questionReferences.addAll(rList); + // add to delList + List delList = getDeletedQuestionReferences(sessionMap); + delList.add(questionReference); + } + + reinitializeAvailableQuestions(sessionMap); + + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return mapping.findForward(AssessmentConstants.SUCCESS); + } + + /** + * Move up current question. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward upQuestionReference(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + return switchQuestionReferences(mapping, request, true); + } + + /** + * Move down current question. + * + * @param mapping + * @param form + * @param request + * @param response + * @return + */ + private ActionForward downQuestionReference(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + return switchQuestionReferences(mapping, request, false); + } + + private ActionForward switchQuestionReferences(ActionMapping mapping, HttpServletRequest request, boolean up) { + // get back sessionMAP + String sessionMapID = WebUtil.readStrParam(request, AssessmentConstants.ATTR_SESSION_MAP_ID); + SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); + + int questionReferenceIdx = NumberUtils.stringToInt(request.getParameter(AssessmentConstants.PARAM_QUESTION_REFERENCE_INDEX), -1); + if (questionReferenceIdx != -1) { + SortedSet references = getQuestionReferences(sessionMap); + List rList = new ArrayList(references); + // get current and the target item, and switch their sequnece + QuestionReference reference = rList.get(questionReferenceIdx); + QuestionReference repReference; + if (up) + repReference = rList.get(--questionReferenceIdx); + else + repReference = rList.get(++questionReferenceIdx); + int upSeqId = repReference.getSequenceId(); + repReference.setSequenceId(reference.getSequenceId()); + reference.setSequenceId(upSeqId); + + // put back list, it will be sorted again + references.clear(); + references.addAll(rList); + } + + request.setAttribute(AssessmentConstants.ATTR_SESSION_MAP_ID, sessionMapID); + return mapping.findForward(AssessmentConstants.SUCCESS); + } + + /** * Ajax call, will add one more input line for new resource item instruction. * * @param mapping @@ -998,6 +1384,26 @@ // Private method // ************************************************************************************* /** + * refreshes set of all available questions for adding to question list + * + * @param sessionMap + */ + private void reinitializeAvailableQuestions(SessionMap sessionMap) { + SortedSet bankQuestions = getQuestionList(sessionMap); + SortedSet references = getQuestionReferences(sessionMap); + Set questionsFromList = new LinkedHashSet(); + for (QuestionReference reference : references) { + questionsFromList.add(reference.getQuestion()); + } + + Set availableQuestions = new TreeSet(new SequencableComparator()); + availableQuestions.addAll(CollectionUtils.subtract(bankQuestions, questionsFromList)); + + sessionMap.put(AssessmentConstants.ATTR_AVAILABLE_QUESTIONS, availableQuestions); + } + + + /** * Return AssessmentService bean. */ private IAssessmentService getAssessmentService() { @@ -1037,6 +1443,22 @@ } return list; } + + /** + * List save current question references. + * + * @param request + * @return + */ + private SortedSet getQuestionReferences(SessionMap sessionMap) { + SortedSet list = (SortedSet) sessionMap + .get(AssessmentConstants.ATTR_QUESTION_REFERENCES); + if (list == null) { + list = new TreeSet(new SequencableComparator()); + sessionMap.put(AssessmentConstants.ATTR_QUESTION_REFERENCES, list); + } + return list; + } /** * List save deleted assessment questions, which could be persisted or non-persisted questions. @@ -1047,6 +1469,16 @@ private List getDeletedQuestionList(SessionMap sessionMap) { return getListFromSession(sessionMap, AssessmentConstants.ATTR_DELETED_QUESTION_LIST); } + + /** + * List save deleted assessment questions, which could be persisted or non-persisted questions. + * + * @param request + * @return + */ + private List getDeletedQuestionReferences(SessionMap sessionMap) { + return getListFromSession(sessionMap, AssessmentConstants.ATTR_DELETED_QUESTION_REFERENCES); + } /** * If a assessment question has attahment file, and the user edit this question and change the attachment to new file, then Index: lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/LearningAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/LearningAction.java,v diff -u -r1.14.6.5 -r1.14.6.6 --- lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/LearningAction.java 13 Apr 2011 20:11:54 -0000 1.14.6.5 +++ lams_tool_assessment/src/java/org/lamsfoundation/lams/tool/assessment/web/action/LearningAction.java 16 Sep 2011 16:59:54 -0000 1.14.6.6 @@ -26,10 +26,12 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; +import java.util.Random; import java.util.Set; import java.util.TimeZone; import java.util.TreeSet; @@ -39,6 +41,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; @@ -58,6 +61,7 @@ import org.lamsfoundation.lams.tool.assessment.model.AssessmentResult; import org.lamsfoundation.lams.tool.assessment.model.AssessmentSession; import org.lamsfoundation.lams.tool.assessment.model.AssessmentUser; +import org.lamsfoundation.lams.tool.assessment.model.QuestionReference; import org.lamsfoundation.lams.tool.assessment.service.AssessmentApplicationException; import org.lamsfoundation.lams.tool.assessment.service.IAssessmentService; import org.lamsfoundation.lams.tool.assessment.util.SequencableComparator; @@ -145,8 +149,26 @@ assessmentUser = getCurrentUser(service, toolSessionId); } - List questionsFromDB = service.getAssessmentQuestionsBySessionId(toolSessionId); Assessment assessment = service.getAssessmentBySessionId(toolSessionId); + + //replacing random questions with real ones + Set questionReferences = assessment.getQuestionReferences(); + Set questionsFromDB = new LinkedHashSet(); + for (QuestionReference questionReference : questionReferences) { + if (!questionReference.isRandomQuestion()) { + questionsFromDB.add(questionReference.getQuestion()); + } + } + Set allQuestions = assessment.getQuestions(); + Collection availableQuestions = CollectionUtils.subtract(allQuestions, questionsFromDB); + for (QuestionReference questionReference : questionReferences) { + if (questionReference.isRandomQuestion()) { + //pick a random element + Random rand = new Random(System.currentTimeMillis()); + AssessmentQuestion question = (AssessmentQuestion) availableQuestions.toArray()[rand.nextInt(availableQuestions.size())]; + questionsFromDB.add(question); + } + } int dbResultCount = service.getAssessmentResultCount(assessment.getUid(), assessmentUser.getUserId()); int attemptsAllowed = assessment.getAttemptsAllowed(); Index: lams_tool_assessment/web/WEB-INF/tags/AuthoringButton.tag =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/web/WEB-INF/tags/AuthoringButton.tag,v diff -u -r1.4.6.1 -r1.4.6.2 --- lams_tool_assessment/web/WEB-INF/tags/AuthoringButton.tag 18 Mar 2010 12:14:55 -0000 1.4.6.1 +++ lams_tool_assessment/web/WEB-INF/tags/AuthoringButton.tag 16 Sep 2011 16:59:54 -0000 1.4.6.2 @@ -70,10 +70,13 @@ location.href=""; } function doSubmit_Form_Only() { - var length = $('#questionTable tr').size(); + var amountOfQuestions = $('#questionTable tr').size(); + var amountOfReferences = $('#referencesTable tr').size(); - if( length <= 1 ) { - alert("") + if( amountOfQuestions <= 1 ) { + alert(""); + } else if (amountOfReferences > amountOfQuestions) { + alert(""); } else { $("#overallFeedbackList").val($('#advancedInputArea').contents().find('#overallFeedbackForm').serialize(true)); document.getElementById("${formID}").submit(); Index: lams_tool_assessment/web/pages/authoring/basic.jsp =================================================================== RCS file: /usr/local/cvsroot/lams_tool_assessment/web/pages/authoring/basic.jsp,v diff -u -r1.6.8.2 -r1.6.8.3 --- lams_tool_assessment/web/pages/authoring/basic.jsp 15 Dec 2010 11:36:36 -0000 1.6.8.2 +++ lams_tool_assessment/web/pages/authoring/basic.jsp 16 Sep 2011 16:59:54 -0000 1.6.8.3 @@ -1,13 +1,14 @@ <%@ include file="/common/taglibs.jsp"%> + - +