Index: lams_central/src/java/org/lamsfoundation/lams/web/qb/QbCollectionController.java =================================================================== diff -u -r8b28898e77f3b0abafb08346c55fae0c590cad96 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_central/src/java/org/lamsfoundation/lams/web/qb/QbCollectionController.java (.../QbCollectionController.java) (revision 8b28898e77f3b0abafb08346c55fae0c590cad96) +++ lams_central/src/java/org/lamsfoundation/lams/web/qb/QbCollectionController.java (.../QbCollectionController.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -22,17 +22,11 @@ package org.lamsfoundation.lams.web.qb; -import java.io.StringWriter; import java.util.List; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; import org.apache.log4j.Logger; import org.lamsfoundation.lams.qb.model.QbCollection; @@ -41,6 +35,7 @@ import org.lamsfoundation.lams.usermanagement.dto.UserDTO; import org.lamsfoundation.lams.util.CommonConstants; import org.lamsfoundation.lams.util.MessageService; +import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.beans.factory.annotation.Autowired; @@ -82,39 +77,49 @@ @RequestMapping("/getCollectionGridData") @ResponseBody - public String getCollectionGridData(@RequestParam long collectionUid, HttpServletResponse response) { + public String getCollectionGridData(@RequestParam long collectionUid, HttpServletRequest request, + HttpServletResponse response) { response.setContentType("text/xml; charset=utf-8"); - List questions = qbService.getCollectionQuestions(collectionUid, 0, 10); - return QbCollectionController.toGridXML(questions); + int page = WebUtil.readIntParam(request, CommonConstants.PARAM_PAGE); + int rowLimit = WebUtil.readIntParam(request, CommonConstants.PARAM_ROWS); + String sortOrder = WebUtil.readStrParam(request, CommonConstants.PARAM_SORD); + String sortBy = WebUtil.readStrParam(request, CommonConstants.PARAM_SIDX, true); + Boolean isSearch = WebUtil.readBooleanParam(request, CommonConstants.PARAM_SEARCH); + String searchString = isSearch ? WebUtil.readStrParam(request, "name", true) : null; + + int offset = (page - 1) * rowLimit; + List questions = qbService.getCollectionQuestions(collectionUid, offset, rowLimit, sortBy, + sortOrder, searchString); + int total = qbService.countCollectionQuestions(collectionUid, searchString); + return QbCollectionController.toGridXML(questions, page, total); } - private static String toGridXML(List questions) { + private static String toGridXML(List questions, int page, int total) { try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document document = builder.newDocument(); + Document document = WebUtil.getDocument(); // root element Element rootElement = document.createElement(CommonConstants.ELEMENT_ROWS); Element pageElement = document.createElement(CommonConstants.ELEMENT_PAGE); - pageElement.appendChild(document.createTextNode("" + 1)); + pageElement.appendChild(document.createTextNode(String.valueOf(page))); rootElement.appendChild(pageElement); Element totalPageElement = document.createElement(CommonConstants.ELEMENT_TOTAL); - totalPageElement.appendChild(document.createTextNode("" + 1)); + totalPageElement.appendChild(document.createTextNode(String.valueOf(total))); rootElement.appendChild(totalPageElement); Element recordsElement = document.createElement(CommonConstants.ELEMENT_RECORDS); - recordsElement.appendChild(document.createTextNode("" + questions.size())); + recordsElement.appendChild(document.createTextNode(String.valueOf(questions.size()))); rootElement.appendChild(recordsElement); for (QbQuestion question : questions) { + String uid = question.getUid().toString(); Element rowElement = document.createElement(CommonConstants.ELEMENT_ROW); - rowElement.setAttribute(CommonConstants.ELEMENT_ID, question.getUid().toString()); + rowElement.setAttribute(CommonConstants.ELEMENT_ID, uid); - String[] data = { question.getUid().toString(), question.getName(), question.getUid().toString() }; + String[] data = { uid, question.getName(), uid }; for (String cell : data) { Element cellElement = document.createElement(CommonConstants.ELEMENT_CELL); @@ -128,14 +133,9 @@ } document.appendChild(rootElement); - DOMSource domSource = new DOMSource(document); - StringWriter writer = new StringWriter(); - StreamResult result = new StreamResult(writer); - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(); - transformer.transform(domSource, result); - return writer.toString(); + return WebUtil.getStringFromDocument(document); + } catch (Exception e) { log.error("Error while generating Question Bank collection jqGrid XML data", e); } Index: lams_central/web/qb/collection.jsp =================================================================== diff -u -r8b28898e77f3b0abafb08346c55fae0c590cad96 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_central/web/qb/collection.jsp (.../collection.jsp) (revision 8b28898e77f3b0abafb08346c55fae0c590cad96) +++ lams_central/web/qb/collection.jsp (.../collection.jsp) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -34,7 +34,7 @@ autowidth:true, shrinkToFit: true, cellEdit: false, - cmTemplate: { title: false }, + cmTemplate: { title: false, search: false }, viewrecords: true, sortorder: "asc", sortname: "name", @@ -47,9 +47,9 @@ "Stats" ], colModel:[ - {name:'id', index:'id', sortable:true, search:false, width: 10}, - {name:'name',index:'name', sortable:true, autoencode:true}, - {name:'stats', index:'stats', sortable:false, search:false, width: 10, align: "center", formatter: statsLinkFormatter} + {name:'id', index:'id', sortable:true, width: 10}, + {name:'name',index:'name', sortable:true, search:true, autoencode:true}, + {name:'stats', index:'stats', sortable:false, width: 10, align: "center", formatter: statsLinkFormatter} ], loadError: function(xhr,st,err) { collectionGrid.clearGridData(); Index: lams_common/src/java/org/lamsfoundation/lams/qb/dao/IQbDAO.java =================================================================== diff -u -re08a9e538cf4c89f50fd15cdabfa0319076c2692 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_common/src/java/org/lamsfoundation/lams/qb/dao/IQbDAO.java (.../IQbDAO.java) (revision e08a9e538cf4c89f50fd15cdabfa0319076c2692) +++ lams_common/src/java/org/lamsfoundation/lams/qb/dao/IQbDAO.java (.../IQbDAO.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -42,8 +42,13 @@ int getCountQbQuestions(Integer questionType, String searchString); - List getCollectionQuestions(long collectionUid, Integer offset, Integer limit); + List getCollectionQuestions(long collectionUid); + List getCollectionQuestions(long collectionUid, Integer offset, Integer limit, String orderBy, + String orderDirection, String search); + + int countCollectionQuestions(long collectionUid, String search); + void addCollectionQuestion(long collectionUid, long qbQuestionUid); void removeCollectionQuestion(long collectionUid, long qbQuestionUid); Index: lams_common/src/java/org/lamsfoundation/lams/qb/dao/hibernate/QbDAO.java =================================================================== diff -u -r8b28898e77f3b0abafb08346c55fae0c590cad96 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_common/src/java/org/lamsfoundation/lams/qb/dao/hibernate/QbDAO.java (.../QbDAO.java) (revision 8b28898e77f3b0abafb08346c55fae0c590cad96) +++ lams_common/src/java/org/lamsfoundation/lams/qb/dao/hibernate/QbDAO.java (.../QbDAO.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -6,8 +6,10 @@ import java.util.List; import java.util.Map; +import javax.persistence.Query; + +import org.apache.commons.lang.StringUtils; import org.hibernate.query.NativeQuery; -import org.hibernate.query.Query; import org.lamsfoundation.lams.dao.hibernate.LAMSBaseDAO; import org.lamsfoundation.lams.learningdesign.ToolActivity; import org.lamsfoundation.lams.qb.dao.IQbDAO; @@ -58,14 +60,15 @@ return (QbQuestion) this.find(QbQuestion.class, qbQuestionUid); } + @SuppressWarnings("unchecked") @Override public List getQbQuestionsByQuestionId(Integer questionId) { final String FIND_QUESTIONS_BY_QUESTION_ID = "FROM " + QbQuestion.class.getName() + " WHERE questionId = :questionId AND local = 0 ORDER BY version ASC"; - Query q = getSession().createQuery(FIND_QUESTIONS_BY_QUESTION_ID, QbQuestion.class); + Query q = getSession().createQuery(FIND_QUESTIONS_BY_QUESTION_ID, QbQuestion.class); q.setParameter("questionId", questionId); - return q.list(); + return q.getResultList(); } @Override @@ -187,12 +190,12 @@ + " OR question.name LIKE CONCAT('%', :searchString, '%') " + " OR REGEXP_REPLACE(qboption.name, '<[^>]*>+', '') LIKE CONCAT('%', :searchString, '%')) "; - Query query = getSession().createNativeQuery(SELECT_QUESTIONS); + Query query = getSession().createNativeQuery(SELECT_QUESTIONS, Integer.class); query.setParameter("questionType", questionType); // support for custom search from a toolbar searchString = searchString == null ? "" : searchString; query.setParameter("searchString", searchString); - int result = ((Number) query.uniqueResult()).intValue(); + int result = (int) query.getSingleResult(); return result; } @@ -221,19 +224,31 @@ } @Override - public List getCollectionQuestions(long collectionUid, Integer offset, Integer limit) { - Query query = getSession().createNativeQuery(FIND_COLLECTION_QUESTIONS, QbQuestion.class); - query.setParameter("collectionUid", collectionUid); + public List getCollectionQuestions(long collectionUid) { + return getCollectionQuestions(collectionUid, null, null, null, null, null); + } + + @SuppressWarnings("unchecked") + @Override + public List getCollectionQuestions(long collectionUid, Integer offset, Integer limit, String orderBy, + String orderDirection, String search) { + Query query = prepareCollectionQuestionsQuery(collectionUid, orderBy, orderDirection, search, false); if (offset != null) { query.setFirstResult(offset); } if (limit != null) { query.setMaxResults(limit); } - return query.list(); + return query.getResultList(); } @Override + public int countCollectionQuestions(long collectionUid, String search) { + Query query = prepareCollectionQuestionsQuery(collectionUid, null, null, search, true); + return ((BigInteger) query.getSingleResult()).intValue(); + } + + @Override public void addCollectionQuestion(long collectionUid, long qbQuestionUid) { getSession().createNativeQuery(ADD_COLLECTION_QUESTION).setParameter("collectionUid", collectionUid) .setParameter("qbQuestionUid", qbQuestionUid).executeUpdate(); @@ -244,4 +259,34 @@ getSession().createNativeQuery(REMOVE_COLLECTION_QUESTION).setParameter("collectionUid", collectionUid) .setParameter("qbQuestionUid", qbQuestionUid).executeUpdate(); } + + private Query prepareCollectionQuestionsQuery(long collectionUid, String orderBy, String orderDirection, + String search, boolean isCount) { + StringBuilder queryBuilder = new StringBuilder(FIND_COLLECTION_QUESTIONS); + + if (StringUtils.isNotBlank(search)) { + queryBuilder.append(" AND (q.name LIKE :search OR q.description LIKE :search)"); + } + + if (!isCount && StringUtils.isNotBlank(orderBy)) { + queryBuilder.append(" ORDER BY ").append(orderBy); + if (StringUtils.isNotBlank(orderDirection)) { + queryBuilder.append(" ").append(orderDirection); + } + } + + String queryText = queryBuilder.toString(); + if (isCount) { + queryText = queryText.replace("q.*", "COUNT(*)"); + } + + Query query = isCount ? getSession().createNativeQuery(queryText) + : getSession().createNativeQuery(queryText, QbQuestion.class); + query.setParameter("collectionUid", collectionUid); + if (StringUtils.isNotBlank(search)) { + query.setParameter("search", "%" + search.trim() + "%"); + } + + return query; + } } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/qb/service/IQbService.java =================================================================== diff -u -r8b28898e77f3b0abafb08346c55fae0c590cad96 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_common/src/java/org/lamsfoundation/lams/qb/service/IQbService.java (.../IQbService.java) (revision 8b28898e77f3b0abafb08346c55fae0c590cad96) +++ lams_common/src/java/org/lamsfoundation/lams/qb/service/IQbService.java (.../IQbService.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -59,8 +59,13 @@ List getUserCollections(int userId); - List getCollectionQuestions(long collectionUid, Integer offset, Integer limit); + List getCollectionQuestions(long collectionUid); + List getCollectionQuestions(long collectionUid, Integer offset, Integer limit, String orderBy, + String orderDirection, String search); + + int countCollectionQuestions(long collectionUid, String search); + QbCollection addCollection(int userId, String name); void removeCollection(long collectionUid); Index: lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java =================================================================== diff -u -r8b28898e77f3b0abafb08346c55fae0c590cad96 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java (.../QbService.java) (revision 8b28898e77f3b0abafb08346c55fae0c590cad96) +++ lams_common/src/java/org/lamsfoundation/lams/qb/service/QbService.java (.../QbService.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -271,11 +271,22 @@ } @Override - public List getCollectionQuestions(long collectionUid, Integer offset, Integer limit) { - return qbDAO.getCollectionQuestions(collectionUid, offset, limit); + public List getCollectionQuestions(long collectionUid) { + return qbDAO.getCollectionQuestions(collectionUid); } @Override + public List getCollectionQuestions(long collectionUid, Integer offset, Integer limit, String orderBy, + String orderDirection, String search) { + return qbDAO.getCollectionQuestions(collectionUid, offset, limit, orderBy, orderDirection, search); + } + + @Override + public int countCollectionQuestions(long collectionUid, String search) { + return qbDAO.countCollectionQuestions(collectionUid, search); + } + + @Override public QbCollection addCollection(int userId, String name) { QbCollection collection = new QbCollection(); collection.setName(name); Index: lams_common/src/java/org/lamsfoundation/lams/util/CommonConstants.java =================================================================== diff -u -r8236da64800893104429c9b88f89d500c505a9a1 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_common/src/java/org/lamsfoundation/lams/util/CommonConstants.java (.../CommonConstants.java) (revision 8236da64800893104429c9b88f89d500c505a9a1) +++ lams_common/src/java/org/lamsfoundation/lams/util/CommonConstants.java (.../CommonConstants.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -1,63 +1,68 @@ -package org.lamsfoundation.lams.util; - -public class CommonConstants { - - // params passed from the jqGrid - public static final String PARAM_PAGE = "page"; - public static final String PARAM_ROWS = "rows"; - public static final String PARAM_SIDX = "sidx"; - public static final String PARAM_SORD = "sord"; - - // default coordinate used if the entry came from Flash is 0 or less. - public static final Integer DEFAULT_COORD = new Integer(10); - - // XML Elemetns - public static final String ELEMENT_ROWS = "rows"; - public static final String ELEMENT_PAGE = "page"; - public static final String ELEMENT_TOTAL = "total"; - public static final String ELEMENT_RECORDS = "records"; - public static final String ELEMENT_ROW = "row"; - public static final String ELEMENT_ID = "id"; - public static final String ELEMENT_CELL = "cell"; - - public static final String PARAM_LEARNING_DESIGN_ID = "ldId"; - public static final String PARAM_USE_PREFIX = "usePrefix"; - public static final String PARAM_MODE = "mode"; - - public static int PORTRAIT_LARGEST_DIMENSION_LARGE = 200; - public static int PORTRAIT_LARGEST_DIMENSION_MEDIUM = 80; - public static int PORTRAIT_LARGEST_DIMENSION_SMALL = 35; - - //used by all tool authoring action class to mark the success flag. - public static final String LAMS_AUTHORING_SUCCESS_FLAG = "LAMS_AUTHORING_SUCCESS_FLAG"; - - // used for tool content folder creation. - public static final String LAMS_WWW_FOLDER = "www/"; - - public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; - public static final String RESPONSE_CONTENT_TYPE_DOWNLOAD = "application/x-download"; - public static final String HEADER_CONTENT_ATTACHMENT = "attachment;filename="; - - public static final String TOOL_SIGNATURE_ASSESSMENT = "laasse10"; - public static final String TOOL_SIGNATURE_FORUM = "lafrum11"; - public static final String TOOL_SIGNATURE_LEADERSELECTION = "lalead11"; - public static final String TOOL_SIGNATURE_MCQ = "lamc11"; - public static final String TOOL_SIGNATURE_SCRATCHIE = "lascrt11"; - public static final String TOOL_SIGNATURE_PEER_REVIEW = "laprev11"; - - public static final String[] COUNTRY_CODES = { "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", - "AT", "AU", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", - "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", - "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU", "CV", "CX", "CW", "CY", "CZ", - "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", - "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", - "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", - "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", - "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", - "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", - "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", - "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SX", "SH", - "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", - "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", - "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW" }; -} +package org.lamsfoundation.lams.util; + +public class CommonConstants { + + // params passed from the jqGrid + public static final String PARAM_PAGE = "page"; + public static final String PARAM_ROWS = "rows"; + public static final String PARAM_SIDX = "sidx"; + public static final String PARAM_SORD = "sord"; + + public static final String PARAM_SEARCH = "_search"; + public static final String PARAM_SEARCH_FIELD = "searchField"; + public static final String PARAM_SEARCH_OPERATION = "searchOper"; + public static final String PARAM_SEARCH_STRING = "searchString"; + + // default coordinate used if the entry came from Flash is 0 or less. + public static final Integer DEFAULT_COORD = new Integer(10); + + // XML Elemetns + public static final String ELEMENT_ROWS = "rows"; + public static final String ELEMENT_PAGE = "page"; + public static final String ELEMENT_TOTAL = "total"; + public static final String ELEMENT_RECORDS = "records"; + public static final String ELEMENT_ROW = "row"; + public static final String ELEMENT_ID = "id"; + public static final String ELEMENT_CELL = "cell"; + + public static final String PARAM_LEARNING_DESIGN_ID = "ldId"; + public static final String PARAM_USE_PREFIX = "usePrefix"; + public static final String PARAM_MODE = "mode"; + + public static int PORTRAIT_LARGEST_DIMENSION_LARGE = 200; + public static int PORTRAIT_LARGEST_DIMENSION_MEDIUM = 80; + public static int PORTRAIT_LARGEST_DIMENSION_SMALL = 35; + + //used by all tool authoring action class to mark the success flag. + public static final String LAMS_AUTHORING_SUCCESS_FLAG = "LAMS_AUTHORING_SUCCESS_FLAG"; + + // used for tool content folder creation. + public static final String LAMS_WWW_FOLDER = "www/"; + + public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition"; + public static final String RESPONSE_CONTENT_TYPE_DOWNLOAD = "application/x-download"; + public static final String HEADER_CONTENT_ATTACHMENT = "attachment;filename="; + + public static final String TOOL_SIGNATURE_ASSESSMENT = "laasse10"; + public static final String TOOL_SIGNATURE_FORUM = "lafrum11"; + public static final String TOOL_SIGNATURE_LEADERSELECTION = "lalead11"; + public static final String TOOL_SIGNATURE_MCQ = "lamc11"; + public static final String TOOL_SIGNATURE_SCRATCHIE = "lascrt11"; + public static final String TOOL_SIGNATURE_PEER_REVIEW = "laprev11"; + + public static final String[] COUNTRY_CODES = { "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", + "AT", "AU", "AI", "AL", "AM", "AO", "AQ", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB", "BD", "BE", + "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", + "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU", "CV", "CX", "CW", "CY", "CZ", + "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", + "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT", "GU", + "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR", "IS", "IT", + "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", + "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK", "ML", "MM", + "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", + "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", + "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SX", "SH", + "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SY", "SZ", "TC", "TD", "TF", "TG", "TH", + "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", + "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "YE", "YT", "ZA", "ZM", "ZW" }; +} Index: lams_common/src/java/org/lamsfoundation/lams/util/WebUtil.java =================================================================== diff -u -rbe74862925361d836bef1df4c5959105c9695a87 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_common/src/java/org/lamsfoundation/lams/util/WebUtil.java (.../WebUtil.java) (revision be74862925361d836bef1df4c5959105c9695a87) +++ lams_common/src/java/org/lamsfoundation/lams/util/WebUtil.java (.../WebUtil.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -1,513 +1,539 @@ -package org.lamsfoundation.lams.util; - -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.security.Principal; -import java.util.HashMap; -import java.util.Map.Entry; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; -import org.lamsfoundation.lams.tool.ToolAccessMode; -import org.lamsfoundation.lams.tool.exception.ToolException; -import org.lamsfoundation.lams.usermanagement.User; -import org.lamsfoundation.lams.web.util.AttributeNames; - -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; - -/** - * helper methods useful for servlets - */ -public class WebUtil { - - // --------------------------------------------------------------------- - // Class level constants - Session attributs - // --------------------------------------------------------------------- - - private static Logger log = Logger.getLogger(WebUtil.class); - /** - * A regular expression pattern that matches HTML tags. - */ - private static final String HTML_TAG_REGEX = "\\<.*?>"; - /** - * A regular expression pattern that matches end-of-line and space tags. If needed, BR tags can be extented to - * (?:
|
|
|
)
. Right now CKeditor creates only the first option. - */ - private static final String SPACE_TAG_REGEX = "(?:
)|(?: )|(?:
)"; - - private static final String URL_SHORTENING_CYPHER = "jbdnuteywk"; - - /** - * @exception IllegalArgumentException - * - if not set - */ - private static void checkObject(String paramName, Object paramValue) throws IllegalArgumentException { - boolean isNull = paramValue == null; - if (!isNull && String.class.isInstance(paramValue)) { - String str = (String) paramValue; - isNull = str.trim().length() == 0; - } - if (isNull) { - throw new IllegalArgumentException(paramName + " is required '" + paramValue + "'"); - } - } - - /** - * @return integer value of paramValue - * @exception IllegalArgumentException - * - if (a) not set and is not optional or (b) not integer - */ - public static Integer checkInteger(String paramName, String paramValue, boolean isOptional) - throws IllegalArgumentException { - try { - if (!isOptional) { - WebUtil.checkObject(paramName, paramValue); - } - String value = paramValue != null ? StringUtils.trimToNull(paramValue) : null; - return value != null ? Integer.valueOf(value) : null; - - } catch (NumberFormatException e) { - throw new IllegalArgumentException(paramName + " should be an integer '" + paramValue + "'"); - } - } - - /** - * @return long value of paramValue - * @exception IllegalArgumentException - * - if (a) not set and is not optional or (b) not long - */ - public static Long checkLong(String paramName, String paramValue, boolean isOptional) - throws IllegalArgumentException { - try { - if (!isOptional) { - WebUtil.checkObject(paramName, paramValue); - } - String value = paramValue != null ? StringUtils.trimToNull(paramValue) : null; - return value != null ? Long.valueOf(value) : null; - - } catch (NumberFormatException e) { - throw new IllegalArgumentException(paramName + " should be a long '" + paramValue + "'"); - } - } - - /** - * Get a long version of paramValue, throwing an IllegalArgumentException if isOptional = false and the is value is - * null - * - * @return long value of paramValue - * @exception IllegalArgumentException - * - if not set or not long - */ - public static long checkLong(String paramName, Long paramValue, boolean isOptional) - throws IllegalArgumentException { - if (!isOptional) { - WebUtil.checkObject(paramName, paramValue); - } - return paramValue.longValue(); - } - - /** - * @return boolean value of paramValue - * @exception IllegalArgumentException - * - if not set or not boolean - */ - public static boolean checkBoolean(String paramName, String paramValue) throws IllegalArgumentException { - WebUtil.checkObject(paramName, paramValue); - return Boolean.valueOf(paramValue.trim()).booleanValue(); - } - - /** - * Read an int parameter, throwing exception if null or not a integer - * - * @param req - * - - * @param paramName - * - - * @return parameter value - */ - public static int readIntParam(HttpServletRequest req, String paramName) { - return WebUtil.checkInteger(paramName, req.getParameter(paramName), false).intValue(); - } - - /** - * Read an int parameter, throwing exception if ( not optional and null ) or not a integer - * - * @param req - * - - * @param paramName - * - - * @param isOptional - * @return parameter value - */ - public static Integer readIntParam(HttpServletRequest req, String paramName, boolean isOptional) { - return WebUtil.checkInteger(paramName, req.getParameter(paramName), isOptional); - } - - /** - * Read an long parameter, throwing exception if null or not a long - * - * @param req - * - - * @param paramName - * - - * @return parameter value - */ - public static long readLongParam(HttpServletRequest req, String paramName) { - return WebUtil.checkLong(paramName, req.getParameter(paramName), false).longValue(); - } - - /** - * Read an long parameter, throwing exception if ( not optional and null ) or not a long - * - * @param req - * - - * @param paramName - * - - * @param isOptional - * @return parameter value - */ - public static Long readLongParam(HttpServletRequest req, String paramName, boolean isOptional) { - return WebUtil.checkLong(paramName, req.getParameter(paramName), isOptional); - } - - /** - * @param req - * - - * @param paramName - * - - * @return parameter value - */ - public static String readStrParam(HttpServletRequest req, String paramName) { - return WebUtil.readStrParam(req, paramName, false); - } - - /** - * @param req - * - - * @param paramName - * - - * @param isOptional - * @return parameter value - */ - public static String readStrParam(HttpServletRequest req, String paramName, boolean isOptional) { - if (!isOptional) { - WebUtil.checkObject(paramName, req.getParameter(paramName)); - } - return req.getParameter(paramName); - } - - /** - * @param req - * - - * @param paramName - * - - * @return parameter value - * @exception IllegalArgumentException - * - if valid boolean parameter value is not found - */ - public static boolean readBooleanParam(HttpServletRequest req, String paramName) throws IllegalArgumentException { - return WebUtil.checkBoolean(paramName, req.getParameter(paramName)); - } - - /** - * @param req - * - - * @param paramName - * - - * @param defaultValue - * - if valid boolean parameter value is not found, return this value - * @return parameter value - */ - public static boolean readBooleanParam(HttpServletRequest req, String paramName, boolean defaultValue) { - try { - return WebUtil.checkBoolean(paramName, req.getParameter(paramName)); - } catch (IllegalArgumentException e) { - return defaultValue; - } - } - - public static boolean readBooleanAttr(HttpServletRequest req, String attrName) { - return WebUtil.checkBoolean(attrName, (String) req.getSession().getAttribute(attrName)); - } - - /** - * Retrieve the tool access mode from http request. This is a utility used by the tools that share an implementation - * for the learner screen. They use mode=learner, mode=author and mode=teacher for learning, preview and monitoring - * respectively. Only used if the tool programmer wants to have one call that supports all three ways of looking at - * a learner screen. - * - * @param request - * @param param_mode - * @return the ToolAccessMode object - */ - public static ToolAccessMode readToolAccessModeParam(HttpServletRequest request, String param_mode, - boolean optional) { - String mode = WebUtil.readStrParam(request, param_mode, optional); - if (mode == null) { - return null; - } else if (mode.equals(ToolAccessMode.AUTHOR.toString())) { - return ToolAccessMode.AUTHOR; - } else if (mode.equals(ToolAccessMode.LEARNER.toString())) { - return ToolAccessMode.LEARNER; - } else if (mode.equals(ToolAccessMode.TEACHER.toString())) { - return ToolAccessMode.TEACHER; - } else { - throw new IllegalArgumentException("[" + mode + "] is not a legal mode" + "in LAMS"); - } - } - - /** - * Retrieve the tool access mode from a string value, presumably from a Form. This is a utility used by the tools - * that share an implementation for the learner screen. They use mode=learner, mode=author and mode=teacher for - * learning, preview and monitoring respectively. Only used if the tool programmer wants to have one call that - * supports all three ways of looking at a learner screen. - * - * @param request - * @return the ToolAccessMode object - */ - public static ToolAccessMode getToolAccessMode(String modeValue) { - if (modeValue != null) { - if (modeValue.equals(ToolAccessMode.AUTHOR.toString())) { - return ToolAccessMode.AUTHOR; - } else if (modeValue.equals(ToolAccessMode.LEARNER.toString())) { - return ToolAccessMode.LEARNER; - } else if (modeValue.equals(ToolAccessMode.TEACHER.toString())) { - return ToolAccessMode.TEACHER; - } - } - throw new IllegalArgumentException("[" + modeValue + "] is not a legal mode" + "in LAMS"); - } - - /** - * Get ToolAccessMode from HttpRequest parameters. Default value is AUTHOR mode. - * - * @param request - * @return - */ - public static ToolAccessMode readToolAccessModeAuthorDefaulted(HttpServletRequest request) { - String modeStr = request.getParameter(AttributeNames.ATTR_MODE); - - ToolAccessMode mode; - if (StringUtils.equalsIgnoreCase(modeStr, ToolAccessMode.TEACHER.toString())) { - mode = ToolAccessMode.TEACHER; - } else { - mode = ToolAccessMode.AUTHOR; - } - return mode; - } - - /** - * Append a parameter to a requested url. - * - * @param parameterName - * the name of the parameter - * @param parameterValue - * the value of the parameter - * @param learnerUrl - * the target url - * @return the url with parameter appended. - */ - public static String appendParameterToURL(String url, String parameterName, String parameterValue) { - return WebUtil.appendParameterDeliminator(url) + parameterName + "=" + parameterValue; - } - - /** - *

- * This helper append the parameter deliminator for a url. - *

- * It is using a null safe String util method to checkup the url String and append proper deliminator if necessary. - * - * @param url - * the url needs to append deliminator. - * @return target url with the deliminator; - */ - public static String appendParameterDeliminator(String url) { - if (url == null) { - return null; - } else if (StringUtils.containsNone(url, "?")) { - return url + "?"; - } else { - return url + "&"; - } - } - - /** - * Converts a url (such as one from a tool) to a complete url. If the url starts with "http" then it is assumed to - * be a complete url and is returned as is. Otherwise it assumes starts with the path of the webapp so it is - * appended to the server url from the LAMS Configuration. - * - * @param url - * e.g. tool/lanb11/starter/learner.do - * @return complete url - */ - public static String convertToFullURL(String url) { - if (url == null) { - return null; - } else if (url.startsWith("http")) { - return url; - } else { - String serverURL = Configuration.get(ConfigurationKeys.SERVER_URL); - if (url.charAt(0) == '/') { - return serverURL + url; - } else { - return serverURL + '/' + url; - } - } - } - - /** - * Convert any newslines in a string to
- * . If input = null, returns null. - */ - public static String convertNewlines(String input) { - if (input != null) { - return input.replaceAll("[\n\r\f]", "
"); - } else { - return null; - } - } - - /** - * Strips HTML tags and leave "pure" text. Useful for CKeditor created text. - * - * @param text - * string to process - * @return string after stripping - */ - public static String removeHTMLtags(String text) { - return text == null ? null - : text.replaceAll(WebUtil.SPACE_TAG_REGEX, " ").replaceAll(WebUtil.HTML_TAG_REGEX, ""); - } - - /** - * Makes a request to the specified url with the specified parameters and returns the response inputstream - * - * @param urlStr - * @param params - * @return - * @throws ToolException - * @throws IOException - */ - public static InputStream getResponseInputStreamFromExternalServer(String urlStr, HashMap params) - throws Exception { - if (!urlStr.contains("?")) { - urlStr += "?"; - } - - for (Entry entry : params.entrySet()) { - urlStr += "&" + entry.getKey() + "=" + entry.getValue(); - } - - WebUtil.log.info("Making request to external servlet: " + urlStr); - - URL url = new URL(urlStr); - URLConnection conn = url.openConnection(); - if (!(conn instanceof HttpURLConnection)) { - WebUtil.log.error("Fail to connect to external server though url: " + urlStr); - throw new Exception("Fail to connect to external server though url: " + urlStr); - } - - HttpURLConnection httpConn = (HttpURLConnection) conn; - if (httpConn.getResponseCode() != HttpURLConnection.HTTP_OK) { - WebUtil.log.error("Response code from external server: " + httpConn.getResponseCode() + " Url: " + urlStr); - } - - InputStream is = url.openConnection().getInputStream(); - if (is == null) { - WebUtil.log.error("Fail to fetch data from external server, return InputStream null: " + urlStr); - throw new Exception("Fail to fetch data from external server, return inputStream null: " + urlStr); - } - - return is; - } - - public static String extractParameterValue(String url, String param) { - if (!StringUtils.isBlank(url) && !StringUtils.isBlank(param)) { - int quotationMarkIndex = url.indexOf("?"); - String queryPart = quotationMarkIndex > -1 ? url.substring(quotationMarkIndex + 1) : url; - String[] paramEntries = queryPart.split("&"); - for (String paramEntry : paramEntries) { - String[] paramEntrySplitted = paramEntry.split("="); - if ((paramEntrySplitted.length > 1) && param.equalsIgnoreCase(paramEntrySplitted[0])) { - return paramEntrySplitted[1]; - } - } - } - return null; - } - - /** - * Produces JSON object with basic user details. - */ - public static ObjectNode userToJSON(User user) { - ObjectNode userJSON = JsonNodeFactory.instance.objectNode(); - userJSON.put("id", user.getUserId()); - userJSON.put("firstName", user.getFirstName()); - userJSON.put("lastName", user.getLastName()); - userJSON.put("login", user.getLogin()); - userJSON.put("portraitId", user.getPortraitUuid()); - return userJSON; - } - - public static String getBaseServerURL() { - String serverURL = Configuration.get(ConfigurationKeys.SERVER_URL); - // "https://" is 8 characters, so next "/" should be context - return serverURL.substring(0, serverURL.indexOf('/', 9)); - } - - /** - * Converse lessonId into alphabetic sequence for using it in URL shortening - * - * @param lessonId - * @return - */ - public static String encodeLessonId(Long lessonId) { - String encodedLessonId = lessonId.toString(); - encodedLessonId = encodedLessonId.replace('0', URL_SHORTENING_CYPHER.charAt(0)); - encodedLessonId = encodedLessonId.replace('1', URL_SHORTENING_CYPHER.charAt(1)); - encodedLessonId = encodedLessonId.replace('2', URL_SHORTENING_CYPHER.charAt(2)); - encodedLessonId = encodedLessonId.replace('3', URL_SHORTENING_CYPHER.charAt(3)); - encodedLessonId = encodedLessonId.replace('4', URL_SHORTENING_CYPHER.charAt(4)); - encodedLessonId = encodedLessonId.replace('5', URL_SHORTENING_CYPHER.charAt(5)); - encodedLessonId = encodedLessonId.replace('6', URL_SHORTENING_CYPHER.charAt(6)); - encodedLessonId = encodedLessonId.replace('7', URL_SHORTENING_CYPHER.charAt(7)); - encodedLessonId = encodedLessonId.replace('8', URL_SHORTENING_CYPHER.charAt(8)); - encodedLessonId = encodedLessonId.replace('9', URL_SHORTENING_CYPHER.charAt(9)); - - return encodedLessonId; - } - - /** - * Decodes alphabetic sequence (that is lessonId encoded for URL shortening purposes) - * - * @param encodedlessonId - * @return - */ - public static String decodeLessonId(String encodedLessonId) throws IllegalArgumentException { - - // it should contain only the characters from URL_SHORTENING_CYPHER - if (!encodedLessonId.matches("[" + URL_SHORTENING_CYPHER + "]*")) { - throw new IllegalArgumentException("LessonId: " + encodedLessonId + " has wrong format."); - } - - String decodedLessonId = encodedLessonId; - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(0), '0'); - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(1), '1'); - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(2), '2'); - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(3), '3'); - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(4), '4'); - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(5), '5'); - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(6), '6'); - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(7), '7'); - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(8), '8'); - decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(9), '9'); - - return decodedLessonId; - } +package org.lamsfoundation.lams.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.Map.Entry; + +import javax.servlet.http.HttpServletRequest; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.tool.ToolAccessMode; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.w3c.dom.Document; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * helper methods useful for servlets + */ +public class WebUtil { + + // --------------------------------------------------------------------- + // Class level constants - Session attributs + // --------------------------------------------------------------------- + + private static Logger log = Logger.getLogger(WebUtil.class); + /** + * A regular expression pattern that matches HTML tags. + */ + private static final String HTML_TAG_REGEX = "\\<.*?>"; + /** + * A regular expression pattern that matches end-of-line and space tags. If needed, BR tags can be extented to + * (?:
|
|
|
)
. Right now CKeditor creates only the first option. + */ + private static final String SPACE_TAG_REGEX = "(?:
)|(?: )|(?:
)"; + + private static final String URL_SHORTENING_CYPHER = "jbdnuteywk"; + + /** + * @exception IllegalArgumentException + * - if not set + */ + private static void checkObject(String paramName, Object paramValue) throws IllegalArgumentException { + boolean isNull = paramValue == null; + if (!isNull && String.class.isInstance(paramValue)) { + String str = (String) paramValue; + isNull = str.trim().length() == 0; + } + if (isNull) { + throw new IllegalArgumentException(paramName + " is required '" + paramValue + "'"); + } + } + + /** + * @return integer value of paramValue + * @exception IllegalArgumentException + * - if (a) not set and is not optional or (b) not integer + */ + public static Integer checkInteger(String paramName, String paramValue, boolean isOptional) + throws IllegalArgumentException { + try { + if (!isOptional) { + WebUtil.checkObject(paramName, paramValue); + } + String value = paramValue != null ? StringUtils.trimToNull(paramValue) : null; + return value != null ? Integer.valueOf(value) : null; + + } catch (NumberFormatException e) { + throw new IllegalArgumentException(paramName + " should be an integer '" + paramValue + "'"); + } + } + + /** + * @return long value of paramValue + * @exception IllegalArgumentException + * - if (a) not set and is not optional or (b) not long + */ + public static Long checkLong(String paramName, String paramValue, boolean isOptional) + throws IllegalArgumentException { + try { + if (!isOptional) { + WebUtil.checkObject(paramName, paramValue); + } + String value = paramValue != null ? StringUtils.trimToNull(paramValue) : null; + return value != null ? Long.valueOf(value) : null; + + } catch (NumberFormatException e) { + throw new IllegalArgumentException(paramName + " should be a long '" + paramValue + "'"); + } + } + + /** + * Get a long version of paramValue, throwing an IllegalArgumentException if isOptional = false and the is value is + * null + * + * @return long value of paramValue + * @exception IllegalArgumentException + * - if not set or not long + */ + public static long checkLong(String paramName, Long paramValue, boolean isOptional) + throws IllegalArgumentException { + if (!isOptional) { + WebUtil.checkObject(paramName, paramValue); + } + return paramValue.longValue(); + } + + /** + * @return boolean value of paramValue + * @exception IllegalArgumentException + * - if not set or not boolean + */ + public static boolean checkBoolean(String paramName, String paramValue) throws IllegalArgumentException { + WebUtil.checkObject(paramName, paramValue); + return Boolean.valueOf(paramValue.trim()).booleanValue(); + } + + /** + * Read an int parameter, throwing exception if null or not a integer + * + * @param req + * - + * @param paramName + * - + * @return parameter value + */ + public static int readIntParam(HttpServletRequest req, String paramName) { + return WebUtil.checkInteger(paramName, req.getParameter(paramName), false).intValue(); + } + + /** + * Read an int parameter, throwing exception if ( not optional and null ) or not a integer + * + * @param req + * - + * @param paramName + * - + * @param isOptional + * @return parameter value + */ + public static Integer readIntParam(HttpServletRequest req, String paramName, boolean isOptional) { + return WebUtil.checkInteger(paramName, req.getParameter(paramName), isOptional); + } + + /** + * Read an long parameter, throwing exception if null or not a long + * + * @param req + * - + * @param paramName + * - + * @return parameter value + */ + public static long readLongParam(HttpServletRequest req, String paramName) { + return WebUtil.checkLong(paramName, req.getParameter(paramName), false).longValue(); + } + + /** + * Read an long parameter, throwing exception if ( not optional and null ) or not a long + * + * @param req + * - + * @param paramName + * - + * @param isOptional + * @return parameter value + */ + public static Long readLongParam(HttpServletRequest req, String paramName, boolean isOptional) { + return WebUtil.checkLong(paramName, req.getParameter(paramName), isOptional); + } + + /** + * @param req + * - + * @param paramName + * - + * @return parameter value + */ + public static String readStrParam(HttpServletRequest req, String paramName) { + return WebUtil.readStrParam(req, paramName, false); + } + + /** + * @param req + * - + * @param paramName + * - + * @param isOptional + * @return parameter value + */ + public static String readStrParam(HttpServletRequest req, String paramName, boolean isOptional) { + if (!isOptional) { + WebUtil.checkObject(paramName, req.getParameter(paramName)); + } + return req.getParameter(paramName); + } + + /** + * @param req + * - + * @param paramName + * - + * @return parameter value + * @exception IllegalArgumentException + * - if valid boolean parameter value is not found + */ + public static boolean readBooleanParam(HttpServletRequest req, String paramName) throws IllegalArgumentException { + return WebUtil.checkBoolean(paramName, req.getParameter(paramName)); + } + + /** + * @param req + * - + * @param paramName + * - + * @param defaultValue + * - if valid boolean parameter value is not found, return this value + * @return parameter value + */ + public static boolean readBooleanParam(HttpServletRequest req, String paramName, boolean defaultValue) { + try { + return WebUtil.checkBoolean(paramName, req.getParameter(paramName)); + } catch (IllegalArgumentException e) { + return defaultValue; + } + } + + public static boolean readBooleanAttr(HttpServletRequest req, String attrName) { + return WebUtil.checkBoolean(attrName, (String) req.getSession().getAttribute(attrName)); + } + + /** + * Retrieve the tool access mode from http request. This is a utility used by the tools that share an implementation + * for the learner screen. They use mode=learner, mode=author and mode=teacher for learning, preview and monitoring + * respectively. Only used if the tool programmer wants to have one call that supports all three ways of looking at + * a learner screen. + * + * @param request + * @param param_mode + * @return the ToolAccessMode object + */ + public static ToolAccessMode readToolAccessModeParam(HttpServletRequest request, String param_mode, + boolean optional) { + String mode = WebUtil.readStrParam(request, param_mode, optional); + if (mode == null) { + return null; + } else if (mode.equals(ToolAccessMode.AUTHOR.toString())) { + return ToolAccessMode.AUTHOR; + } else if (mode.equals(ToolAccessMode.LEARNER.toString())) { + return ToolAccessMode.LEARNER; + } else if (mode.equals(ToolAccessMode.TEACHER.toString())) { + return ToolAccessMode.TEACHER; + } else { + throw new IllegalArgumentException("[" + mode + "] is not a legal mode" + "in LAMS"); + } + } + + /** + * Retrieve the tool access mode from a string value, presumably from a Form. This is a utility used by the tools + * that share an implementation for the learner screen. They use mode=learner, mode=author and mode=teacher for + * learning, preview and monitoring respectively. Only used if the tool programmer wants to have one call that + * supports all three ways of looking at a learner screen. + * + * @param request + * @return the ToolAccessMode object + */ + public static ToolAccessMode getToolAccessMode(String modeValue) { + if (modeValue != null) { + if (modeValue.equals(ToolAccessMode.AUTHOR.toString())) { + return ToolAccessMode.AUTHOR; + } else if (modeValue.equals(ToolAccessMode.LEARNER.toString())) { + return ToolAccessMode.LEARNER; + } else if (modeValue.equals(ToolAccessMode.TEACHER.toString())) { + return ToolAccessMode.TEACHER; + } + } + throw new IllegalArgumentException("[" + modeValue + "] is not a legal mode" + "in LAMS"); + } + + /** + * Get ToolAccessMode from HttpRequest parameters. Default value is AUTHOR mode. + * + * @param request + * @return + */ + public static ToolAccessMode readToolAccessModeAuthorDefaulted(HttpServletRequest request) { + String modeStr = request.getParameter(AttributeNames.ATTR_MODE); + + ToolAccessMode mode; + if (StringUtils.equalsIgnoreCase(modeStr, ToolAccessMode.TEACHER.toString())) { + mode = ToolAccessMode.TEACHER; + } else { + mode = ToolAccessMode.AUTHOR; + } + return mode; + } + + /** + * Append a parameter to a requested url. + * + * @param parameterName + * the name of the parameter + * @param parameterValue + * the value of the parameter + * @param learnerUrl + * the target url + * @return the url with parameter appended. + */ + public static String appendParameterToURL(String url, String parameterName, String parameterValue) { + return WebUtil.appendParameterDeliminator(url) + parameterName + "=" + parameterValue; + } + + /** + *

+ * This helper append the parameter deliminator for a url. + *

+ * It is using a null safe String util method to checkup the url String and append proper deliminator if necessary. + * + * @param url + * the url needs to append deliminator. + * @return target url with the deliminator; + */ + public static String appendParameterDeliminator(String url) { + if (url == null) { + return null; + } else if (StringUtils.containsNone(url, "?")) { + return url + "?"; + } else { + return url + "&"; + } + } + + /** + * Converts a url (such as one from a tool) to a complete url. If the url starts with "http" then it is assumed to + * be a complete url and is returned as is. Otherwise it assumes starts with the path of the webapp so it is + * appended to the server url from the LAMS Configuration. + * + * @param url + * e.g. tool/lanb11/starter/learner.do + * @return complete url + */ + public static String convertToFullURL(String url) { + if (url == null) { + return null; + } else if (url.startsWith("http")) { + return url; + } else { + String serverURL = Configuration.get(ConfigurationKeys.SERVER_URL); + if (url.charAt(0) == '/') { + return serverURL + url; + } else { + return serverURL + '/' + url; + } + } + } + + /** + * Convert any newslines in a string to
+ * . If input = null, returns null. + */ + public static String convertNewlines(String input) { + if (input != null) { + return input.replaceAll("[\n\r\f]", "
"); + } else { + return null; + } + } + + /** + * Strips HTML tags and leave "pure" text. Useful for CKeditor created text. + * + * @param text + * string to process + * @return string after stripping + */ + public static String removeHTMLtags(String text) { + return text == null ? null + : text.replaceAll(WebUtil.SPACE_TAG_REGEX, " ").replaceAll(WebUtil.HTML_TAG_REGEX, ""); + } + + /** + * Makes a request to the specified url with the specified parameters and returns the response inputstream + * + * @param urlStr + * @param params + * @return + * @throws ToolException + * @throws IOException + */ + public static InputStream getResponseInputStreamFromExternalServer(String urlStr, HashMap params) + throws Exception { + if (!urlStr.contains("?")) { + urlStr += "?"; + } + + for (Entry entry : params.entrySet()) { + urlStr += "&" + entry.getKey() + "=" + entry.getValue(); + } + + WebUtil.log.info("Making request to external servlet: " + urlStr); + + URL url = new URL(urlStr); + URLConnection conn = url.openConnection(); + if (!(conn instanceof HttpURLConnection)) { + WebUtil.log.error("Fail to connect to external server though url: " + urlStr); + throw new Exception("Fail to connect to external server though url: " + urlStr); + } + + HttpURLConnection httpConn = (HttpURLConnection) conn; + if (httpConn.getResponseCode() != HttpURLConnection.HTTP_OK) { + WebUtil.log.error("Response code from external server: " + httpConn.getResponseCode() + " Url: " + urlStr); + } + + InputStream is = url.openConnection().getInputStream(); + if (is == null) { + WebUtil.log.error("Fail to fetch data from external server, return InputStream null: " + urlStr); + throw new Exception("Fail to fetch data from external server, return inputStream null: " + urlStr); + } + + return is; + } + + public static String extractParameterValue(String url, String param) { + if (!StringUtils.isBlank(url) && !StringUtils.isBlank(param)) { + int quotationMarkIndex = url.indexOf("?"); + String queryPart = quotationMarkIndex > -1 ? url.substring(quotationMarkIndex + 1) : url; + String[] paramEntries = queryPart.split("&"); + for (String paramEntry : paramEntries) { + String[] paramEntrySplitted = paramEntry.split("="); + if ((paramEntrySplitted.length > 1) && param.equalsIgnoreCase(paramEntrySplitted[0])) { + return paramEntrySplitted[1]; + } + } + } + return null; + } + + /** + * Produces JSON object with basic user details. + */ + public static ObjectNode userToJSON(User user) { + ObjectNode userJSON = JsonNodeFactory.instance.objectNode(); + userJSON.put("id", user.getUserId()); + userJSON.put("firstName", user.getFirstName()); + userJSON.put("lastName", user.getLastName()); + userJSON.put("login", user.getLogin()); + userJSON.put("portraitId", user.getPortraitUuid()); + return userJSON; + } + + public static String getBaseServerURL() { + String serverURL = Configuration.get(ConfigurationKeys.SERVER_URL); + // "https://" is 8 characters, so next "/" should be context + return serverURL.substring(0, serverURL.indexOf('/', 9)); + } + + /** + * Converse lessonId into alphabetic sequence for using it in URL shortening + * + * @param lessonId + * @return + */ + public static String encodeLessonId(Long lessonId) { + String encodedLessonId = lessonId.toString(); + encodedLessonId = encodedLessonId.replace('0', URL_SHORTENING_CYPHER.charAt(0)); + encodedLessonId = encodedLessonId.replace('1', URL_SHORTENING_CYPHER.charAt(1)); + encodedLessonId = encodedLessonId.replace('2', URL_SHORTENING_CYPHER.charAt(2)); + encodedLessonId = encodedLessonId.replace('3', URL_SHORTENING_CYPHER.charAt(3)); + encodedLessonId = encodedLessonId.replace('4', URL_SHORTENING_CYPHER.charAt(4)); + encodedLessonId = encodedLessonId.replace('5', URL_SHORTENING_CYPHER.charAt(5)); + encodedLessonId = encodedLessonId.replace('6', URL_SHORTENING_CYPHER.charAt(6)); + encodedLessonId = encodedLessonId.replace('7', URL_SHORTENING_CYPHER.charAt(7)); + encodedLessonId = encodedLessonId.replace('8', URL_SHORTENING_CYPHER.charAt(8)); + encodedLessonId = encodedLessonId.replace('9', URL_SHORTENING_CYPHER.charAt(9)); + + return encodedLessonId; + } + + /** + * Decodes alphabetic sequence (that is lessonId encoded for URL shortening purposes) + * + * @param encodedlessonId + * @return + */ + public static String decodeLessonId(String encodedLessonId) throws IllegalArgumentException { + + // it should contain only the characters from URL_SHORTENING_CYPHER + if (!encodedLessonId.matches("[" + URL_SHORTENING_CYPHER + "]*")) { + throw new IllegalArgumentException("LessonId: " + encodedLessonId + " has wrong format."); + } + + String decodedLessonId = encodedLessonId; + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(0), '0'); + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(1), '1'); + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(2), '2'); + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(3), '3'); + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(4), '4'); + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(5), '5'); + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(6), '6'); + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(7), '7'); + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(8), '8'); + decodedLessonId = decodedLessonId.replace(URL_SHORTENING_CYPHER.charAt(9), '9'); + + return decodedLessonId; + } + + public static Document getDocument() throws ParserConfigurationException { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.newDocument(); + return document; + } + + public static String getStringFromDocument(Document document) throws TransformerException { + DOMSource domSource = new DOMSource(document); + StringWriter writer = new StringWriter(); + StreamResult result = new StreamResult(writer); + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer transformer = tf.newTransformer(); + transformer.transform(domSource, result); + return writer.toString(); + } } \ No newline at end of file Index: lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/util/GradebookConstants.java =================================================================== diff -u -r62aaf160878735888d077bf28fac3c1989bb8fbd -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/util/GradebookConstants.java (.../GradebookConstants.java) (revision 62aaf160878735888d077bf28fac3c1989bb8fbd) +++ lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/util/GradebookConstants.java (.../GradebookConstants.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -1,87 +1,83 @@ -/**************************************************************** - * Copyright (C) 2008 LAMS Foundation (http://lamsfoundation.org) - * ============================================================= - * License Information: http://lamsfoundation.org/licensing/lams/2.0/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2.0 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA - * - * http://www.gnu.org/licenses/gpl.txt - * **************************************************************** - */ - -package org.lamsfoundation.lams.gradebook.util; - -/** - * Constants for gradebook module - * - * @author lfoxton - * - */ -public class GradebookConstants { - - public static final String MODULE_NAME = "gradebook"; - - // Parameters - public static final String PARAM_LOGIN = "login"; - public static final String PARAM_ID = "id"; - public static final String PARAM_MARK = "mark"; - public static final String PARAM_FEEDBACK = "feedback"; - public static final String PARAM_USERID = "userID"; - public static final String PARAM_SEARCH = "_search"; - public static final String PARAM_SEARCH_FIELD = "searchField"; - public static final String PARAM_SEARCH_OPERATION = "searchOper"; - public static final String PARAM_SEARCH_STRING = "searchString"; - public static final String PARAM_ROW_NAME = "rowName"; - public static final String PARAM_TIME_TAKEN = "timeTaken"; - public static final String PARAM_AVG_TIME_TAKEN = "avgTimeTaken"; - public static final String PARAM_AVG_MARK = "avgMark"; - public static final String PARAM_VIEW = "view"; - public static final String PARAM_START_DATE = "startDate"; - public static final String PARAM_GROUP_ID = "groupId"; - - // Sort - public static final String SORT_DESC = "desc"; - public static final String SORT_ASC = "asc"; - - // Search - public static final String SEARCH_EQUALS = "eq"; - public static final String SEARCH_NOT_EQUALS = "ne"; - public static final String SEARCH_BEGINS_WITH = "bw"; - public static final String SEARCH_ENDS_WITH = "ew"; - public static final String SEARCH_CONTAINS = "cn"; - - // Views - public static final String VIEW_MON_ACTIVITY = "monActivityView"; - public static final String VIEW_MON_USER = "monUserView"; - public static final String VIEW_MON_COURSE = "monCourse"; - public static final String VIEW_LRN_COURSE = "lrnCourse"; - public static final String VIEW_LRN_ACTIVITY = "lrnActivity"; - public static final String VIEW_LIST = "listView"; - - // XML Elemetns - public static final String ELEMENT_ROWS = "rows"; - public static final String ELEMENT_PAGE = "page"; - public static final String ELEMENT_TOTAL = "total"; - public static final String ELEMENT_RECORDS = "records"; - public static final String ELEMENT_ROW = "row"; - public static final String ELEMENT_ID = "id"; - public static final String ELEMENT_CELL = "cell"; - - // Misc - public static final String CONTENT_TYPE_TEXTXML = "text/xml"; - public static final String CONTENT_TYPE_TEXTPLAIN = "text/plain"; - public static final String CELL_EMPTY = "-"; - public static final String UTF8 = "UTF8"; - -} +/**************************************************************** + * Copyright (C) 2008 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.gradebook.util; + +/** + * Constants for gradebook module + * + * @author lfoxton + * + */ +public class GradebookConstants { + + public static final String MODULE_NAME = "gradebook"; + + // Parameters + public static final String PARAM_LOGIN = "login"; + public static final String PARAM_ID = "id"; + public static final String PARAM_MARK = "mark"; + public static final String PARAM_FEEDBACK = "feedback"; + public static final String PARAM_USERID = "userID"; + public static final String PARAM_ROW_NAME = "rowName"; + public static final String PARAM_TIME_TAKEN = "timeTaken"; + public static final String PARAM_AVG_TIME_TAKEN = "avgTimeTaken"; + public static final String PARAM_AVG_MARK = "avgMark"; + public static final String PARAM_VIEW = "view"; + public static final String PARAM_START_DATE = "startDate"; + public static final String PARAM_GROUP_ID = "groupId"; + + // Sort + public static final String SORT_DESC = "desc"; + public static final String SORT_ASC = "asc"; + + // Search + public static final String SEARCH_EQUALS = "eq"; + public static final String SEARCH_NOT_EQUALS = "ne"; + public static final String SEARCH_BEGINS_WITH = "bw"; + public static final String SEARCH_ENDS_WITH = "ew"; + public static final String SEARCH_CONTAINS = "cn"; + + // Views + public static final String VIEW_MON_ACTIVITY = "monActivityView"; + public static final String VIEW_MON_USER = "monUserView"; + public static final String VIEW_MON_COURSE = "monCourse"; + public static final String VIEW_LRN_COURSE = "lrnCourse"; + public static final String VIEW_LRN_ACTIVITY = "lrnActivity"; + public static final String VIEW_LIST = "listView"; + + // XML Elemetns + public static final String ELEMENT_ROWS = "rows"; + public static final String ELEMENT_PAGE = "page"; + public static final String ELEMENT_TOTAL = "total"; + public static final String ELEMENT_RECORDS = "records"; + public static final String ELEMENT_ROW = "row"; + public static final String ELEMENT_ID = "id"; + public static final String ELEMENT_CELL = "cell"; + + // Misc + public static final String CONTENT_TYPE_TEXTXML = "text/xml"; + public static final String CONTENT_TYPE_TEXTPLAIN = "text/plain"; + public static final String CELL_EMPTY = "-"; + public static final String UTF8 = "UTF8"; + +} Index: lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/util/GradebookUtil.java =================================================================== diff -u -rbe74862925361d836bef1df4c5959105c9695a87 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/util/GradebookUtil.java (.../GradebookUtil.java) (revision be74862925361d836bef1df4c5959105c9695a87) +++ lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/util/GradebookUtil.java (.../GradebookUtil.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -1,341 +1,318 @@ -/**************************************************************** - * Copyright (C) 2008 LAMS Foundation (http://lamsfoundation.org) - * ============================================================= - * License Information: http://lamsfoundation.org/licensing/lams/2.0/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2.0 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA - * - * http://www.gnu.org/licenses/gpl.txt - * **************************************************************** - */ - - -package org.lamsfoundation.lams.gradebook.util; - -import java.io.StringWriter; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.lamsfoundation.lams.gradebook.dto.GradebookGridRowDTO; -import org.lamsfoundation.lams.gradebook.dto.comparators.GBAverageMarkComparator; -import org.lamsfoundation.lams.gradebook.dto.comparators.GBIDComparator; -import org.lamsfoundation.lams.gradebook.dto.comparators.GBMarkComparator; -import org.lamsfoundation.lams.gradebook.dto.comparators.GBMedianTimeTakenComparator; -import org.lamsfoundation.lams.gradebook.dto.comparators.GBRowNameComparator; -import org.lamsfoundation.lams.gradebook.dto.comparators.GBStartDateComparator; -import org.lamsfoundation.lams.gradebook.dto.comparators.GBTimeTakenComparator; -import org.lamsfoundation.lams.util.CommonConstants; -import org.lamsfoundation.lams.util.ExcelCell; -import org.lamsfoundation.lams.util.WebUtil; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -public class GradebookUtil { - - /** - * Wrapper method for printing the xml for grid rows - * - * It takes the list of rows along with the grid parameter and returns the - * xml for the altered set - * - * - * @param gridRows - * @param view - * @param sortBy - * @param isSearch - * @param searchField - * @param searchOper - * @param searchString - * @param sortOrder - * @param rowLimit - * @param page - * @return - */ - public static String toGridXML(List gridRows, GBGridView view, String sortBy, boolean isSearch, String searchField, - String searchOper, String searchString, String sortOrder, int rowLimit, int page) { - - // Alter the set based on the parameters - gridRows = GradebookUtil.makeGridRowAlterations(gridRows, sortBy, isSearch, searchField, searchOper, - searchString, sortOrder, rowLimit, page); - // Work out the sublist to fetch based on rowlimit and current page. - int totalPages = 1; - if (rowLimit < gridRows.size()) { - - totalPages = new Double( - Math.ceil(new Integer(gridRows.size()).doubleValue() / new Integer(rowLimit).doubleValue())) - .intValue(); - int firstRow = (page - 1) * rowLimit; - int lastRow = firstRow + rowLimit; - - if (lastRow > gridRows.size()) { - gridRows = gridRows.subList(firstRow, gridRows.size()); - } else { - gridRows = gridRows.subList(firstRow, lastRow); - } - - } - - return GradebookUtil.toGridXML(gridRows, page, totalPages, view); - } - - /** - * Tranlates a list of grid rows into the required jqGrid xml - * - * @param gridRows - * @param page - * @param totalPages - * @param view - * @return - */ - public static String toGridXML(List gridRows, int page, int totalPages, GBGridView view) { - String xml = ""; - try { - Document document = GradebookUtil.getDocument(); - - // root element - Element rootElement = document.createElement(CommonConstants.ELEMENT_ROWS); - - Element pageElement = document.createElement(CommonConstants.ELEMENT_PAGE); - pageElement.appendChild(document.createTextNode("" + page)); - rootElement.appendChild(pageElement); - - Element totalPageElement = document.createElement(CommonConstants.ELEMENT_TOTAL); - totalPageElement.appendChild(document.createTextNode("" + totalPages)); - rootElement.appendChild(totalPageElement); - - Element recordsElement = document.createElement(CommonConstants.ELEMENT_RECORDS); - recordsElement.appendChild(document.createTextNode("" + gridRows.size())); - rootElement.appendChild(recordsElement); - - Iterator iter = gridRows.iterator(); - while (iter.hasNext()) { - GradebookGridRowDTO gridRow = (GradebookGridRowDTO) iter.next(); - Element rowElement = document.createElement(CommonConstants.ELEMENT_ROW); - rowElement.setAttribute(CommonConstants.ELEMENT_ID, gridRow.getId().toString()); - - // Work out which grid we want to put the data into - ArrayList gridRowStringArray = new ArrayList(); - - gridRowStringArray = gridRow.toStringArray(view); - - for (String gradebookItem : gridRowStringArray) { - Element cellElement = document.createElement(CommonConstants.ELEMENT_CELL); - gradebookItem = (gradebookItem != null) ? gradebookItem : ""; - cellElement.appendChild(document.createTextNode(gradebookItem)); - rowElement.appendChild(cellElement); - } - rootElement.appendChild(rowElement); - } - - document.appendChild(rootElement); - xml = GradebookUtil.getStringFromDocument(document); - - } catch (ParserConfigurationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (TransformerException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return xml; - } - - public static String niceFormatting(Double mark) { - String markStr = new DecimalFormat("##0.00").format(mark); - return markStr; - } - - public static String niceFormatting(Double mark, boolean displayAsPercentage) { - String markStr = new DecimalFormat("##0.00").format(mark); - if ( displayAsPercentage ) - markStr += "%"; - return markStr; - } - - public static ExcelCell createPercentageCell(Double mark, boolean markConversionNeeded) { - return createPercentageCell(mark, markConversionNeeded, false, 0); - } - -// public static ExcelCell createPercentageCell(Double mark, boolean markConversionNeeded, Boolean isBold) { -// return createPercentageCell(mark, markConversionNeeded, isBold, 0); -// } - - // if markConversionNeeded is true then mark is divided by 100. Otherwise assumes already a percentage. - public static ExcelCell createPercentageCell(Double mark, boolean markConversionNeeded, Boolean isBold, int borderStyle) { - Double convertedMark = null; - if ( mark != null ) - convertedMark = markConversionNeeded ? mark / 100.0 : mark; - - ExcelCell userMarkCell = new ExcelCell(convertedMark, isBold, borderStyle); - userMarkCell.setIsPercentage(true); - return userMarkCell; - } - - private static Document getDocument() throws ParserConfigurationException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document document = builder.newDocument(); - return document; - - } - - private static String getStringFromDocument(Document document) throws TransformerException { - DOMSource domSource = new DOMSource(document); - StringWriter writer = new StringWriter(); - StreamResult result = new StreamResult(writer); - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(); - transformer.transform(domSource, result); - return writer.toString(); - } - - /** - * Alters a grid row for sorting and searching - * - * @param gridRows - * @param sortBy - * @param isSearch - * @param searchField - * @param searchOper - * @param searchString - * @param sortOrder - * @param rowLimit - * @param page - * @return - */ - @SuppressWarnings("unchecked") - private static List makeGridRowAlterations(List gridRows, String sortBy, boolean isSearch, String searchField, - String searchOper, String searchString, String sortOrder, int rowLimit, int page) { - - // Sort the list appropriately - if (sortBy != null) { - if (sortBy.equals(GradebookConstants.PARAM_ROW_NAME)) { - Collections.sort(gridRows, new GBRowNameComparator()); - } else if (sortBy.equals(GradebookConstants.PARAM_MARK)) { - Collections.sort(gridRows, new GBMarkComparator()); - } else if (sortBy.equals(GradebookConstants.PARAM_ID)) { - Collections.sort(gridRows, new GBIDComparator()); - } else if (sortBy.equals(GradebookConstants.PARAM_TIME_TAKEN)) { - Collections.sort(gridRows, new GBTimeTakenComparator()); - } else if (sortBy.equals(GradebookConstants.PARAM_AVG_TIME_TAKEN)) { - Collections.sort(gridRows, new GBMedianTimeTakenComparator()); - } else if (sortBy.equals(GradebookConstants.PARAM_AVG_MARK)) { - Collections.sort(gridRows, new GBAverageMarkComparator()); - } else if (sortBy.equals(GradebookConstants.PARAM_START_DATE)) { - Collections.sort(gridRows, new GBStartDateComparator()); - } else { - Collections.sort(gridRows, new GBRowNameComparator()); - } - } else { - Collections.sort(gridRows, new GBRowNameComparator()); - } - - // if it is a search fix up the set - if (isSearch && searchField != null && searchOper != null && searchString != null) { - gridRows = GradebookUtil.doRowNameSearch(gridRows, searchField, searchOper, searchString.toLowerCase()); - } - - // Reverse the order if requested - if (sortOrder != null && sortOrder.equals(GradebookConstants.SORT_DESC)) { - Collections.reverse(gridRows); - } - - return gridRows; - - } - - /** - * Does the search operation on the set for row names - * - * @param gradebookRows - * @param searchField - * @param searchOper - * @param searchString - * @return - */ - private static List doRowNameSearch(List gradebookRows, String searchField, String searchOper, - String searchString) { - List ret = new ArrayList(); - - if (searchField.equals(GradebookConstants.PARAM_ROW_NAME)) { - Iterator it = gradebookRows.iterator(); - - while (it.hasNext()) { - GradebookGridRowDTO userRow = (GradebookGridRowDTO) it.next(); - - String rowName = userRow.getRowName(); - rowName = rowName.toLowerCase(); - - if (searchOper.equals(GradebookConstants.SEARCH_EQUALS)) { - if (rowName.equals(searchString)) { - ret.add(userRow); - } - } else if (searchOper.equals(GradebookConstants.SEARCH_NOT_EQUALS)) { - if (!rowName.equals(searchString)) { - ret.add(userRow); - } - } else if (searchOper.equals(GradebookConstants.SEARCH_BEGINS_WITH)) { - if (rowName.startsWith(searchString)) { - ret.add(userRow); - } - } else if (searchOper.equals(GradebookConstants.SEARCH_ENDS_WITH)) { - if (rowName.endsWith(searchString)) { - ret.add(userRow); - } - } else if (searchOper.equals(GradebookConstants.SEARCH_CONTAINS)) { - if (rowName.contains(searchString)) { - ret.add(userRow); - } - } - } - - } - return ret; - } - - public static GBGridView readGBGridViewParam(HttpServletRequest request, String param_mode, boolean optional) { - String view = WebUtil.readStrParam(request, param_mode, optional); - if (view == null) { - return null; - } else if (view.equals(GradebookConstants.VIEW_MON_USER)) { - return GBGridView.MON_USER; - } else if (view.equals(GradebookConstants.VIEW_MON_ACTIVITY)) { - return GBGridView.MON_ACTIVITY; - } else if (view.equals(GradebookConstants.VIEW_MON_COURSE)) { - return GBGridView.MON_COURSE; - } else if (view.equals(GradebookConstants.VIEW_LRN_COURSE)) { - return GBGridView.LRN_COURSE; - } else if (view.equals(GradebookConstants.VIEW_LRN_ACTIVITY)) { - return GBGridView.LRN_ACTIVITY; - } else if (view.equals(GradebookConstants.VIEW_LIST)) { - return GBGridView.LIST; - } else { - throw new IllegalArgumentException("[" + view + "] is not a legal gradebook view"); - } - } -} +/**************************************************************** + * Copyright (C) 2008 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.gradebook.util; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.lamsfoundation.lams.gradebook.dto.GradebookGridRowDTO; +import org.lamsfoundation.lams.gradebook.dto.comparators.GBAverageMarkComparator; +import org.lamsfoundation.lams.gradebook.dto.comparators.GBIDComparator; +import org.lamsfoundation.lams.gradebook.dto.comparators.GBMarkComparator; +import org.lamsfoundation.lams.gradebook.dto.comparators.GBMedianTimeTakenComparator; +import org.lamsfoundation.lams.gradebook.dto.comparators.GBRowNameComparator; +import org.lamsfoundation.lams.gradebook.dto.comparators.GBStartDateComparator; +import org.lamsfoundation.lams.gradebook.dto.comparators.GBTimeTakenComparator; +import org.lamsfoundation.lams.util.CommonConstants; +import org.lamsfoundation.lams.util.ExcelCell; +import org.lamsfoundation.lams.util.WebUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +public class GradebookUtil { + + /** + * Wrapper method for printing the xml for grid rows + * + * It takes the list of rows along with the grid parameter and returns the + * xml for the altered set + * + * + * @param gridRows + * @param view + * @param sortBy + * @param isSearch + * @param searchField + * @param searchOper + * @param searchString + * @param sortOrder + * @param rowLimit + * @param page + * @return + */ + public static String toGridXML(List gridRows, GBGridView view, String sortBy, boolean isSearch, String searchField, + String searchOper, String searchString, String sortOrder, int rowLimit, int page) { + + // Alter the set based on the parameters + gridRows = GradebookUtil.makeGridRowAlterations(gridRows, sortBy, isSearch, searchField, searchOper, + searchString, sortOrder, rowLimit, page); + // Work out the sublist to fetch based on rowlimit and current page. + int totalPages = 1; + if (rowLimit < gridRows.size()) { + + totalPages = new Double( + Math.ceil(new Integer(gridRows.size()).doubleValue() / new Integer(rowLimit).doubleValue())) + .intValue(); + int firstRow = (page - 1) * rowLimit; + int lastRow = firstRow + rowLimit; + + if (lastRow > gridRows.size()) { + gridRows = gridRows.subList(firstRow, gridRows.size()); + } else { + gridRows = gridRows.subList(firstRow, lastRow); + } + + } + + return GradebookUtil.toGridXML(gridRows, page, totalPages, view); + } + + /** + * Tranlates a list of grid rows into the required jqGrid xml + * + * @param gridRows + * @param page + * @param totalPages + * @param view + * @return + */ + public static String toGridXML(List gridRows, int page, int totalPages, GBGridView view) { + String xml = ""; + try { + Document document = WebUtil.getDocument(); + + // root element + Element rootElement = document.createElement(CommonConstants.ELEMENT_ROWS); + + Element pageElement = document.createElement(CommonConstants.ELEMENT_PAGE); + pageElement.appendChild(document.createTextNode("" + page)); + rootElement.appendChild(pageElement); + + Element totalPageElement = document.createElement(CommonConstants.ELEMENT_TOTAL); + totalPageElement.appendChild(document.createTextNode("" + totalPages)); + rootElement.appendChild(totalPageElement); + + Element recordsElement = document.createElement(CommonConstants.ELEMENT_RECORDS); + recordsElement.appendChild(document.createTextNode("" + gridRows.size())); + rootElement.appendChild(recordsElement); + + Iterator iter = gridRows.iterator(); + while (iter.hasNext()) { + GradebookGridRowDTO gridRow = (GradebookGridRowDTO) iter.next(); + Element rowElement = document.createElement(CommonConstants.ELEMENT_ROW); + rowElement.setAttribute(CommonConstants.ELEMENT_ID, gridRow.getId().toString()); + + // Work out which grid we want to put the data into + ArrayList gridRowStringArray = new ArrayList<>(); + + gridRowStringArray = gridRow.toStringArray(view); + + for (String gradebookItem : gridRowStringArray) { + Element cellElement = document.createElement(CommonConstants.ELEMENT_CELL); + gradebookItem = (gradebookItem != null) ? gradebookItem : ""; + cellElement.appendChild(document.createTextNode(gradebookItem)); + rowElement.appendChild(cellElement); + } + rootElement.appendChild(rowElement); + } + + document.appendChild(rootElement); + xml = WebUtil.getStringFromDocument(document); + + } catch (ParserConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (TransformerException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return xml; + } + + public static String niceFormatting(Double mark) { + String markStr = new DecimalFormat("##0.00").format(mark); + return markStr; + } + + public static String niceFormatting(Double mark, boolean displayAsPercentage) { + String markStr = new DecimalFormat("##0.00").format(mark); + if (displayAsPercentage) { + markStr += "%"; + } + return markStr; + } + + public static ExcelCell createPercentageCell(Double mark, boolean markConversionNeeded) { + return GradebookUtil.createPercentageCell(mark, markConversionNeeded, false, 0); + } + +// public static ExcelCell createPercentageCell(Double mark, boolean markConversionNeeded, Boolean isBold) { +// return createPercentageCell(mark, markConversionNeeded, isBold, 0); +// } + + // if markConversionNeeded is true then mark is divided by 100. Otherwise assumes already a percentage. + public static ExcelCell createPercentageCell(Double mark, boolean markConversionNeeded, Boolean isBold, + int borderStyle) { + Double convertedMark = null; + if (mark != null) { + convertedMark = markConversionNeeded ? mark / 100.0 : mark; + } + + ExcelCell userMarkCell = new ExcelCell(convertedMark, isBold, borderStyle); + userMarkCell.setIsPercentage(true); + return userMarkCell; + } + + /** + * Alters a grid row for sorting and searching + * + * @param gridRows + * @param sortBy + * @param isSearch + * @param searchField + * @param searchOper + * @param searchString + * @param sortOrder + * @param rowLimit + * @param page + * @return + */ + @SuppressWarnings("unchecked") + private static List makeGridRowAlterations(List gridRows, String sortBy, boolean isSearch, String searchField, + String searchOper, String searchString, String sortOrder, int rowLimit, int page) { + + // Sort the list appropriately + if (sortBy != null) { + if (sortBy.equals(GradebookConstants.PARAM_ROW_NAME)) { + Collections.sort(gridRows, new GBRowNameComparator()); + } else if (sortBy.equals(GradebookConstants.PARAM_MARK)) { + Collections.sort(gridRows, new GBMarkComparator()); + } else if (sortBy.equals(GradebookConstants.PARAM_ID)) { + Collections.sort(gridRows, new GBIDComparator()); + } else if (sortBy.equals(GradebookConstants.PARAM_TIME_TAKEN)) { + Collections.sort(gridRows, new GBTimeTakenComparator()); + } else if (sortBy.equals(GradebookConstants.PARAM_AVG_TIME_TAKEN)) { + Collections.sort(gridRows, new GBMedianTimeTakenComparator()); + } else if (sortBy.equals(GradebookConstants.PARAM_AVG_MARK)) { + Collections.sort(gridRows, new GBAverageMarkComparator()); + } else if (sortBy.equals(GradebookConstants.PARAM_START_DATE)) { + Collections.sort(gridRows, new GBStartDateComparator()); + } else { + Collections.sort(gridRows, new GBRowNameComparator()); + } + } else { + Collections.sort(gridRows, new GBRowNameComparator()); + } + + // if it is a search fix up the set + if (isSearch && searchField != null && searchOper != null && searchString != null) { + gridRows = GradebookUtil.doRowNameSearch(gridRows, searchField, searchOper, searchString.toLowerCase()); + } + + // Reverse the order if requested + if (sortOrder != null && sortOrder.equals(GradebookConstants.SORT_DESC)) { + Collections.reverse(gridRows); + } + + return gridRows; + + } + + /** + * Does the search operation on the set for row names + * + * @param gradebookRows + * @param searchField + * @param searchOper + * @param searchString + * @return + */ + private static List doRowNameSearch(List gradebookRows, String searchField, String searchOper, + String searchString) { + List ret = new ArrayList<>(); + + if (searchField.equals(GradebookConstants.PARAM_ROW_NAME)) { + Iterator it = gradebookRows.iterator(); + + while (it.hasNext()) { + GradebookGridRowDTO userRow = (GradebookGridRowDTO) it.next(); + + String rowName = userRow.getRowName(); + rowName = rowName.toLowerCase(); + + if (searchOper.equals(GradebookConstants.SEARCH_EQUALS)) { + if (rowName.equals(searchString)) { + ret.add(userRow); + } + } else if (searchOper.equals(GradebookConstants.SEARCH_NOT_EQUALS)) { + if (!rowName.equals(searchString)) { + ret.add(userRow); + } + } else if (searchOper.equals(GradebookConstants.SEARCH_BEGINS_WITH)) { + if (rowName.startsWith(searchString)) { + ret.add(userRow); + } + } else if (searchOper.equals(GradebookConstants.SEARCH_ENDS_WITH)) { + if (rowName.endsWith(searchString)) { + ret.add(userRow); + } + } else if (searchOper.equals(GradebookConstants.SEARCH_CONTAINS)) { + if (rowName.contains(searchString)) { + ret.add(userRow); + } + } + } + + } + return ret; + } + + public static GBGridView readGBGridViewParam(HttpServletRequest request, String param_mode, boolean optional) { + String view = WebUtil.readStrParam(request, param_mode, optional); + if (view == null) { + return null; + } else if (view.equals(GradebookConstants.VIEW_MON_USER)) { + return GBGridView.MON_USER; + } else if (view.equals(GradebookConstants.VIEW_MON_ACTIVITY)) { + return GBGridView.MON_ACTIVITY; + } else if (view.equals(GradebookConstants.VIEW_MON_COURSE)) { + return GBGridView.MON_COURSE; + } else if (view.equals(GradebookConstants.VIEW_LRN_COURSE)) { + return GBGridView.LRN_COURSE; + } else if (view.equals(GradebookConstants.VIEW_LRN_ACTIVITY)) { + return GBGridView.LRN_ACTIVITY; + } else if (view.equals(GradebookConstants.VIEW_LIST)) { + return GBGridView.LIST; + } else { + throw new IllegalArgumentException("[" + view + "] is not a legal gradebook view"); + } + } +} Index: lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/web/controller/GradebookController.java =================================================================== diff -u -r29a37489a63e5a95f42a5ef5fd8a7daeb65c53c5 -r43d88e533dd5666feeaeab4368982ad8028bfae3 --- lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/web/controller/GradebookController.java (.../GradebookController.java) (revision 29a37489a63e5a95f42a5ef5fd8a7daeb65c53c5) +++ lams_gradebook/src/java/org/lamsfoundation/lams/gradebook/web/controller/GradebookController.java (.../GradebookController.java) (revision 43d88e533dd5666feeaeab4368982ad8028bfae3) @@ -1,624 +1,624 @@ -/**************************************************************** - * Copyright (C) 2008 LAMS Foundation (http://lamsfoundation.org) - * ============================================================= - * License Information: http://lamsfoundation.org/licensing/lams/2.0/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2.0 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA - * - * http://www.gnu.org/licenses/gpl.txt - * **************************************************************** - */ - -package org.lamsfoundation.lams.gradebook.web.controller; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.apache.log4j.Logger; -import org.lamsfoundation.lams.gradebook.GradebookUserLesson; -import org.lamsfoundation.lams.gradebook.dto.GBLessonGridRowDTO; -import org.lamsfoundation.lams.gradebook.dto.GBUserGridRowDTO; -import org.lamsfoundation.lams.gradebook.dto.GradebookGridRowDTO; -import org.lamsfoundation.lams.gradebook.service.IGradebookFullService; -import org.lamsfoundation.lams.gradebook.util.GBGridView; -import org.lamsfoundation.lams.gradebook.util.GradebookConstants; -import org.lamsfoundation.lams.gradebook.util.GradebookUtil; -import org.lamsfoundation.lams.learning.service.ILearnerService; -import org.lamsfoundation.lams.learningdesign.Activity; -import org.lamsfoundation.lams.learningdesign.Group; -import org.lamsfoundation.lams.learningdesign.ToolActivity; -import org.lamsfoundation.lams.learningdesign.dto.ActivityURL; -import org.lamsfoundation.lams.lesson.Lesson; -import org.lamsfoundation.lams.lesson.service.ILessonService; -import org.lamsfoundation.lams.security.ISecurityService; -import org.lamsfoundation.lams.usermanagement.Organisation; -import org.lamsfoundation.lams.usermanagement.Role; -import org.lamsfoundation.lams.usermanagement.User; -import org.lamsfoundation.lams.usermanagement.dto.UserDTO; -import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; -import org.lamsfoundation.lams.util.CommonConstants; -import org.lamsfoundation.lams.util.Configuration; -import org.lamsfoundation.lams.util.ConfigurationKeys; -import org.lamsfoundation.lams.util.WebUtil; -import org.lamsfoundation.lams.web.session.SessionManager; -import org.lamsfoundation.lams.web.util.AttributeNames; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; - -/** - * Handles the general requests for content in gradebook - * - * @author lfoxton - */ -@Controller -@RequestMapping("/gradebook") -public class GradebookController { - private static Logger logger = Logger.getLogger(GradebookController.class); - - @Autowired - private IGradebookFullService gradebookService; - @Autowired - private IUserManagementService userManagementService; - @Autowired - private ILessonService lessonService; - @Autowired - private ISecurityService securityService; - @Autowired - private ILearnerService learnerService; - - @RequestMapping("") - @ResponseBody - public void unspecified() throws Exception { - } - - /** - * Returns an xml representation of the activity grid for gradebook - * - * This has two modes, userView and activityView - * - * User view will get the grid data for a specified user, which is all their activity marks/outputs etc - * - * Activity view will get the grid data for all activities, without user info, instead there is an average mark for - * each activity. - */ - @RequestMapping("/getActivityGridData") - @ResponseBody - public String getActivityGridData(HttpServletRequest request, HttpServletResponse response) throws Exception { - // Getting the params passed in from the jqGrid - int page = WebUtil.readIntParam(request, CommonConstants.PARAM_PAGE); - int rowLimit = WebUtil.readIntParam(request, CommonConstants.PARAM_ROWS); - String sortOrder = WebUtil.readStrParam(request, CommonConstants.PARAM_SORD); - String sortBy = WebUtil.readStrParam(request, CommonConstants.PARAM_SIDX, true); - Boolean isSearch = WebUtil.readBooleanParam(request, GradebookConstants.PARAM_SEARCH); - String searchField = WebUtil.readStrParam(request, GradebookConstants.PARAM_SEARCH_FIELD, true); - String searchOper = WebUtil.readStrParam(request, GradebookConstants.PARAM_SEARCH_OPERATION, true); - String searchString = WebUtil.readStrParam(request, GradebookConstants.PARAM_SEARCH_STRING, true); - GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); - - Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - if (!securityService.isLessonParticipant(lessonID, getUser().getUserID(), "get activity gradebook data", - false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a learner in the lesson"); - return null; - } - - // Getting userID param, it is passed differently from different views - UserDTO currentUserDTO = getUser(); - Integer userID = null; - if (view == GBGridView.MON_USER) { - userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); - } else if (view == GBGridView.LRN_ACTIVITY) { - if (currentUserDTO != null) { - userID = currentUserDTO.getUserID(); - } - } - - List gradebookActivityDTOs = new ArrayList<>(); - - // Get the user gradebook list from the db - // A slightly different list is needed for userview or activity view - if ((view == GBGridView.MON_USER) || (view == GBGridView.LRN_ACTIVITY)) {//2nd level && from personal marks page (2nd level or 1st) - gradebookActivityDTOs = gradebookService.getGBActivityRowsForLearner(lessonID, userID, - currentUserDTO.getTimeZone()); - } else if (view == GBGridView.MON_ACTIVITY) { - gradebookActivityDTOs = gradebookService.getGBActivityRowsForLesson(lessonID, currentUserDTO.getTimeZone(), - true); - } - - if ((sortBy == null) || sortBy.equals("")) { - sortBy = GradebookConstants.PARAM_START_DATE; - } - - String ret = GradebookUtil.toGridXML(gradebookActivityDTOs, view, sortBy, isSearch, searchField, searchOper, - searchString, sortOrder, rowLimit, page); - - response.setContentType("text/xml; charset=utf-8"); - return ret; - } - - @RequestMapping("/getActivityArchiveGridData") - @ResponseBody - public String getActivityArchiveGridData(HttpServletRequest request, HttpServletResponse response) - throws Exception { - GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); - - Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - Long activityID = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID); - if (!securityService.isLessonParticipant(lessonID, getUser().getUserID(), "get activity archive gradebook data", - false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a learner in the lesson"); - return null; - } - - // Getting userID param, it is passed differently from different views - UserDTO currentUserDTO = getUser(); - Integer userID = null; - if (view == GBGridView.MON_USER || view == GBGridView.MON_ACTIVITY) { - userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); - } else if (view == GBGridView.LRN_ACTIVITY) { - if (currentUserDTO != null) { - userID = currentUserDTO.getUserID(); - } - } - - List gradebookActivityDTOs = new ArrayList(); - - // Get the user gradebook list from the db - // A slightly different list is needed for userview or activity view - if ((view == GBGridView.MON_USER) || (view == GBGridView.LRN_ACTIVITY) || (view == GBGridView.MON_ACTIVITY)) {//2nd level && from personal marks page (2nd level or 1st) - gradebookActivityDTOs = gradebookService.getGBActivityArchiveRowsForLearner(activityID, userID, - currentUserDTO.getTimeZone()); - } - - String ret = GradebookUtil.toGridXML(gradebookActivityDTOs, view, GradebookConstants.PARAM_ID, false, null, - null, null, GradebookConstants.SORT_DESC, 100, 1); - - response.setContentType("text/xml; charset=utf-8"); - return ret; - } - - @SuppressWarnings("unchecked") - @RequestMapping("/getLessonCompleteGridData") - @ResponseBody - public String getLessonCompleteGridData(HttpServletRequest request, HttpServletResponse response) throws Exception { - // Getting the params passed in from the jqGrid - Long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - UserDTO currentUserDTO = getUser(); - Integer userId = currentUserDTO.getUserID(); - if (!securityService.isLessonParticipant(lessonId, userId, "get lesson complete gradebook data", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a learner in the lesson"); - } - - List gradebookActivityDTOs = gradebookService.getGBLessonComplete(lessonId, userId); - - ObjectNode resultJSON = JsonNodeFactory.instance.objectNode(); - resultJSON.put(CommonConstants.ELEMENT_RECORDS, gradebookActivityDTOs.size()); - - ArrayNode rowsJSON = JsonNodeFactory.instance.arrayNode(); - for (GradebookGridRowDTO gradebookActivityDTO : gradebookActivityDTOs) { - ObjectNode rowJSON = JsonNodeFactory.instance.objectNode(); - String id = gradebookActivityDTO.getId(); - String[] idParts = id.split("_"); - if (idParts.length > 1) { - // if activity is grouped, use just the real activity ID and leave out group ID - // as we know there will be no ID clash in this single learner gradebook table - id = idParts[0]; - } - rowJSON.put(GradebookConstants.ELEMENT_ID, id); - - ArrayNode cellJSON = JsonNodeFactory.instance.arrayNode(); - cellJSON.add(gradebookActivityDTO.getRowName()); - cellJSON.add(gradebookActivityDTO.getStatus()); - cellJSON.add(gradebookActivityDTO.getAverageMark() == null ? GradebookConstants.CELL_EMPTY - : GradebookUtil.niceFormatting(gradebookActivityDTO.getAverageMark())); - cellJSON.add(gradebookActivityDTO.getMark() == null ? GradebookConstants.CELL_EMPTY - : GradebookUtil.niceFormatting(gradebookActivityDTO.getMark())); - - rowJSON.set(CommonConstants.ELEMENT_CELL, cellJSON); - rowsJSON.add(rowJSON); - } - resultJSON.set(CommonConstants.ELEMENT_ROWS, rowsJSON); - - // make a mapping of activity ID -> URL, same as in progress bar - ObjectNode activityURLJSON = JsonNodeFactory.instance.objectNode(); - Object[] ret = learnerService.getStructuredActivityURLs(userId, lessonId); - for (ActivityURL activity : (List) ret[0]) { - String url = activity.getUrl(); - if (url != null) { - if (url.startsWith("learner.do")) { - url = "learning/" + url; - } - String serverUrl = Configuration.get(ConfigurationKeys.SERVER_URL); - if (!url.startsWith(serverUrl)) { - // monitor mode URLs should be prepended with server URL - url = serverUrl + url; - } - activityURLJSON.put(activity.getActivityId().toString(), activity.getUrl()); - } - } - resultJSON.set("urls", activityURLJSON); - - boolean isWeighted = gradebookService.isWeightedMarks(lessonId); - GradebookUserLesson gradebookUserLesson = gradebookService.getGradebookUserLesson(lessonId, userId); - resultJSON.put("learnerLessonMark", - gradebookUserLesson == null || gradebookUserLesson.getMark() == null ? GradebookConstants.CELL_EMPTY - : GradebookUtil.niceFormatting(gradebookUserLesson.getMark(), isWeighted)); - Double averageLessonMark = gradebookService.getAverageMarkForLesson(lessonId); - resultJSON.put("averageLessonMark", averageLessonMark == null ? GradebookConstants.CELL_EMPTY - : GradebookUtil.niceFormatting(averageLessonMark, isWeighted)); - - response.setContentType("application/json;charset=utf-8"); - return resultJSON.toString(); - } - - /** - * Returns an xml representation of the user grid for gradebook - * - * This has three modes: userView, activityView and courseMonitorView - * - * User view will get all the learners in a lesson and print their gradebook data with their mark for the entire - * lesson - * - * Activity view will take an extra parameter (activityID) and instead show the user's mark just for one activity - * - * Course monitor view gets the same as the user view, but the link is set to the lesson level gradebook instead of - * learner. - */ - @RequestMapping("/getUserGridData") - @ResponseBody - public String getUserGridData(HttpServletRequest request, HttpServletResponse response) throws Exception { - - // Getting the params passed in from the jqGrid - int page = WebUtil.readIntParam(request, CommonConstants.PARAM_PAGE); - int rowLimit = WebUtil.readIntParam(request, CommonConstants.PARAM_ROWS); - String sortOrder = WebUtil.readStrParam(request, CommonConstants.PARAM_SORD); - String sortBy = WebUtil.readStrParam(request, CommonConstants.PARAM_SIDX, true); - Boolean isSearch = WebUtil.readBooleanParam(request, GradebookConstants.PARAM_SEARCH); - String searchField = WebUtil.readStrParam(request, GradebookConstants.PARAM_SEARCH_FIELD, true); - String searchString = WebUtil.readStrParam(request, GradebookConstants.PARAM_SEARCH_STRING, true); - GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); - Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID, true); - Integer organisationID = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID, true); - UserDTO user = getUser(); - - // in case of toolbar searching (which uses different parameters than a single field searching) get those - // parameters - if (isSearch && (searchField == null)) { - searchField = GradebookConstants.PARAM_ROW_NAME; - searchString = WebUtil.readStrParam(request, GradebookConstants.PARAM_ROW_NAME, true); - } - - // Get the user gradebook list from the db - List gradebookUserDTOs = new ArrayList<>(); - - int totalUsers = 0; - // if leesonID is specified show results based on lesson - if (lessonID != null) { - if (!securityService.isLessonMonitor(lessonID, user.getUserID(), "get gradebook", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); - return null; - } - - Lesson lesson = lessonService.getLesson(lessonID); - //GBGridView.MON_USER - 1st table of gradebook lesson monitor - //GBGridView.MON_COURSE - Subgrid of 1st table of gradebook course monitor - if (view == GBGridView.MON_USER || view == GBGridView.MON_COURSE) { - gradebookUserDTOs = gradebookService.getGBUserRowsForLesson(lesson, page - 1, rowLimit, sortBy, - sortOrder, searchString, user.getTimeZone()); - totalUsers = lesson.getAllLearners().size(); - - // Subgrid of 2nd table of gradebook lesson monitor - } else if (view == GBGridView.MON_ACTIVITY) { - String rowID = WebUtil.readStrParam(request, AttributeNames.PARAM_ACTIVITY_ID); - - Long activityID = null; - - // Splitting the rowID param to get the activity/group id pair - String[] split = rowID.split("_"); - if (split.length == 2) { - activityID = Long.parseLong(split[0]); - } else { - activityID = Long.parseLong(rowID); - } - - // Getting the group id if it is there - Long groupId = WebUtil.readLongParam(request, GradebookConstants.PARAM_GROUP_ID, true); - - Activity activity = gradebookService.getActivityById(activityID); - if ((activity != null) && (activity instanceof ToolActivity)) { - gradebookUserDTOs = gradebookService.getGBUserRowsForActivity(lesson, (ToolActivity) activity, - groupId, page - 1, rowLimit, sortBy, sortOrder, searchString, user.getTimeZone()); - - //calculate totalUsers - totalUsers = lesson.getAllLearners().size(); - if (groupId != null) { - Group group = (Group) userManagementService.findById(Group.class, groupId); - if (group != null) { - totalUsers = group.getUsers().size(); - } - } - - } else { - // return null and the grid will report an error - logger.error("No activity found for: " + activityID); - return null; - } - } - - // 2nd table of gradebook course monitor - // if organisationID is specified (but not lessonID) then show results for organisation - } else if (organisationID != null) { - if (!securityService.isGroupMonitor(organisationID, user.getUserID(), "get gradebook", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the organisation"); - return null; - } - - Organisation org = (Organisation) userManagementService.findById(Organisation.class, organisationID); - gradebookUserDTOs = gradebookService.getGBUserRowsForOrganisation(org, page - 1, rowLimit, sortOrder, - searchString); - totalUsers = gradebookService.getCountUsersByOrganisation(organisationID, searchString); - - } else { - logger.error("Missing parameters: either lessonID or organisationID should be specified."); - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing parameters"); - return null; - } - - //calculate totalPages - int totalPages = new Double( - Math.ceil(new Integer(totalUsers).doubleValue() / new Integer(rowLimit).doubleValue())).intValue(); - String ret = GradebookUtil.toGridXML(gradebookUserDTOs, page, totalPages, view); - - response.setContentType("text/xml; charset=utf-8"); - return ret; - } - - /** - * Returns an xml representation of the lesson grid for a course for gradebook - * - * This has two modes, learnerView and monitorView - * - * Learner view will get the data specific to one user - * - * Monitor will get the data average for whole lessons. - */ - @SuppressWarnings("unchecked") - @RequestMapping("/getCourseGridData") - @ResponseBody - public String getCourseGridData(HttpServletRequest request, HttpServletResponse response) throws Exception { - // Getting the params passed in from the jqGrid - int page = WebUtil.readIntParam(request, CommonConstants.PARAM_PAGE); - int rowLimit = WebUtil.readIntParam(request, CommonConstants.PARAM_ROWS); - String sortOrder = WebUtil.readStrParam(request, CommonConstants.PARAM_SORD); - String sortBy = WebUtil.readStrParam(request, CommonConstants.PARAM_SIDX, true); - Boolean isSearch = WebUtil.readBooleanParam(request, GradebookConstants.PARAM_SEARCH); - String searchField = WebUtil.readStrParam(request, GradebookConstants.PARAM_SEARCH_FIELD, true); - String searchOper = WebUtil.readStrParam(request, GradebookConstants.PARAM_SEARCH_OPERATION, true); - String searchString = WebUtil.readStrParam(request, GradebookConstants.PARAM_SEARCH_STRING, true); - GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); - Integer courseID = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID); - Organisation organisation = (Organisation) userManagementService.findById(Organisation.class, courseID); - - // in case of toolbar searching (which uses different parameters than a single field searching) get those - // parameters - if (isSearch && (searchField == null)) { - searchField = GradebookConstants.PARAM_ROW_NAME; - searchOper = GradebookConstants.SEARCH_CONTAINS; - searchString = WebUtil.readStrParam(request, GradebookConstants.PARAM_ROW_NAME, true); - } - - if (sortBy == null) { - sortBy = GradebookConstants.PARAM_ID; - } - - if (sortOrder == null) { - sortOrder = GradebookConstants.SORT_ASC; - } - - Set lessons = organisation.getLessons(); - if (lessons == null) { - return null; - } - - User user; - User viewer = getRealUser(); - if (view == GBGridView.MON_USER) { - Integer userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); - user = (User) userManagementService.findById(User.class, userID); - } else { - user = getRealUser(); - } - - //permission check - if (view == GBGridView.MON_USER) { - if (!securityService.isGroupMonitor(courseID, viewer.getUserId(), "get course gradebook", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the organisation"); - return null; - } - - } else if (view == GBGridView.MON_COURSE || view == GBGridView.LIST) { - if (!securityService.hasOrgRole(courseID, viewer.getUserId(), - new String[] { Role.GROUP_MANAGER}, "get course gradebook", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, - "User is not a group manager or admin in the organisation"); - return null; - } - - } else if (view == GBGridView.LRN_COURSE) { - if (!securityService.hasOrgRole(courseID, viewer.getUserId(), new String[] { Role.LEARNER }, - "get course gradebook for learner", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a learner in the organisation"); - return null; - } - - } else { - return null; - } - - if ((organisation == null) || (user == null) || (viewer == null)) { - // Grid will handle error, just log and return null - logger.error("Error: request for course gradebook data with null course or user. CourseID: " + courseID); - return null; - } - List gradebookLessonDTOs = gradebookService.getGBLessonRows(organisation, user, viewer, - view, page - 1, rowLimit, sortBy, sortOrder, searchString, getUser().getTimeZone()); - - String ret; - if (view == GBGridView.MON_COURSE || view == GBGridView.LIST) { - int totalPages = new Double( - Math.ceil(new Integer(lessons.size()).doubleValue() / new Integer(rowLimit).doubleValue())) - .intValue(); - ret = GradebookUtil.toGridXML(gradebookLessonDTOs, page, totalPages, view); - - } else { - ret = GradebookUtil.toGridXML(gradebookLessonDTOs, view, sortBy, isSearch, searchField, searchOper, - searchString, sortOrder, rowLimit, page); - } - - response.setContentType("text/xml; charset=utf-8"); - return ret; - } - - /** - * Gets the total mark for a user's lesson and writes the result in the response. - */ - @RequestMapping("/getLessonMarkAggregate") - @ResponseBody - public String getLessonMarkAggregate(HttpServletRequest request, HttpServletResponse response) throws Exception { - Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - Integer userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); - - if (getUser().getUserID().equals(userID)) { - if (!securityService.isLessonParticipant(lessonID, userID, "get lesson mark aggregate", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a participant in the lesson"); - return null; - } - } else { - if (!securityService.isLessonMonitor(lessonID, getUser().getUserID(), "get lesson mark aggregate", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); - return null; - } - } - - Lesson lesson = lessonService.getLesson(lessonID); - User learner = (User) userManagementService.findById(User.class, userID); - - if ((lesson != null) && (learner != null)) { - GradebookUserLesson lessonMark = gradebookService.getGradebookUserLesson(lessonID, userID); - if (lessonMark.getMark() != null) { - response.setContentType("text/plain; charset=utf-8"); - - return GradebookUtil.niceFormatting(lessonMark.getMark()); - } - } else { - // Grid will handle error, just log and return null - logger.error("Error: request for course gradebook data with null user or lesson. lessonID: " + lessonID); - } - return null; - } - - /** - * Gets the average mark for an activity and writes the result in the response - */ - @SuppressWarnings("unchecked") - @RequestMapping("/getActivityMarkAverage") - @ResponseBody - public String getActivityMarkAverage(HttpServletRequest request, HttpServletResponse response) throws Exception { - String rowID = WebUtil.readStrParam(request, AttributeNames.PARAM_ACTIVITY_ID); - - Long activityID = null; - Long groupID = null; - - // Splitting the rowID param to get the activity/group id pair - String[] split = rowID.split("_"); - if (split.length == 2) { - activityID = Long.parseLong(split[0]); - groupID = Long.parseLong(split[1]); - } else { - activityID = Long.parseLong(rowID); - } - - Activity activity = gradebookService.getActivityById(activityID); - if (activity == null) { - logger.error("Activity with ID: " + activityID + " could not be found when getting activity mark average"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing parameters"); - return null; - } - Integer userID = getUser().getUserID(); - for (Lesson lesson : (Set) activity.getLearningDesign().getLessons()) { - if (!securityService.isLessonMonitor(lesson.getLessonId(), userID, "get activity mark average", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); - return null; - } - } - - Double averageMark = gradebookService.getAverageMarkForActivity(activityID, groupID); - response.setContentType("text/plain, charset=utf-8"); - if (averageMark != null) { - return GradebookUtil.niceFormatting(averageMark); - - } else { - return GradebookConstants.CELL_EMPTY; - } - } - - /** - * Gets the average mark for lesson and writes the result in the response - */ - @RequestMapping("/getAverageMarkForLesson") - @ResponseBody - public String getAverageMarkForLesson(HttpServletRequest request, HttpServletResponse response) throws Exception { - Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); - if (!securityService.isLessonMonitor(lessonID, getUser().getUserID(), "get lesson mark average", false)) { - response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); - return null; - } - - Double averageMark = gradebookService.getAverageMarkForLesson(lessonID); - - response.setContentType("text/plain; charset=utf-8"); - if (averageMark != null) { - return GradebookUtil.niceFormatting(averageMark); - - } else { - return GradebookConstants.CELL_EMPTY; - } - } - - private UserDTO getUser() { - HttpSession ss = SessionManager.getSession(); - return (UserDTO) ss.getAttribute(AttributeNames.USER); - } - - private User getRealUser() { - UserDTO userDTO = getUser(); - if (userDTO != null) { - return userManagementService.getUserByLogin(userDTO.getLogin()); - } else { - return null; - } - } - +/**************************************************************** + * Copyright (C) 2008 LAMS Foundation (http://lamsfoundation.org) + * ============================================================= + * License Information: http://lamsfoundation.org/licensing/lams/2.0/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA + * + * http://www.gnu.org/licenses/gpl.txt + * **************************************************************** + */ + +package org.lamsfoundation.lams.gradebook.web.controller; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.gradebook.GradebookUserLesson; +import org.lamsfoundation.lams.gradebook.dto.GBLessonGridRowDTO; +import org.lamsfoundation.lams.gradebook.dto.GBUserGridRowDTO; +import org.lamsfoundation.lams.gradebook.dto.GradebookGridRowDTO; +import org.lamsfoundation.lams.gradebook.service.IGradebookFullService; +import org.lamsfoundation.lams.gradebook.util.GBGridView; +import org.lamsfoundation.lams.gradebook.util.GradebookConstants; +import org.lamsfoundation.lams.gradebook.util.GradebookUtil; +import org.lamsfoundation.lams.learning.service.ILearnerService; +import org.lamsfoundation.lams.learningdesign.Activity; +import org.lamsfoundation.lams.learningdesign.Group; +import org.lamsfoundation.lams.learningdesign.ToolActivity; +import org.lamsfoundation.lams.learningdesign.dto.ActivityURL; +import org.lamsfoundation.lams.lesson.Lesson; +import org.lamsfoundation.lams.lesson.service.ILessonService; +import org.lamsfoundation.lams.security.ISecurityService; +import org.lamsfoundation.lams.usermanagement.Organisation; +import org.lamsfoundation.lams.usermanagement.Role; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; +import org.lamsfoundation.lams.util.CommonConstants; +import org.lamsfoundation.lams.util.Configuration; +import org.lamsfoundation.lams.util.ConfigurationKeys; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Handles the general requests for content in gradebook + * + * @author lfoxton + */ +@Controller +@RequestMapping("/gradebook") +public class GradebookController { + private static Logger logger = Logger.getLogger(GradebookController.class); + + @Autowired + private IGradebookFullService gradebookService; + @Autowired + private IUserManagementService userManagementService; + @Autowired + private ILessonService lessonService; + @Autowired + private ISecurityService securityService; + @Autowired + private ILearnerService learnerService; + + @RequestMapping("") + @ResponseBody + public void unspecified() throws Exception { + } + + /** + * Returns an xml representation of the activity grid for gradebook + * + * This has two modes, userView and activityView + * + * User view will get the grid data for a specified user, which is all their activity marks/outputs etc + * + * Activity view will get the grid data for all activities, without user info, instead there is an average mark for + * each activity. + */ + @RequestMapping("/getActivityGridData") + @ResponseBody + public String getActivityGridData(HttpServletRequest request, HttpServletResponse response) throws Exception { + // Getting the params passed in from the jqGrid + int page = WebUtil.readIntParam(request, CommonConstants.PARAM_PAGE); + int rowLimit = WebUtil.readIntParam(request, CommonConstants.PARAM_ROWS); + String sortOrder = WebUtil.readStrParam(request, CommonConstants.PARAM_SORD); + String sortBy = WebUtil.readStrParam(request, CommonConstants.PARAM_SIDX, true); + Boolean isSearch = WebUtil.readBooleanParam(request, CommonConstants.PARAM_SEARCH); + String searchField = WebUtil.readStrParam(request, CommonConstants.PARAM_SEARCH_FIELD, true); + String searchOper = WebUtil.readStrParam(request, CommonConstants.PARAM_SEARCH_OPERATION, true); + String searchString = WebUtil.readStrParam(request, CommonConstants.PARAM_SEARCH_STRING, true); + GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); + + Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); + if (!securityService.isLessonParticipant(lessonID, getUser().getUserID(), "get activity gradebook data", + false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a learner in the lesson"); + return null; + } + + // Getting userID param, it is passed differently from different views + UserDTO currentUserDTO = getUser(); + Integer userID = null; + if (view == GBGridView.MON_USER) { + userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); + } else if (view == GBGridView.LRN_ACTIVITY) { + if (currentUserDTO != null) { + userID = currentUserDTO.getUserID(); + } + } + + List gradebookActivityDTOs = new ArrayList<>(); + + // Get the user gradebook list from the db + // A slightly different list is needed for userview or activity view + if ((view == GBGridView.MON_USER) || (view == GBGridView.LRN_ACTIVITY)) {//2nd level && from personal marks page (2nd level or 1st) + gradebookActivityDTOs = gradebookService.getGBActivityRowsForLearner(lessonID, userID, + currentUserDTO.getTimeZone()); + } else if (view == GBGridView.MON_ACTIVITY) { + gradebookActivityDTOs = gradebookService.getGBActivityRowsForLesson(lessonID, currentUserDTO.getTimeZone(), + true); + } + + if ((sortBy == null) || sortBy.equals("")) { + sortBy = GradebookConstants.PARAM_START_DATE; + } + + String ret = GradebookUtil.toGridXML(gradebookActivityDTOs, view, sortBy, isSearch, searchField, searchOper, + searchString, sortOrder, rowLimit, page); + + response.setContentType("text/xml; charset=utf-8"); + return ret; + } + + @RequestMapping("/getActivityArchiveGridData") + @ResponseBody + public String getActivityArchiveGridData(HttpServletRequest request, HttpServletResponse response) + throws Exception { + GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); + + Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); + Long activityID = WebUtil.readLongParam(request, AttributeNames.PARAM_ACTIVITY_ID); + if (!securityService.isLessonParticipant(lessonID, getUser().getUserID(), "get activity archive gradebook data", + false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a learner in the lesson"); + return null; + } + + // Getting userID param, it is passed differently from different views + UserDTO currentUserDTO = getUser(); + Integer userID = null; + if (view == GBGridView.MON_USER || view == GBGridView.MON_ACTIVITY) { + userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); + } else if (view == GBGridView.LRN_ACTIVITY) { + if (currentUserDTO != null) { + userID = currentUserDTO.getUserID(); + } + } + + List gradebookActivityDTOs = new ArrayList<>(); + + // Get the user gradebook list from the db + // A slightly different list is needed for userview or activity view + if ((view == GBGridView.MON_USER) || (view == GBGridView.LRN_ACTIVITY) || (view == GBGridView.MON_ACTIVITY)) {//2nd level && from personal marks page (2nd level or 1st) + gradebookActivityDTOs = gradebookService.getGBActivityArchiveRowsForLearner(activityID, userID, + currentUserDTO.getTimeZone()); + } + + String ret = GradebookUtil.toGridXML(gradebookActivityDTOs, view, GradebookConstants.PARAM_ID, false, null, + null, null, GradebookConstants.SORT_DESC, 100, 1); + + response.setContentType("text/xml; charset=utf-8"); + return ret; + } + + @SuppressWarnings("unchecked") + @RequestMapping("/getLessonCompleteGridData") + @ResponseBody + public String getLessonCompleteGridData(HttpServletRequest request, HttpServletResponse response) throws Exception { + // Getting the params passed in from the jqGrid + Long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); + UserDTO currentUserDTO = getUser(); + Integer userId = currentUserDTO.getUserID(); + if (!securityService.isLessonParticipant(lessonId, userId, "get lesson complete gradebook data", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a learner in the lesson"); + } + + List gradebookActivityDTOs = gradebookService.getGBLessonComplete(lessonId, userId); + + ObjectNode resultJSON = JsonNodeFactory.instance.objectNode(); + resultJSON.put(CommonConstants.ELEMENT_RECORDS, gradebookActivityDTOs.size()); + + ArrayNode rowsJSON = JsonNodeFactory.instance.arrayNode(); + for (GradebookGridRowDTO gradebookActivityDTO : gradebookActivityDTOs) { + ObjectNode rowJSON = JsonNodeFactory.instance.objectNode(); + String id = gradebookActivityDTO.getId(); + String[] idParts = id.split("_"); + if (idParts.length > 1) { + // if activity is grouped, use just the real activity ID and leave out group ID + // as we know there will be no ID clash in this single learner gradebook table + id = idParts[0]; + } + rowJSON.put(GradebookConstants.ELEMENT_ID, id); + + ArrayNode cellJSON = JsonNodeFactory.instance.arrayNode(); + cellJSON.add(gradebookActivityDTO.getRowName()); + cellJSON.add(gradebookActivityDTO.getStatus()); + cellJSON.add(gradebookActivityDTO.getAverageMark() == null ? GradebookConstants.CELL_EMPTY + : GradebookUtil.niceFormatting(gradebookActivityDTO.getAverageMark())); + cellJSON.add(gradebookActivityDTO.getMark() == null ? GradebookConstants.CELL_EMPTY + : GradebookUtil.niceFormatting(gradebookActivityDTO.getMark())); + + rowJSON.set(CommonConstants.ELEMENT_CELL, cellJSON); + rowsJSON.add(rowJSON); + } + resultJSON.set(CommonConstants.ELEMENT_ROWS, rowsJSON); + + // make a mapping of activity ID -> URL, same as in progress bar + ObjectNode activityURLJSON = JsonNodeFactory.instance.objectNode(); + Object[] ret = learnerService.getStructuredActivityURLs(userId, lessonId); + for (ActivityURL activity : (List) ret[0]) { + String url = activity.getUrl(); + if (url != null) { + if (url.startsWith("learner.do")) { + url = "learning/" + url; + } + String serverUrl = Configuration.get(ConfigurationKeys.SERVER_URL); + if (!url.startsWith(serverUrl)) { + // monitor mode URLs should be prepended with server URL + url = serverUrl + url; + } + activityURLJSON.put(activity.getActivityId().toString(), activity.getUrl()); + } + } + resultJSON.set("urls", activityURLJSON); + + boolean isWeighted = gradebookService.isWeightedMarks(lessonId); + GradebookUserLesson gradebookUserLesson = gradebookService.getGradebookUserLesson(lessonId, userId); + resultJSON.put("learnerLessonMark", + gradebookUserLesson == null || gradebookUserLesson.getMark() == null ? GradebookConstants.CELL_EMPTY + : GradebookUtil.niceFormatting(gradebookUserLesson.getMark(), isWeighted)); + Double averageLessonMark = gradebookService.getAverageMarkForLesson(lessonId); + resultJSON.put("averageLessonMark", averageLessonMark == null ? GradebookConstants.CELL_EMPTY + : GradebookUtil.niceFormatting(averageLessonMark, isWeighted)); + + response.setContentType("application/json;charset=utf-8"); + return resultJSON.toString(); + } + + /** + * Returns an xml representation of the user grid for gradebook + * + * This has three modes: userView, activityView and courseMonitorView + * + * User view will get all the learners in a lesson and print their gradebook data with their mark for the entire + * lesson + * + * Activity view will take an extra parameter (activityID) and instead show the user's mark just for one activity + * + * Course monitor view gets the same as the user view, but the link is set to the lesson level gradebook instead of + * learner. + */ + @RequestMapping("/getUserGridData") + @ResponseBody + public String getUserGridData(HttpServletRequest request, HttpServletResponse response) throws Exception { + + // Getting the params passed in from the jqGrid + int page = WebUtil.readIntParam(request, CommonConstants.PARAM_PAGE); + int rowLimit = WebUtil.readIntParam(request, CommonConstants.PARAM_ROWS); + String sortOrder = WebUtil.readStrParam(request, CommonConstants.PARAM_SORD); + String sortBy = WebUtil.readStrParam(request, CommonConstants.PARAM_SIDX, true); + Boolean isSearch = WebUtil.readBooleanParam(request, CommonConstants.PARAM_SEARCH); + String searchField = WebUtil.readStrParam(request, CommonConstants.PARAM_SEARCH_FIELD, true); + String searchString = WebUtil.readStrParam(request, CommonConstants.PARAM_SEARCH_STRING, true); + GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); + Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID, true); + Integer organisationID = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID, true); + UserDTO user = getUser(); + + // in case of toolbar searching (which uses different parameters than a single field searching) get those + // parameters + if (isSearch && (searchField == null)) { + searchField = GradebookConstants.PARAM_ROW_NAME; + searchString = WebUtil.readStrParam(request, GradebookConstants.PARAM_ROW_NAME, true); + } + + // Get the user gradebook list from the db + List gradebookUserDTOs = new ArrayList<>(); + + int totalUsers = 0; + // if leesonID is specified show results based on lesson + if (lessonID != null) { + if (!securityService.isLessonMonitor(lessonID, user.getUserID(), "get gradebook", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); + return null; + } + + Lesson lesson = lessonService.getLesson(lessonID); + //GBGridView.MON_USER - 1st table of gradebook lesson monitor + //GBGridView.MON_COURSE - Subgrid of 1st table of gradebook course monitor + if (view == GBGridView.MON_USER || view == GBGridView.MON_COURSE) { + gradebookUserDTOs = gradebookService.getGBUserRowsForLesson(lesson, page - 1, rowLimit, sortBy, + sortOrder, searchString, user.getTimeZone()); + totalUsers = lesson.getAllLearners().size(); + + // Subgrid of 2nd table of gradebook lesson monitor + } else if (view == GBGridView.MON_ACTIVITY) { + String rowID = WebUtil.readStrParam(request, AttributeNames.PARAM_ACTIVITY_ID); + + Long activityID = null; + + // Splitting the rowID param to get the activity/group id pair + String[] split = rowID.split("_"); + if (split.length == 2) { + activityID = Long.parseLong(split[0]); + } else { + activityID = Long.parseLong(rowID); + } + + // Getting the group id if it is there + Long groupId = WebUtil.readLongParam(request, GradebookConstants.PARAM_GROUP_ID, true); + + Activity activity = gradebookService.getActivityById(activityID); + if ((activity != null) && (activity instanceof ToolActivity)) { + gradebookUserDTOs = gradebookService.getGBUserRowsForActivity(lesson, (ToolActivity) activity, + groupId, page - 1, rowLimit, sortBy, sortOrder, searchString, user.getTimeZone()); + + //calculate totalUsers + totalUsers = lesson.getAllLearners().size(); + if (groupId != null) { + Group group = (Group) userManagementService.findById(Group.class, groupId); + if (group != null) { + totalUsers = group.getUsers().size(); + } + } + + } else { + // return null and the grid will report an error + logger.error("No activity found for: " + activityID); + return null; + } + } + + // 2nd table of gradebook course monitor + // if organisationID is specified (but not lessonID) then show results for organisation + } else if (organisationID != null) { + if (!securityService.isGroupMonitor(organisationID, user.getUserID(), "get gradebook", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the organisation"); + return null; + } + + Organisation org = (Organisation) userManagementService.findById(Organisation.class, organisationID); + gradebookUserDTOs = gradebookService.getGBUserRowsForOrganisation(org, page - 1, rowLimit, sortOrder, + searchString); + totalUsers = gradebookService.getCountUsersByOrganisation(organisationID, searchString); + + } else { + logger.error("Missing parameters: either lessonID or organisationID should be specified."); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing parameters"); + return null; + } + + //calculate totalPages + int totalPages = new Double( + Math.ceil(new Integer(totalUsers).doubleValue() / new Integer(rowLimit).doubleValue())).intValue(); + String ret = GradebookUtil.toGridXML(gradebookUserDTOs, page, totalPages, view); + + response.setContentType("text/xml; charset=utf-8"); + return ret; + } + + /** + * Returns an xml representation of the lesson grid for a course for gradebook + * + * This has two modes, learnerView and monitorView + * + * Learner view will get the data specific to one user + * + * Monitor will get the data average for whole lessons. + */ + @SuppressWarnings("unchecked") + @RequestMapping("/getCourseGridData") + @ResponseBody + public String getCourseGridData(HttpServletRequest request, HttpServletResponse response) throws Exception { + // Getting the params passed in from the jqGrid + int page = WebUtil.readIntParam(request, CommonConstants.PARAM_PAGE); + int rowLimit = WebUtil.readIntParam(request, CommonConstants.PARAM_ROWS); + String sortOrder = WebUtil.readStrParam(request, CommonConstants.PARAM_SORD); + String sortBy = WebUtil.readStrParam(request, CommonConstants.PARAM_SIDX, true); + Boolean isSearch = WebUtil.readBooleanParam(request, CommonConstants.PARAM_SEARCH); + String searchField = WebUtil.readStrParam(request, CommonConstants.PARAM_SEARCH_FIELD, true); + String searchOper = WebUtil.readStrParam(request, CommonConstants.PARAM_SEARCH_OPERATION, true); + String searchString = WebUtil.readStrParam(request, CommonConstants.PARAM_SEARCH_STRING, true); + GBGridView view = GradebookUtil.readGBGridViewParam(request, GradebookConstants.PARAM_VIEW, false); + Integer courseID = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID); + Organisation organisation = (Organisation) userManagementService.findById(Organisation.class, courseID); + + // in case of toolbar searching (which uses different parameters than a single field searching) get those + // parameters + if (isSearch && (searchField == null)) { + searchField = GradebookConstants.PARAM_ROW_NAME; + searchOper = GradebookConstants.SEARCH_CONTAINS; + searchString = WebUtil.readStrParam(request, GradebookConstants.PARAM_ROW_NAME, true); + } + + if (sortBy == null) { + sortBy = GradebookConstants.PARAM_ID; + } + + if (sortOrder == null) { + sortOrder = GradebookConstants.SORT_ASC; + } + + Set lessons = organisation.getLessons(); + if (lessons == null) { + return null; + } + + User user; + User viewer = getRealUser(); + if (view == GBGridView.MON_USER) { + Integer userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); + user = (User) userManagementService.findById(User.class, userID); + } else { + user = getRealUser(); + } + + //permission check + if (view == GBGridView.MON_USER) { + if (!securityService.isGroupMonitor(courseID, viewer.getUserId(), "get course gradebook", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the organisation"); + return null; + } + + } else if (view == GBGridView.MON_COURSE || view == GBGridView.LIST) { + if (!securityService.hasOrgRole(courseID, viewer.getUserId(), new String[] { Role.GROUP_MANAGER }, + "get course gradebook", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, + "User is not a group manager or admin in the organisation"); + return null; + } + + } else if (view == GBGridView.LRN_COURSE) { + if (!securityService.hasOrgRole(courseID, viewer.getUserId(), new String[] { Role.LEARNER }, + "get course gradebook for learner", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a learner in the organisation"); + return null; + } + + } else { + return null; + } + + if ((organisation == null) || (user == null) || (viewer == null)) { + // Grid will handle error, just log and return null + logger.error("Error: request for course gradebook data with null course or user. CourseID: " + courseID); + return null; + } + List gradebookLessonDTOs = gradebookService.getGBLessonRows(organisation, user, viewer, + view, page - 1, rowLimit, sortBy, sortOrder, searchString, getUser().getTimeZone()); + + String ret; + if (view == GBGridView.MON_COURSE || view == GBGridView.LIST) { + int totalPages = new Double( + Math.ceil(new Integer(lessons.size()).doubleValue() / new Integer(rowLimit).doubleValue())) + .intValue(); + ret = GradebookUtil.toGridXML(gradebookLessonDTOs, page, totalPages, view); + + } else { + ret = GradebookUtil.toGridXML(gradebookLessonDTOs, view, sortBy, isSearch, searchField, searchOper, + searchString, sortOrder, rowLimit, page); + } + + response.setContentType("text/xml; charset=utf-8"); + return ret; + } + + /** + * Gets the total mark for a user's lesson and writes the result in the response. + */ + @RequestMapping("/getLessonMarkAggregate") + @ResponseBody + public String getLessonMarkAggregate(HttpServletRequest request, HttpServletResponse response) throws Exception { + Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); + Integer userID = WebUtil.readIntParam(request, GradebookConstants.PARAM_USERID); + + if (getUser().getUserID().equals(userID)) { + if (!securityService.isLessonParticipant(lessonID, userID, "get lesson mark aggregate", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a participant in the lesson"); + return null; + } + } else { + if (!securityService.isLessonMonitor(lessonID, getUser().getUserID(), "get lesson mark aggregate", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); + return null; + } + } + + Lesson lesson = lessonService.getLesson(lessonID); + User learner = (User) userManagementService.findById(User.class, userID); + + if ((lesson != null) && (learner != null)) { + GradebookUserLesson lessonMark = gradebookService.getGradebookUserLesson(lessonID, userID); + if (lessonMark.getMark() != null) { + response.setContentType("text/plain; charset=utf-8"); + + return GradebookUtil.niceFormatting(lessonMark.getMark()); + } + } else { + // Grid will handle error, just log and return null + logger.error("Error: request for course gradebook data with null user or lesson. lessonID: " + lessonID); + } + return null; + } + + /** + * Gets the average mark for an activity and writes the result in the response + */ + @SuppressWarnings("unchecked") + @RequestMapping("/getActivityMarkAverage") + @ResponseBody + public String getActivityMarkAverage(HttpServletRequest request, HttpServletResponse response) throws Exception { + String rowID = WebUtil.readStrParam(request, AttributeNames.PARAM_ACTIVITY_ID); + + Long activityID = null; + Long groupID = null; + + // Splitting the rowID param to get the activity/group id pair + String[] split = rowID.split("_"); + if (split.length == 2) { + activityID = Long.parseLong(split[0]); + groupID = Long.parseLong(split[1]); + } else { + activityID = Long.parseLong(rowID); + } + + Activity activity = gradebookService.getActivityById(activityID); + if (activity == null) { + logger.error("Activity with ID: " + activityID + " could not be found when getting activity mark average"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing parameters"); + return null; + } + Integer userID = getUser().getUserID(); + for (Lesson lesson : activity.getLearningDesign().getLessons()) { + if (!securityService.isLessonMonitor(lesson.getLessonId(), userID, "get activity mark average", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); + return null; + } + } + + Double averageMark = gradebookService.getAverageMarkForActivity(activityID, groupID); + response.setContentType("text/plain, charset=utf-8"); + if (averageMark != null) { + return GradebookUtil.niceFormatting(averageMark); + + } else { + return GradebookConstants.CELL_EMPTY; + } + } + + /** + * Gets the average mark for lesson and writes the result in the response + */ + @RequestMapping("/getAverageMarkForLesson") + @ResponseBody + public String getAverageMarkForLesson(HttpServletRequest request, HttpServletResponse response) throws Exception { + Long lessonID = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); + if (!securityService.isLessonMonitor(lessonID, getUser().getUserID(), "get lesson mark average", false)) { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "User is not a monitor in the lesson"); + return null; + } + + Double averageMark = gradebookService.getAverageMarkForLesson(lessonID); + + response.setContentType("text/plain; charset=utf-8"); + if (averageMark != null) { + return GradebookUtil.niceFormatting(averageMark); + + } else { + return GradebookConstants.CELL_EMPTY; + } + } + + private UserDTO getUser() { + HttpSession ss = SessionManager.getSession(); + return (UserDTO) ss.getAttribute(AttributeNames.USER); + } + + private User getRealUser() { + UserDTO userDTO = getUser(); + if (userDTO != null) { + return userManagementService.getUserByLogin(userDTO.getLogin()); + } else { + return null; + } + } + } \ No newline at end of file