Index: 3rdParty_sources/versions.txt =================================================================== diff -u -rdd64f16fdf89f789b8c2179d421290dcabf15835 -r266434d5ec15cc4026c93a740c3110c046b1d88a --- 3rdParty_sources/versions.txt (.../versions.txt) (revision dd64f16fdf89f789b8c2179d421290dcabf15835) +++ 3rdParty_sources/versions.txt (.../versions.txt) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -9,31 +9,36 @@ CKEditor Java 2.6 -Apache HttpClient 4.2.1 +Apache HttpClient 4.5 -Apache HttpCore 4.2.1 +Apache HttpCore 4.4.1 +Apache POI 3.16 + +Commons Digester 2.1 + +Commons Fileupload 1.3.3 + Commons Lang 2.6 Commons IO 2.4 -gson 2.2.4 +Commons Validator 1.6 -Hibernate Core 4.3.7 +Hibernate Core 5.0.10 httpunit 1.7 -JBoss Web 2.1.3 +Jackson 2.7.4 +jLaTexMath 1.0.6 + jsonwebtoken 0.9.0 JSP API 2.3 -lucene 2.4.0 -contains lucene-snowball 2.4.0 +MySQL Connector/J 5.1.46 -MySQL Connector/J 5.1.38 - oauth 20100527 oauth-provider 20100527 @@ -42,20 +47,20 @@ openws 1.5.0 -Quartz 2.2.1 +Quartz 2.2.3 Servlet API 3.1 -Spring 4.0.6 +Spring 4.3.10 Struts 1.2.9 -Undertow core 1.1.8 +Undertow core 1.4.0 -Undertow servlet 1.1.8 +Undertow servlet 1.4.0 xmltooling 1.4.0 XStream 1.5.0 -websocket api_1.1_spec-1.1.0.Final \ No newline at end of file +websocket api_1.1_spec-1.1.1.Final \ No newline at end of file Index: lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/OrganisationAction.java =================================================================== diff -u -r68f6bb788ddb8f2df61d1a2437a9d7db8d6a846f -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/OrganisationAction.java (.../OrganisationAction.java) (revision 68f6bb788ddb8f2df61d1a2437a9d7db8d6a846f) +++ lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/OrganisationAction.java (.../OrganisationAction.java) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -36,7 +36,6 @@ import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.DynaActionForm; -import org.apache.tomcat.util.json.JSONException; import org.lamsfoundation.lams.admin.service.AdminServiceProxy; import org.lamsfoundation.lams.lesson.Lesson; import org.lamsfoundation.lams.usermanagement.Organisation; @@ -179,7 +178,7 @@ @SuppressWarnings("unchecked") public ActionForward deleteAllLessons(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException, JSONException { + HttpServletResponse response) throws IOException { Integer userID = getUserID(); Integer limit = WebUtil.readIntParam(request, "limit", true); Integer organisationId = WebUtil.readIntParam(request, "orgId"); Index: lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/PolicyManagementAction.java =================================================================== diff -u --- lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/PolicyManagementAction.java (revision 0) +++ lams_admin/src/java/org/lamsfoundation/lams/admin/web/action/PolicyManagementAction.java (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -0,0 +1,295 @@ +package org.lamsfoundation.lams.admin.web.action; + +import java.io.IOException; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.apache.struts.action.Action; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.DynaActionForm; +import org.lamsfoundation.lams.policies.Policy; +import org.lamsfoundation.lams.policies.dto.UserPolicyConsentDTO; +import org.lamsfoundation.lams.policies.service.IPolicyService; +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.DateUtil; +import org.lamsfoundation.lams.util.WebUtil; +import org.lamsfoundation.lams.web.session.SessionManager; +import org.lamsfoundation.lams.web.util.AttributeNames; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; +import org.springframework.web.util.HtmlUtils; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Handles Policy management requests. + * + * @author Andrey Balan + */ +public class PolicyManagementAction extends Action { + + private static Logger log = Logger.getLogger(PolicyManagementAction.class); + private static IPolicyService policyService = null; + private static IUserManagementService userManagementService = null; + + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + + if (policyService == null) { + WebApplicationContext wac = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + policyService = (IPolicyService) wac.getBean("policyService"); + } + if (userManagementService == null) { + WebApplicationContext wac = WebApplicationContextUtils + .getRequiredWebApplicationContext(getServlet().getServletContext()); + userManagementService = (IUserManagementService) wac.getBean("userManagementService"); + } + + String method = WebUtil.readStrParam(request, "method", true); + if (StringUtils.equals(method, "list") || isCancelled(request)) { + handleListPage(request); + return mapping.findForward("policyList"); + } else if (StringUtils.equals(method, "edit")) { + return edit(mapping, form, request, response); + } else if (StringUtils.equals(method, "save")) { + return save(mapping, form, request, response); + } else if (StringUtils.equals(method, "displayUserConsents")) { + return displayUserConsents(mapping, form, request, response); + } else if (StringUtils.equals(method, "getConsentsGridData")) { + return getConsentsGridData(mapping, form, request, response); + } else if (StringUtils.equals(method, "viewPreviousVersions")) { + handleViewPreviousVersionsPage(request); + return mapping.findForward("policyList"); + } else if (StringUtils.equals(method, "togglePolicyStatus")) { + return togglePolicyStatus(mapping, form, request, response); + } + + return mapping.findForward("error"); + } + + /** + * Prepare all data for the "list" page. + */ + private void handleListPage(HttpServletRequest request) { + Collection policies = policyService.getPoliciesOfDistinctVersions(); + request.setAttribute("policies", policies); + + int userCount = userManagementService.getCountUsers(); + request.setAttribute("userCount", userCount); + } + + private ActionForward edit(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + Long policyUid = WebUtil.readLongParam(request, "policyUid", true); + if (policyUid != null && policyUid > 0) { + Policy policy = policyService.getPolicyByUid(policyUid); + if (policy != null) { + DynaActionForm policyForm = (DynaActionForm) form; + policyForm.set("policyUid", policy.getUid()); + policyForm.set("policyId", policy.getPolicyId()); + policyForm.set("policyName", policy.getPolicyName()); + policyForm.set("summary", policy.getSummary()); + policyForm.set("fullPolicy", policy.getFullPolicy()); + policyForm.set("policyTypeId", policy.getPolicyTypeId()); + policyForm.set("version", policy.getVersion()); + policyForm.set("policyStateId", policy.getPolicyStateId()); + request.setAttribute("policyForm", policyForm); + } + } + return mapping.findForward("editPolicy"); + } + + private ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + DynaActionForm policyForm = (DynaActionForm) form; + String currentDate = ZonedDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE); + + Object policyUid = policyForm.get("policyUid"); + String version = policyForm.getString("version"); + Integer policyStateId = (Integer) policyForm.get("policyStateId"); + Boolean isMinorChange = (Boolean) policyForm.get("minorChange"); + + Policy oldPolicy = (policyUid != null) && ((Long) policyUid > 0) + ? policyService.getPolicyByUid((Long) policyUid) + : null; + + // set policyId: generate Unique long ID in case of new policy and reuse existing one otherwise + Long policyId = oldPolicy == null ? policyId = UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE + : oldPolicy.getPolicyId(); + + Policy policy; + // edit existing policy only in case of minor change + if (isMinorChange) { + policy = policyService.getPolicyByUid((Long) policyUid); + + } else { + //if it's not a minor change - then instantiate a new child policy + policy = new Policy(); + + //set policy's version: if version was not changed by the user - append current date + if (oldPolicy != null && oldPolicy.getVersion().equals(version)) { + version += " " + currentDate; + } + } + + //set default version, if it's empty + if (StringUtils.isEmpty(version)) { + version = currentDate; + } + + //in case we edit existing policy and the new policy is Active - set all other policy versions to Inactive + if (oldPolicy != null && Policy.STATUS_ACTIVE.equals(policyStateId)) { + + //in case old policy was active - we only need to deactivate it, otherwise we need to find an active one from the policy family + if (Policy.STATUS_ACTIVE.equals(oldPolicy.getPolicyStateId())) { + oldPolicy.setPolicyStateId(Policy.STATUS_INACTIVE); + userManagementService.save(oldPolicy); + + } else { + List policyFamily = policyService.getPreviousVersionsPolicies(policyId); + for (Policy policyFromFamily : policyFamily) { + if (!policyFromFamily.getUid().equals(policyUid) + && Policy.STATUS_ACTIVE.equals(policyFromFamily.getPolicyStateId())) { + policyFromFamily.setPolicyStateId(Policy.STATUS_INACTIVE); + userManagementService.save(policyFromFamily); + } + } + + } + } + + policy.setPolicyId(policyId); + policy.setVersion(version); + policy.setSummary(policyForm.getString("summary")); + policy.setFullPolicy(policyForm.getString("fullPolicy")); + policy.setPolicyTypeId((Integer) policyForm.get("policyTypeId")); + policy.setPolicyStateId(policyStateId); + policy.setPolicyName(policyForm.getString("policyName")); + //set created user + Integer loggeduserId = ((UserDTO) SessionManager.getSession().getAttribute(AttributeNames.USER)).getUserID(); + User createdBy = (User) userManagementService.findById(User.class, loggeduserId); + policy.setCreatedBy(createdBy); + policy.setLastModified(new Date()); + userManagementService.save(policy); + + return mapping.findForward("policyListRedirect"); + } + + private ActionForward displayUserConsents(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + Long policyUid = WebUtil.readLongParam(request, "policyUid"); + Policy policy = policyService.getPolicyByUid(policyUid); + request.setAttribute("policy", policy); + + return mapping.findForward("userConsents"); + } + + /** + * Prepares all data for "vewPreviousVersions" page. + */ + private void handleViewPreviousVersionsPage(HttpServletRequest request) { + long policyId = WebUtil.readLongParam(request, "policyId"); + List previousVersions = policyService.getPreviousVersionsPolicies(policyId); +// remove the first one from the list +// if (previousVersion.size() > 1) { +// policyFamily.remove(policyFamily.size() - 1); +// } + request.setAttribute("policies", previousVersions); + + int userCount = userManagementService.getCountUsers(); + request.setAttribute("userCount", userCount); + + request.setAttribute("viewPreviousVersions", true); + } + + private ActionForward togglePolicyStatus(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + + long policyUid = WebUtil.readLongParam(request, "policyUid"); + policyService.togglePolicyStatus(policyUid); + + Boolean isViewPreviousVersions = WebUtil.readBooleanParam(request, "viewPreviousVersions", false); + if (isViewPreviousVersions) { + handleViewPreviousVersionsPage(request); + } else { + handleListPage(request); + } + return mapping.findForward("policyTable"); + } + + /** + */ + @SuppressWarnings("unchecked") + public ActionForward getConsentsGridData(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws IOException { + Long policyUid = WebUtil.readLongParam(request, "policyUid"); + Policy policy = policyService.getPolicyByUid(policyUid); + + // Getting the params passed in from the jqGrid + int page = WebUtil.readIntParam(request, "page"); + int rowLimit = WebUtil.readIntParam(request, "rows"); + String sortOrder = WebUtil.readStrParam(request, "sord"); + String sortBy = WebUtil.readStrParam(request, "sidx", true); + if (StringUtils.isEmpty(sortBy)) { + sortBy = "fullName"; + } + String searchString = WebUtil.readStrParam(request, "fullName", true); + + List consentDtos = policyService.getConsentDtosByPolicy(policyUid, page - 1, rowLimit, + sortBy, sortOrder, searchString); + int countUsers = userManagementService.getCountUsers(searchString); + int totalPages = new Double( + Math.ceil(new Integer(countUsers).doubleValue() / new Integer(rowLimit).doubleValue())).intValue(); + + ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); + responcedata.put("total", "" + totalPages); + responcedata.put("page", "" + page); + responcedata.put("records", "" + countUsers); + + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + for (UserPolicyConsentDTO consentDto : consentDtos) { + ArrayNode userData = JsonNodeFactory.instance.arrayNode(); + userData.add(consentDto.getUserID()); + String firstName = consentDto.getFirstName() == null ? "" : consentDto.getFirstName(); + String lastName = consentDto.getLastName() == null ? "" : consentDto.getLastName(); + String fullName = HtmlUtils.htmlEscape(lastName) + " " + HtmlUtils.htmlEscape(firstName); + userData.add(fullName); + String consentedIcon = consentDto.isConsentGivenByUser() + ? "" + : "-"; + userData.add(consentedIcon); + String dateAgreedOn = consentDto.getDateAgreedOn() == null ? "" + : DateUtil.convertToStringForJSON(consentDto.getDateAgreedOn(), request.getLocale()); + userData.add(HtmlUtils.htmlEscape(dateAgreedOn)); + + ObjectNode cellobj = JsonNodeFactory.instance.objectNode(); + cellobj.put("id", "" + consentDto.getUserID()); + cellobj.set("cell", userData); + rows.add(cellobj); + } + responcedata.put("rows", rows); + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(new String(responcedata.toString())); + return null; + } +} Index: lams_build/3rdParty.userlibraries =================================================================== diff -u -r7092d66ea24caa9e23a1dce9027c39581aeb34ff -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision 7092d66ea24caa9e23a1dce9027c39581aeb34ff) +++ lams_build/3rdParty.userlibraries (.../3rdParty.userlibraries) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -1,10 +1,6 @@ - - - - @@ -13,32 +9,28 @@ - - - - - - - - - - - - - - - - + + + + + + + + - - - - - + + + + + + + + + Index: lams_build/build.xml =================================================================== diff -u -r33d7aa31deb6606940bcd51544b17d62387777cf -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_build/build.xml (.../build.xml) (revision 33d7aa31deb6606940bcd51544b17d62387777cf) +++ lams_build/build.xml (.../build.xml) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -28,8 +28,7 @@ deploy-learning-libraries --> Deploys complex Tools lams-cruise --> Runs full LAMS redeployment lams-cruise-min-tools --> Runs full LAMS redeployment with minimal Tools set - slim-jboss --> Removes unused JBoss files - slim-jboss-revert --> Puts back JBoss files removed in slimming process + slim-wildfly --> Removes unused WidlFly files If you want to run full deployment, execute lams-cruise. @@ -381,7 +380,7 @@ dbPassword="${db.password}" dbUsername="${db.username}" dbDriverUrl="${db.url.build}" - dbDriverClass="com.mysql.jdbc.Driver" + dbDriverClass="com.mysql.cj.jdbc.Driver" /> Deploying language files @@ -496,32 +495,21 @@ - + - + - - - - - - - - - - + - - - - - - - - @@ -564,17 +544,6 @@ file="lib/json/jjwt.module.xml" overwrite="true" verbose="true" /> - - - - - - - - - - @@ -650,6 +619,7 @@ file="lib/googleauth/googleauth.module.xml" overwrite="true" verbose="true" /> + @@ -660,17 +630,6 @@ - - - - - - - - - - @@ -692,11 +651,11 @@ use them till migration to Wildfly 9.x It will be placed back if deploy-cluster is run. --> + overwrite="false" verbose="true" failonerror="false"> - + @@ -723,6 +682,7 @@ + @@ -736,6 +696,7 @@ + @@ -809,6 +770,7 @@ + @@ -837,7 +799,7 @@ - + @@ -858,30 +820,37 @@ + + + + + + + + - - - + + + + + - - - @@ -921,14 +890,17 @@ + + + Index: lams_build/conf/j2ee/jboss-deployment-structure.xml =================================================================== diff -u -r33d7aa31deb6606940bcd51544b17d62387777cf -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_build/conf/j2ee/jboss-deployment-structure.xml (.../jboss-deployment-structure.xml) (revision 33d7aa31deb6606940bcd51544b17d62387777cf) +++ lams_build/conf/j2ee/jboss-deployment-structure.xml (.../jboss-deployment-structure.xml) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -1,4 +1,4 @@ - + false @@ -30,18 +30,14 @@ - - - - @@ -53,8 +49,10 @@ + + - + Index: lams_build/lib/jdk/jdk.module.xml =================================================================== diff -u -r33d7aa31deb6606940bcd51544b17d62387777cf -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_build/lib/jdk/jdk.module.xml (.../jdk.module.xml) (revision 33d7aa31deb6606940bcd51544b17d62387777cf) +++ lams_build/lib/jdk/jdk.module.xml (.../jdk.module.xml) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -21,7 +21,7 @@ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + Index: lams_build/lib/lams/lams-central.jar =================================================================== diff -u -raa9051146a2c7e16c12ccb68a00595bc79fb2e78 -r266434d5ec15cc4026c93a740c3110c046b1d88a Binary files differ Index: lams_build/lib/lams/lams-gradebook.jar =================================================================== diff -u -r2485ce33e55a921bdcde94e4f242da5da3cf1fc4 -r266434d5ec15cc4026c93a740c3110c046b1d88a Binary files differ Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r5cf9e6a0f2d86fd8371a466a07b8c0cbf3f81cb8 -r266434d5ec15cc4026c93a740c3110c046b1d88a Binary files differ Index: lams_build/liblist.txt =================================================================== diff -u -r33d7aa31deb6606940bcd51544b17d62387777cf -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_build/liblist.txt (.../liblist.txt) (revision 33d7aa31deb6606940bcd51544b17d62387777cf) +++ lams_build/liblist.txt (.../liblist.txt) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -2,10 +2,10 @@ Folder Library Version License Vendor Description -apache-poi poi-3.10-FINAL-20140208.jar 3.10 Apache License 2.0 Apache the Java API for Microsoft Documents - poi-ooxml-3.10-FINAL-20140208.jar - poi-ooxml-schemas-3.10-FINAL-20140208.jar - xmlbeans-2.4.0.jar 2.3.0 +apache-poi poi-3.16.jar 3.16 Apache License 2.0 Apache the Java API for Microsoft Documents + poi-ooxml-3.16.jar + poi-ooxml-schemas-3.16.jar + xmlbeans-2.6.0.jar 2.6.0 autopatch autopatch-1.4.2-lams.jar 1.4.2-lams Apache License Tacit Knowledge automated Java patching system discovery-1.0.5-lams.jar 1.0.5-lams @@ -23,48 +23,38 @@ googleauth googleauth-1.1.1.jar 1.1.1 Public Domain Enrico M. Crisostomo Java server library that implements the Time-based One-time Password (TOTP) algorithm jakarta-commons commons-digester-2.1.jar 2.1 Apache Software License 2.0 Apache Software Foundation XML -> Java object mapping tool - commons-fileupload.jar 1.0 Apache Software License 1.1 Apache Software Foundation File upload component for Java servlets - commons-validator.jar 1.1.4 Apache License 2.0 The Apache Software Foundation Commons Validator + commons-fileupload-1.3.3.jar 1.3.3 Apache Software License 1.1 Apache Software Foundation File upload component for Java servlets + commons-validator-1.6.jar 1.6 Apache License 2.0 The Apache Software Foundation Commons Validator + commons-discovery-0.5.jar 0.5 Apache License 2.0 The Apache Software Foundation -jboss jbossweb.jar 2.1.3 LGPL 2.1 Apache Software Foundation SSO valve and JSON - -jlatexmath jlatexmath-1.0.3.jar 1.0.3 +jlatexmath jlatexmath-1.0.6.jar 1.0.6 json-simple json-simple-1.1.1.jar 1.1.1 Apache License 2.0 fangyidong A simple Java toolkit for JSON jsonwebtoken jjwt-0.9.0.jar 0.9.0 JWTK Apache -lucene lucene-core-2.4.0.jar 2.4.0 Apache License 2.0 Apache text search engine library - lucene-snowball-2.4.0.jar 2.4.0 +mysql mysql-connector-java-5.1.46-bin.jar 5.1.46 GPL Oracle Java connector for MySQL -mysql mysql-connector-java-5.1.38-bin.jar 5.1.31 GPL Oracle Java connector for MySQL - odmg odmg-3.0.jar 3.0 -quartz quartz-2.2.1.jar 2.2.1 Apache License 2.0 Terracotta For running scheduled jobs +quartz quartz-2.2.3.jar 2.2.3 Apache License 2.0 Terracotta For running scheduled jobs -spring spring-core-4.0.6.RELEASE.jar 4.0.6 Apache License 2.0 GoPivotal programming and configuration model for modern Java-based enterprise applications - spring-beans-4.0.6.RELEASE.jar - spring-context-4.0.6.RELEASE.jar - spring-context-support-4.0.6.RELEASE.jar - spring-expression-4.0.6.RELEASE.jar - spring-jdbc-4.0.6.RELEASE.jar - spring-orm-4.0.6.RELEASE.jar - spring-tx-4.0.6.RELEASE.jar - spring-web-4.0.6.RELEASE.jar - aopalliance.jar 1.0 Public Domain AOP Alliance +spring spring-core-4.3.10.RELEASE.jar 4.3.10 Apache License 2.0 Pivotal programming and configuration model for modern Java-based enterprise applications + spring-beans-4.3.10.RELEASE.jar + spring-context-4.3.10.RELEASE.jar + spring-context-support-4.3.10.RELEASE.jar + spring-expression-4.3.10.RELEASE.jar + spring-jdbc-4.3.10.RELEASE.jar + spring-orm-4.3.10.RELEASE.jar + spring-tx-4.3.10.RELEASE.jar + spring-web-4.3.10.RELEASE.jar struts jakarta-oro.jar 2.0.7 Apache License 2.0 Apache regular expressions struts.jar 1.2.7 Apache License 2.0 Apache Struts Framework struts-el.jar 1.2.9 Apache License 2.0 Apache Struts extensions urlrewritefilter urlrewritefilter-4.0.3.jar 4.0.3 BSD License tuckey.org Java Web Filter which allows rewriting URLs -xml-commons xml-apis.jar 1.3 - xml-apis-ext.jar 1.3 Apache License 2.0 Apache Common code and guidelines for xml projects +xstream xstream-1.5.0-SNAPSHOT.jar 1.5.0 XML serializer -xstream xmlpull-1.1.3.1.jar 1.1.3.1 - xpp3_min-1.1.4c.jar 1.1.4c - xstream-1.5.0-SNAPSHOT.jar 1.5.0 XML serializer - yuicompressor yuicompressor-2.4.9 2.4.9 BSD License YUI CSS and JS minifier Index: lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java =================================================================== diff -u -re59191f853aa9bdaf89c4e430fa9517541c073ed -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java (.../IndexAction.java) (revision e59191f853aa9bdaf89c4e430fa9517541c073ed) +++ lams_central/src/java/org/lamsfoundation/lams/web/IndexAction.java (.../IndexAction.java) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -37,9 +37,6 @@ import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.index.IndexLinkBean; import org.lamsfoundation.lams.integration.service.IIntegrationService; import org.lamsfoundation.lams.integration.service.IntegrationService; @@ -60,6 +57,10 @@ import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.util.HtmlUtils; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * * @author Fei Yang @@ -79,7 +80,7 @@ public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { - setHeaderLinks(request); + IndexAction.setHeaderLinks(request); setAdminLinks(request); // check if this is user's first login; some action (like displaying a dialog for disabling tutorials) can be @@ -121,7 +122,7 @@ return mapping.findForward("editprofile"); } else if (StringUtils.equals(method, "password")) { return mapping.findForward("password"); - } else if (StringUtils.equals(method, "portrait")) { + } else if (StringUtils.equals(method, "portrait")) { return mapping.findForward("portrait"); } else if (StringUtils.equals(method, "lessons")) { return mapping.findForward("lessons"); @@ -142,23 +143,24 @@ return null; } } - + // only show the growl warning the first time after a user has logged in & if turned on in configuration Boolean tzWarning = Configuration.getAsBoolean(ConfigurationKeys.SHOW_TIMEZONE_WARNING); request.setAttribute("showTimezoneWarning", tzWarning); request.setAttribute("showTimezoneWarningPopup", false); - if ( tzWarning ) { + if (tzWarning) { Boolean ssWarningShown = (Boolean) ss.getAttribute("timezoneWarningShown"); - if ( ! Boolean.TRUE.equals(ssWarningShown) ) { + if (!Boolean.TRUE.equals(ssWarningShown)) { ss.setAttribute("timezoneWarningShown", Boolean.TRUE); request.setAttribute("showTimezoneWarningPopup", true); } } - - List favoriteOrganisations = userManagementService.getFavoriteOrganisationsByUser(userDTO.getUserID()); + + List favoriteOrganisations = userManagementService + .getFavoriteOrganisationsByUser(userDTO.getUserID()); request.setAttribute("favoriteOrganisations", favoriteOrganisations); request.setAttribute("activeOrgId", user.getLastVisitedOrganisationId()); - + boolean isSysadmin = request.isUserInRole(Role.SYSADMIN); int userCoursesCount = userManagementService.getCountActiveCoursesByUser(userDTO.getUserID(), isSysadmin, null); request.setAttribute("isCourseSearchOn", userCoursesCount > 10); @@ -167,9 +169,9 @@ } private static void setHeaderLinks(HttpServletRequest request) { - List headerLinks = new ArrayList(); + List headerLinks = new ArrayList<>(); if (request.isUserInRole(Role.AUTHOR)) { - if (isPedagogicalPlannerAvailable()) { + if (IndexAction.isPedagogicalPlannerAvailable()) { headerLinks.add(new IndexLinkBean("index.planner", "javascript:openPedagogicalPlanner()")); } headerLinks.add(new IndexLinkBean("index.author", "javascript:showAuthoringDialog()")); @@ -185,7 +187,7 @@ } private void setAdminLinks(HttpServletRequest request) { - List adminLinks = new ArrayList(); + List adminLinks = new ArrayList<>(); if (request.isUserInRole(Role.SYSADMIN) || request.isUserInRole(Role.GROUP_ADMIN) || request.isUserInRole(Role.GROUP_MANAGER)) { adminLinks.add(new IndexLinkBean("index.courseman", "javascript:openOrgManagement(" @@ -201,10 +203,10 @@ * Returns list of organisations for user. Used by offcanvas tablesorter on main.jsp. */ public ActionForward getOrgs(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException, JSONException { + HttpServletResponse res) throws IOException, ServletException { getUserManagementService(); User loggedInUser = getUserManagementService().getUserByLogin(request.getRemoteUser()); - + Integer userId = loggedInUser.getUserId(); boolean isSysadmin = request.isUserInRole(Role.SYSADMIN); String searchString = WebUtil.readStrParam(request, "fcol[1]", true); @@ -225,27 +227,28 @@ // // } - List orgDtos = userManagementService.getActiveCoursesByUser(userId, isSysadmin, page, size, searchString); + List orgDtos = userManagementService.getActiveCoursesByUser(userId, isSysadmin, page, size, + searchString); - JSONObject responcedata = new JSONObject(); - responcedata.put("total_rows", userManagementService.getCountActiveCoursesByUser(userId, isSysadmin, searchString)); + ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); + responcedata.put("total_rows", + userManagementService.getCountActiveCoursesByUser(userId, isSysadmin, searchString)); - JSONArray rows = new JSONArray(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); for (OrganisationDTO orgDto : orgDtos) { - - JSONObject responseRow = new JSONObject(); + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); responseRow.put("id", orgDto.getOrganisationID()); String orgName = orgDto.getName() == null ? "" : orgDto.getName(); responseRow.put("name", HtmlUtils.htmlEscape(orgName)); - rows.put(responseRow); + rows.add(responseRow); } - responcedata.put("rows", rows); + responcedata.set("rows", rows); res.setContentType("application/json;charset=utf-8"); res.getWriter().print(new String(responcedata.toString())); return null; } - + /** * Toggles whether organisation is marked as favorite. */ @@ -261,18 +264,18 @@ List favoriteOrganisations = userManagementService.getFavoriteOrganisationsByUser(userId); request.setAttribute("favoriteOrganisations", favoriteOrganisations); - + String activeOrgId = request.getParameter("activeOrgId"); request.setAttribute("activeOrgId", activeOrgId); return mapping.findForward("favoriteOrganisations"); } - + /** * Saves to DB last visited organisation. It's required for displaying some org on main.jsp next time user logs in. */ - public ActionForward storeLastVisitedOrganisation(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException { + public ActionForward storeLastVisitedOrganisation(ActionMapping mapping, ActionForm form, + HttpServletRequest request, HttpServletResponse res) throws IOException, ServletException { getUserManagementService(); Integer lastVisitedOrganisationId = WebUtil.readIntParam(request, "orgId", false); @@ -285,13 +288,13 @@ return null; } - + private Integer getUserId() { HttpSession ss = SessionManager.getSession(); UserDTO learner = (UserDTO) ss.getAttribute(AttributeNames.USER); return learner != null ? learner.getUserID() : null; } - + private IIntegrationService getIntegrationService() { if (integrationService == null) { integrationService = (IntegrationService) WebApplicationContextUtils Index: lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/usermanagement/User.hbm.xml =================================================================== diff -u -r5cf9e6a0f2d86fd8371a466a07b8c0cbf3f81cb8 -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/usermanagement/User.hbm.xml (.../User.hbm.xml) (revision 5cf9e6a0f2d86fd8371a466a07b8c0cbf3f81cb8) +++ lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/usermanagement/User.hbm.xml (.../User.hbm.xml) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -66,7 +66,7 @@ + not-null="false" length="64"> @hibernate.property column="two_factor_auth_secret" Index: lams_common/src/java/org/lamsfoundation/lams/commonContext.xml =================================================================== diff -u -re59191f853aa9bdaf89c4e430fa9517541c073ed -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision e59191f853aa9bdaf89c4e430fa9517541c073ed) +++ lams_common/src/java/org/lamsfoundation/lams/commonContext.xml (.../commonContext.xml) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -14,7 +14,7 @@ - + Index: lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java =================================================================== diff -u -rd5b05f6e239a87908856f9f4251a487158ed9ca8 -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision d5b05f6e239a87908856f9f4251a487158ed9ca8) +++ lams_common/src/java/org/lamsfoundation/lams/integration/service/IntegrationService.java (.../IntegrationService.java) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -44,8 +44,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONObject; import org.imsglobal.pox.IMSPOXRequest; import org.lamsfoundation.lams.gradebook.GradebookUserLesson; import org.lamsfoundation.lams.gradebook.service.IGradebookService; @@ -76,10 +74,14 @@ import org.lamsfoundation.lams.util.CSVUtil; import org.lamsfoundation.lams.util.CommonConstants; import org.lamsfoundation.lams.util.HashUtil; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.LanguageUtil; import org.lamsfoundation.lams.util.ValidationUtil; import org.lamsfoundation.lams.util.WebUtil; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; + import oauth.signpost.exception.OAuthException; /** @@ -796,25 +798,22 @@ BufferedReader isReader = new BufferedReader(new InputStreamReader(is)); String str = isReader.readLine(); - JSONArray jsonGroups = new JSONArray(str); + ArrayNode jsonGroups = JsonUtil.readArray(str); List extGroups = new ArrayList<>(); - for (int i = 0; i < jsonGroups.length(); i++) { - JSONObject jsonGroup = jsonGroups.getJSONObject(i); + for (JsonNode jsonGroup : jsonGroups) { ExtGroupDTO group = new ExtGroupDTO(); - group.setGroupName(jsonGroup.getString("groupName")); - group.setGroupId(jsonGroup.getString("groupId")); + group.setGroupName(JsonUtil.optString(jsonGroup, "groupName")); + group.setGroupId(JsonUtil.optString(jsonGroup, "groupId")); extGroups.add(group); // in case group info is also requested - provide selected groups' ids if (extGroupIds != null && extGroupIds.length > 0) { ArrayList users = new ArrayList<>(); - JSONArray jsonUsers = jsonGroup.getJSONArray("users"); - for (int j = 0; j < jsonUsers.length(); j++) { - JSONObject jsonUser = jsonUsers.getJSONObject(j); + ArrayNode jsonUsers = JsonUtil.optArray(jsonGroup, "users"); + for (JsonNode jsonUser : jsonUsers) { + String extUsername = JsonUtil.optString(jsonUser, "userName"); - String extUsername = jsonUser.getString("userName"); - ExtUserUseridMap extUserUseridMap = getExistingExtUserUseridMap(extServer, extUsername); //create extUserUseridMap if it's not available @@ -824,7 +823,7 @@ // language>, String[] userData = new String[14]; for (int k = 1; k <= 14; k++) { - String userProperty = jsonUser.getString("" + k); + String userProperty = JsonUtil.optString(jsonUser, "" + k); userData[k - 1] = userProperty; } String salt = HashUtil.salt(); @@ -848,7 +847,7 @@ group.setUsers(users); } else { - group.setNumberUsers(jsonGroup.getInt("groupSize")); + group.setNumberUsers(JsonUtil.optInt(jsonGroup, "groupSize")); } } Index: lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java =================================================================== diff -u -r17599037f2f775fd6e66fada5c098966dad53b21 -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java (.../ForumService.java) (revision 17599037f2f775fd6e66fada5c098966dad53b21) +++ lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/service/ForumService.java (.../ForumService.java) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -42,9 +42,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.upload.FormFile; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.confidencelevel.ConfidenceLevelDTO; import org.lamsfoundation.lams.contentrepository.ICredentials; import org.lamsfoundation.lams.contentrepository.ITicket; @@ -117,6 +114,9 @@ import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * * @author Steve.Ni @@ -1535,50 +1535,49 @@ /** * Used by the Rest calls to create content. Mandatory fields in toolContentJSON: title, instructions, topics. - * Topics must contain a JSONArray of JSONObject objects, which have the following mandatory fields: subject, body + * Topics must contain a ArrayNode of ObjectNode objects, which have the following mandatory fields: subject, body * There will usually be at least one topic object in the Topics array but the array may be of zero length. */ @Override - public void createRestToolContent(Integer userID, Long toolContentID, JSONObject toolContentJSON) - throws JSONException { + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { Forum forum = new Forum(); Date updateDate = new Date(); forum.setCreated(updateDate); forum.setUpdated(updateDate); forum.setContentId(toolContentID); - forum.setTitle(toolContentJSON.getString(RestTags.TITLE)); - forum.setInstructions(toolContentJSON.getString(RestTags.INSTRUCTIONS)); + forum.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + forum.setInstructions(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); - forum.setAllowAnonym(JsonUtil.opt(toolContentJSON, "allowAnonym", Boolean.FALSE)); - forum.setAllowEdit(JsonUtil.opt(toolContentJSON, "allowEdit", Boolean.TRUE)); // defaults to true in the default - // entry in the db - forum.setAllowNewTopic(JsonUtil.opt(toolContentJSON, "allowNewTopic", Boolean.TRUE)); // defaults to true in the - // default entry in the db - forum.setAllowRateMessages(JsonUtil.opt(toolContentJSON, "allowRateMessages", Boolean.FALSE)); - forum.setAllowRichEditor(JsonUtil.opt(toolContentJSON, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); - forum.setAllowUpload(JsonUtil.opt(toolContentJSON, "allowUpload", Boolean.FALSE)); + forum.setAllowAnonym(JsonUtil.optBoolean(toolContentJSON, "allowAnonym", Boolean.FALSE)); + forum.setAllowEdit(JsonUtil.optBoolean(toolContentJSON, "allowEdit", Boolean.TRUE)); // defaults to true in the default + // entry in the db + forum.setAllowNewTopic(JsonUtil.optBoolean(toolContentJSON, "allowNewTopic", Boolean.TRUE)); // defaults to true in the + // default entry in the db + forum.setAllowRateMessages(JsonUtil.optBoolean(toolContentJSON, "allowRateMessages", Boolean.FALSE)); + forum.setAllowRichEditor(JsonUtil.optBoolean(toolContentJSON, RestTags.ALLOW_RICH_TEXT_EDITOR, Boolean.FALSE)); + forum.setAllowUpload(JsonUtil.optBoolean(toolContentJSON, "allowUpload", Boolean.FALSE)); forum.setContentInUse(false); forum.setDefineLater(false); - forum.setLimitedMaxCharacters(JsonUtil.opt(toolContentJSON, "limitedMaxCharacters", Boolean.TRUE)); - forum.setLimitedMinCharacters(JsonUtil.opt(toolContentJSON, "limitedMinCharacters", Boolean.FALSE)); - forum.setLockWhenFinished(JsonUtil.opt(toolContentJSON, "lockWhenFinished", Boolean.FALSE)); - forum.setMaxCharacters(JsonUtil.opt(toolContentJSON, "maxCharacters", 5000)); // defaults to 5000 chars in the - // default entry in the db. - forum.setMaximumRate(JsonUtil.opt(toolContentJSON, "maximumRate", 0)); - forum.setMaximumReply(JsonUtil.opt(toolContentJSON, "maximumReply", 0)); - forum.setMinCharacters(JsonUtil.opt(toolContentJSON, "minCharacters", 0)); - forum.setMinimumRate(JsonUtil.opt(toolContentJSON, "minimumRate", 0)); - forum.setMinimumReply(JsonUtil.opt(toolContentJSON, "minimumReply", 0)); + forum.setLimitedMaxCharacters(JsonUtil.optBoolean(toolContentJSON, "limitedMaxCharacters", Boolean.TRUE)); + forum.setLimitedMinCharacters(JsonUtil.optBoolean(toolContentJSON, "limitedMinCharacters", Boolean.FALSE)); + forum.setLockWhenFinished(JsonUtil.optBoolean(toolContentJSON, "lockWhenFinished", Boolean.FALSE)); + forum.setMaxCharacters(JsonUtil.optInt(toolContentJSON, "maxCharacters", 5000)); // defaults to 5000 chars in the + // default entry in the db. + forum.setMaximumRate(JsonUtil.optInt(toolContentJSON, "maximumRate", 0)); + forum.setMaximumReply(JsonUtil.optInt(toolContentJSON, "maximumReply", 0)); + forum.setMinCharacters(JsonUtil.optInt(toolContentJSON, "minCharacters", 0)); + forum.setMinimumRate(JsonUtil.optInt(toolContentJSON, "minimumRate", 0)); + forum.setMinimumReply(JsonUtil.optInt(toolContentJSON, "minimumReply", 0)); forum.setNotifyLearnersOnForumPosting( - JsonUtil.opt(toolContentJSON, "notifyLearnersOnForumPosting", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyLearnersOnForumPosting", Boolean.FALSE)); forum.setNotifyLearnersOnMarkRelease( - JsonUtil.opt(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); forum.setNotifyTeachersOnForumPosting( - JsonUtil.opt(toolContentJSON, "notifyTeachersOnForumPosting", Boolean.FALSE)); - forum.setReflectInstructions((String) JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, null)); - forum.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyTeachersOnForumPosting", Boolean.FALSE)); + forum.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + forum.setReflectOnActivity(JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); // submissionDeadline is set in monitoring // *******************************Handle user******************* @@ -1592,27 +1591,27 @@ // UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); ForumUser forumUser = getUserByID(userID.longValue()); if (forumUser == null) { - forumUser = new ForumUser(userID.longValue(), toolContentJSON.getString("firstName"), - toolContentJSON.getString("lastName"), toolContentJSON.getString("loginName")); + forumUser = new ForumUser(userID.longValue(), JsonUtil.optString(toolContentJSON, "firstName"), + JsonUtil.optString(toolContentJSON, "lastName"), JsonUtil.optString(toolContentJSON, "loginName")); getForumUserDao().save(forumUser); } forum.setCreatedBy(forumUser); updateForum(forum); // **************************** Handle topic ********************* - JSONArray topics = toolContentJSON.getJSONArray("topics"); - for (int i = 0; i < topics.length(); i++) { - JSONObject msgData = (JSONObject) topics.get(i); + ArrayNode topics = JsonUtil.optArray(toolContentJSON, "topics"); + for (int i = 0; i < topics.size(); i++) { + ObjectNode msgData = (ObjectNode) topics.get(i); Message newMsg = new Message(); // newMsg.setAttachments(attachments); TODO newMsg.setCreatedBy(forumUser); newMsg.setCreated(updateDate); newMsg.setModifiedBy(null); newMsg.setUpdated(updateDate); - newMsg.setSubject(msgData.getString("subject")); - newMsg.setBody(msgData.getString("body")); + newMsg.setSubject(JsonUtil.optString(msgData, "subject")); + newMsg.setBody(JsonUtil.optString(msgData, "body")); newMsg.setForum(forum); newMsg.setHideFlag(false); // newMsg.setIsAnonymous(false); Does not appear on authoring interface Index: lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/web/actions/LearningAction.java =================================================================== diff -u -rb1c0d52ecba9b00684a98dfb74dbf07ea927b489 -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/web/actions/LearningAction.java (.../LearningAction.java) (revision b1c0d52ecba9b00684a98dfb74dbf07ea927b489) +++ lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/web/actions/LearningAction.java (.../LearningAction.java) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -21,7 +21,6 @@ * **************************************************************** */ - package org.lamsfoundation.lams.tool.forum.web.actions; import java.io.IOException; @@ -45,8 +44,6 @@ import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.events.IEventNotificationService; import org.lamsfoundation.lams.learning.web.bean.ActivityPositionDTO; import org.lamsfoundation.lams.learning.web.util.LearningWebUtil; @@ -83,6 +80,9 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * User: conradb Date: 24/06/2005 Time: 10:54:09 */ @@ -176,7 +176,7 @@ if (sessionMapID != null) { sessionMap = (SessionMap) request.getSession().getAttribute(sessionMapID); } else { - sessionMap = new SessionMap(); + sessionMap = new SessionMap<>(); request.getSession().setAttribute(sessionMap.getSessionID(), sessionMap); } @@ -231,14 +231,14 @@ sessionMap.put(ForumConstants.ATTR_USER_FINISHED, forumUser.isSessionFinished()); sessionMap.put(ForumConstants.ATTR_ALLOW_EDIT, forum.isAllowEdit()); sessionMap.put(ForumConstants.ATTR_ALLOW_ANONYMOUS, forum.getAllowAnonym()); - + sessionMap.put(ForumConstants.ATTR_ALLOW_UPLOAD, forum.isAllowUpload()); int uploadMaxFileSize = Configuration.getAsInt(ConfigurationKeys.UPLOAD_FILE_MAX_SIZE); // it defaults to -1 if property was not found if (uploadMaxFileSize > 0) { sessionMap.put(ForumConstants.ATTR_UPLOAD_MAX_FILE_SIZE, FileValidatorUtil.formatSize(uploadMaxFileSize)); } - + sessionMap.put(ForumConstants.ATTR_ALLOW_RATE_MESSAGES, forum.isAllowRateMessages()); sessionMap.put(ForumConstants.ATTR_MINIMUM_RATE, forum.getMinimumRate()); sessionMap.put(ForumConstants.ATTR_MAXIMUM_RATE, forum.getMaximumRate()); @@ -483,11 +483,12 @@ // if coming from topic list, the toolSessionId is in the SessionMap. // if coming from the monitoring statistics window, it is passed in as a parameter. Long toolSessionId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID, true); - if ( toolSessionId != null ) { + if (toolSessionId != null) { sessionMap.put(AttributeNames.PARAM_TOOL_SESSION_ID, toolSessionId); String mode = WebUtil.readStrParam(request, AttributeNames.PARAM_MODE, true); - if ( mode != null ) + if (mode != null) { sessionMap.put(AttributeNames.PARAM_MODE, mode); + } } else { toolSessionId = (Long) sessionMap.get(AttributeNames.PARAM_TOOL_SESSION_ID); } @@ -767,9 +768,8 @@ /** * Create a replayed topic for a parent topic. */ - private ActionForward replyTopicInline(ActionMapping mapping, ActionForm form, - HttpServletRequest request, HttpServletResponse response) - throws InterruptedException, JSONException, IOException { + private ActionForward replyTopicInline(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws InterruptedException, IOException { MessageForm messageForm = (MessageForm) form; SessionMap sessionMap = getSessionMap(request, messageForm); @@ -804,24 +804,23 @@ boolean noMorePosts = forum.getMaximumReply() != 0 && numOfPosts >= forum.getMaximumReply() && !forum.isAllowNewTopic() ? Boolean.TRUE : Boolean.FALSE; - JSONObject JSONObject = new JSONObject(); - JSONObject.put(ForumConstants.ATTR_MESS_ID, newMessageSeq.getMessage().getUid()); - JSONObject.put(ForumConstants.ATTR_NO_MORE_POSTS, noMorePosts); - JSONObject.put(ForumConstants.ATTR_NUM_OF_POSTS, numOfPosts); - JSONObject.put(ForumConstants.ATTR_THREAD_ID, newMessageSeq.getThreadMessage().getUid()); - JSONObject.put(ForumConstants.ATTR_SESSION_MAP_ID, messageForm.getSessionMapID()); - JSONObject.put(ForumConstants.ATTR_ROOT_TOPIC_UID, rootTopicId); - JSONObject.put(ForumConstants.ATTR_PARENT_TOPIC_ID, newMessageSeq.getMessage().getParent().getUid()); + ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); + ObjectNode.put(ForumConstants.ATTR_MESS_ID, newMessageSeq.getMessage().getUid()); + ObjectNode.put(ForumConstants.ATTR_NO_MORE_POSTS, noMorePosts); + ObjectNode.put(ForumConstants.ATTR_NUM_OF_POSTS, numOfPosts); + ObjectNode.put(ForumConstants.ATTR_THREAD_ID, newMessageSeq.getThreadMessage().getUid()); + ObjectNode.put(ForumConstants.ATTR_SESSION_MAP_ID, messageForm.getSessionMapID()); + ObjectNode.put(ForumConstants.ATTR_ROOT_TOPIC_UID, rootTopicId); + ObjectNode.put(ForumConstants.ATTR_PARENT_TOPIC_ID, newMessageSeq.getMessage().getParent().getUid()); response.setContentType("application/json;charset=utf-8"); - response.getWriter().print(JSONObject); + response.getWriter().print(ObjectNode); return null; } private void setMonitorMode(SessionMap sessionMap, Message message) { message.setIsMonitor(ToolAccessMode.TEACHER.equals(sessionMap.get(AttributeNames.ATTR_MODE))); } - - + /** * Display a editable form for a special topic in order to update it. */ @@ -919,11 +918,11 @@ userId = messagePO.getCreatedBy().getUserId(); loginName = messagePO.getCreatedBy().getLoginName(); } - if ( messagePO.getToolSession() != null && messagePO.getToolSession().getForum() != null ) { + if (messagePO.getToolSession() != null && messagePO.getToolSession().getForum() != null) { toolContentId = messagePO.getToolSession().getForum().getContentId(); } - forumService.getLogEventService().logChangeLearnerContent(userId, loginName, toolContentId, oldMessageString, - messagePO.toString()); + forumService.getLogEventService().logChangeLearnerContent(userId, loginName, toolContentId, + oldMessageString, messagePO.toString()); } // save message into database @@ -935,7 +934,7 @@ * Update a topic. */ public ActionForward updateTopicInline(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws PersistenceException, JSONException, IOException { + HttpServletResponse response) throws PersistenceException, IOException { forumService = getForumManager(); @@ -946,13 +945,13 @@ doUpdateTopic(request, messageForm, sessionMap, topicId, message); - JSONObject JSONObject = new JSONObject(); - JSONObject.put(ForumConstants.ATTR_MESS_ID, topicId); - JSONObject.put(ForumConstants.ATTR_SESSION_MAP_ID, messageForm.getSessionMapID()); + ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); + ObjectNode.put(ForumConstants.ATTR_MESS_ID, topicId); + ObjectNode.put(ForumConstants.ATTR_SESSION_MAP_ID, messageForm.getSessionMapID()); Long rootTopicId = forumService.getRootTopicId(topicId); - JSONObject.put(ForumConstants.ATTR_ROOT_TOPIC_UID, rootTopicId); + ObjectNode.put(ForumConstants.ATTR_ROOT_TOPIC_UID, rootTopicId); response.setContentType("application/json;charset=utf-8"); - response.getWriter().print(JSONObject); + response.getWriter().print(ObjectNode); return null; } @@ -1000,7 +999,7 @@ * Rates postings submitted by other learners. */ public ActionForward rateMessage(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException, IOException { + HttpServletResponse response) throws IOException { forumService = getForumManager(); String sessionMapId = WebUtil.readStrParam(request, ForumConstants.ATTR_SESSION_MAP_ID); @@ -1029,13 +1028,13 @@ sessionMap.put(ForumConstants.ATTR_IS_MIN_RATINGS_COMPLETED, isMinRatingsCompleted); sessionMap.put(ForumConstants.ATTR_NUM_OF_RATINGS, numOfRatings); - JSONObject JSONObject = new JSONObject(); - JSONObject.put("averageRating", averageRatingDTO.getRating()); - JSONObject.put("numberOfVotes", averageRatingDTO.getNumberOfVotes()); - JSONObject.put(ForumConstants.ATTR_NO_MORE_RATINGSS, noMoreRatings); - JSONObject.put(ForumConstants.ATTR_NUM_OF_RATINGS, numOfRatings); + ObjectNode ObjectNode = JsonNodeFactory.instance.objectNode(); + ObjectNode.put("averageRating", averageRatingDTO.getRating()); + ObjectNode.put("numberOfVotes", averageRatingDTO.getNumberOfVotes()); + ObjectNode.put(ForumConstants.ATTR_NO_MORE_RATINGSS, noMoreRatings); + ObjectNode.put(ForumConstants.ATTR_NUM_OF_RATINGS, numOfRatings); response.setContentType("application/json;charset=utf-8"); - response.getWriter().print(JSONObject); + response.getWriter().print(ObjectNode); return null; } Index: lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/web/actions/MonitoringAction.java =================================================================== diff -u -r17599037f2f775fd6e66fada5c098966dad53b21 -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/web/actions/MonitoringAction.java (.../MonitoringAction.java) (revision 17599037f2f775fd6e66fada5c098966dad53b21) +++ lams_tool_forum/src/java/org/lamsfoundation/lams/tool/forum/web/actions/MonitoringAction.java (.../MonitoringAction.java) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -58,9 +58,6 @@ import org.apache.struts.action.ActionMessages; import org.apache.struts.action.ActionRedirect; import org.apache.struts.config.ForwardConfig; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.tool.forum.dto.MessageDTO; import org.lamsfoundation.lams.tool.forum.dto.SessionDTO; import org.lamsfoundation.lams.tool.forum.persistence.Forum; @@ -87,6 +84,10 @@ import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.util.HtmlUtils; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + public class MonitoringAction extends Action { private static Logger log = Logger.getLogger(MonitoringAction.class); @@ -125,6 +126,7 @@ if (param.equals("updateMark")) { return updateMark(mapping, form, request, response); } + if (param.equals("releaseMark")) { return releaseMark(mapping, form, request, response); } @@ -211,7 +213,8 @@ Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline); sessionMap.put(ForumConstants.ATTR_SUBMISSION_DEADLINE, tzSubmissionDeadline.getTime()); // use the unconverted time, as convertToStringForJSON() does the timezone conversion if needed - request.setAttribute(ForumConstants.ATTR_SUBMISSION_DEADLINE_DATESTRING, DateUtil.convertToStringForJSON(submissionDeadline, request.getLocale())); + request.setAttribute(ForumConstants.ATTR_SUBMISSION_DEADLINE_DATESTRING, + DateUtil.convertToStringForJSON(submissionDeadline, request.getLocale())); } boolean isGroupedActivity = forumService.isGroupedActivity(toolContentId); @@ -222,7 +225,7 @@ * Refreshes user list. */ public ActionForward getUsers(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse res) throws IOException, ServletException, JSONException { + HttpServletResponse res) throws IOException, ServletException { forumService = getForumService(); String sessionMapId = WebUtil.readStrParam(request, ForumConstants.ATTR_SESSION_MAP_ID); SessionMap sessionMap = (SessionMap) request.getSession() @@ -285,14 +288,14 @@ List users = forumService.getUsersForTablesorter(sessionId, page, size, sorting, searchString, forum.isReflectOnActivity()); - JSONArray rows = new JSONArray(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); - JSONObject responcedata = new JSONObject(); + ObjectNode responcedata = JsonNodeFactory.instance.objectNode(); responcedata.put("total_rows", forumService.getCountUsersBySession(sessionId, searchString)); for (Object[] userAndReflection : users) { - JSONObject responseRow = new JSONObject(); + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); ForumUser user = (ForumUser) userAndReflection[0]; @@ -329,14 +332,14 @@ if (userAndReflection.length > 1 && userAndReflection[1] != null) { responseRow.put("notebookEntry", HtmlUtils.htmlEscape((String) userAndReflection[1])); } - + if (userAndReflection.length > 2 && userAndReflection[2] != null) { - responseRow.put(ForumConstants.ATTR_PORTRAIT_ID, userAndReflection[2]); + responseRow.put(ForumConstants.ATTR_PORTRAIT_ID, (String) userAndReflection[2]); } - rows.put(responseRow); + rows.add(responseRow); } - responcedata.put("rows", rows); + responcedata.set("rows", rows); res.setContentType("application/json;charset=utf-8"); res.getWriter().print(new String(responcedata.toString())); return null; @@ -732,7 +735,7 @@ return mapping.findForward("success"); } else { // mark from view forum - // display root topic rather than leaf one + // display root topic rather than leaf one Long rootTopicId = forumService.getRootTopicId(msg.getUid()); ForwardConfig redirectConfig = mapping.findForwardConfig("viewTopic"); @@ -798,8 +801,7 @@ * @return */ private Map> getTopicsSortedByAuthor(List topics) { - Map> topicsByUser = new TreeMap<>( - new ForumUserComparator()); + Map> topicsByUser = new TreeMap<>(new ForumUserComparator()); for (MessageDTO topic : topics) { if (topic.getMessage().getIsAuthored()) { continue; Index: lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/service/SubmitFilesService.java =================================================================== diff -u -r17ec5b2c7e557b3ce71e0d143ef162909c515107 -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/service/SubmitFilesService.java (.../SubmitFilesService.java) (revision 17ec5b2c7e557b3ce71e0d143ef162909c515107) +++ lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/service/SubmitFilesService.java (.../SubmitFilesService.java) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -42,8 +42,6 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts.upload.FormFile; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.confidencelevel.ConfidenceLevelDTO; import org.lamsfoundation.lams.contentrepository.ICredentials; import org.lamsfoundation.lams.contentrepository.ITicket; @@ -107,6 +105,8 @@ import org.lamsfoundation.lams.web.util.AttributeNames; import org.springframework.dao.DataAccessException; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author Manpreet Minhas */ @@ -247,13 +247,15 @@ List submissions = submissionDetailsDAO.getBySessionAndLearner(session.getSessionID(), userId); submissionDetailsDAO.deleteAll(submissions); + SubmitUser user = submitUserDAO.getLearner(session.getSessionID(), userId); if (user != null) { NotebookEntry entry = getEntry(session.getSessionID(), CoreNotebookConstants.NOTEBOOK_TOOL, SbmtConstants.TOOL_SIGNATURE, userId); if (entry != null) { submitFilesContentDAO.delete(entry); } + gradebookService.removeActivityMark(user.getUserID(), session.getSessionID()); submitUserDAO.delete(user); @@ -263,6 +265,7 @@ @Override public void copyLearnerContent(SubmitUser fromUser, SubmitUser toUser) throws ToolException { + if ((fromUser == null) || (toUser == null) || fromUser.getUid().equals(toUser.getUid())) { return; } @@ -311,7 +314,7 @@ } else { usersubmission.setReport(null); } - + submissionDetailsDAO.save(usersubmission); } } @@ -578,7 +581,7 @@ @Override public List getToolOutputs(String name, Long toolContentId) { - return new ArrayList(); + return new ArrayList<>(); } @Override @@ -624,6 +627,7 @@ detailSet.add(details); session.setSubmissionDetails(detailSet); submissionDetailsDAO.saveOrUpdate(session); + } /** @@ -773,6 +777,7 @@ submitFilesReportDAO.update(report); } + } } else { @@ -849,7 +854,7 @@ } userIdToTotalMarkMap.put(userId, userTotalMark); - } + } } else { SubmissionDetails submissionDetails = submissionDetailsDAO.getSubmissionDetailsByID(reportID); Integer userId = submissionDetails.getLearner().getUserID(); @@ -877,10 +882,11 @@ @Override public void removeMarkFile(Long reportID, Long markFileUUID, Long markFileVersionID, Long sessionID) { + SubmitFilesSession session = getSessionById(sessionID); SubmitFilesContent content = session.getContent(); boolean isUseSelectLeaderToolOuput = content.isUseSelectLeaderToolOuput(); - + if (isUseSelectLeaderToolOuput) { List reportIDs = submitUserDAO.getReportsForGroup(sessionID, reportID); for (Long reportIDGroup : reportIDs) { @@ -904,6 +910,7 @@ } deleteFromRepository(markFileUUID, markFileVersionID); + } @Override @@ -923,9 +930,9 @@ if (detail.getReport() != null) { // push outputs to gradebook recalculateUserTotalMarks(false, detail.getSubmitFileSession(), detail.getReport().getReportID()); - } } } + } @Override public void restoreLearnerFile(Long detailID, UserDTO monitor) { @@ -942,8 +949,8 @@ if (detail.getReport() != null) { // push outputs to gradebook recalculateUserTotalMarks(false, detail.getSubmitFileSession(), detail.getReport().getReportID()); - } } + } } @@ -1055,6 +1062,44 @@ } } + /** + * Sends marks to gradebook + * + * @param user + * @param toolSessionID + */ + @SuppressWarnings("unchecked") + public void sendMarksToGradebook(SubmitUser user, Long toolSessionID) { + submissionDetailsDAO.getSubmissionDetailsBySession(toolSessionID); + List detailsList = submissionDetailsDAO.getBySessionAndLearner(toolSessionID, + user.getUserID()); + if (detailsList != null) { + Float totalMark = null; + for (SubmissionDetails details : detailsList) { + if (!details.isRemoved()) { + SubmitFilesReport report = details.getReport(); + if (report != null) { + if (totalMark == null) { + totalMark = details.getReport().getMarks(); + } else if (report.getMarks() != null) { + totalMark += report.getMarks(); + } + } + } + } + if (totalMark != null) { + Double mark = new Double(totalMark); + gradebookService.updateActivityMark(mark, null, user.getUserID(), toolSessionID, false); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * org.lamsfoundation.lams.tool.sbmt.service.ISubmitFilesService#getToolDefaultContentIdBySignature(java.lang.Long) + */ @Override public Long getToolDefaultContentIdBySignature(String toolSignature) { Long contentId = null; @@ -1182,6 +1227,7 @@ submitUserDAO.saveOrUpdateUser(author); return author; + } @Override @@ -1200,6 +1246,7 @@ submitUserDAO.saveOrUpdateUser(learner); return learner; + } @Override @@ -1244,6 +1291,13 @@ } /** + * @return Returns the sbmtToolContentHandler. + */ + public IToolContentHandler getSbmtToolContentHandler() { + return sbmtToolContentHandler; + } + + /** * @param sbmtToolContentHandler * The sbmtToolContentHandler to set. */ @@ -1344,17 +1398,20 @@ for (SubmissionDetails detail : list) { Date newDate = detail.getDateOfSubmission(); if (newDate != null) { - if (startDate == null || newDate.before(startDate)) + if (startDate == null || newDate.before(startDate)) { startDate = newDate; - if (endDate == null || newDate.after(endDate)) + } + if (endDate == null || newDate.after(endDate)) { endDate = newDate; + } } } - if (learner.isFinished()) + if (learner.isFinished()) { return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_COMPLETED, startDate, endDate); - else + } else { return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_ATTEMPTED, startDate, null); + } } // ****************** REST methods ************************* @@ -1363,36 +1420,37 @@ * Used by the Rest calls to create content. Mandatory fields in toolContentJSON: title, instructions */ @Override - public void createRestToolContent(Integer userID, Long toolContentID, JSONObject toolContentJSON) - throws JSONException { + public void createRestToolContent(Integer userID, Long toolContentID, ObjectNode toolContentJSON) { SubmitFilesContent content = new SubmitFilesContent(); Date updateDate = new Date(); content.setCreated(updateDate); content.setUpdated(updateDate); content.setContentID(toolContentID); - content.setTitle(toolContentJSON.getString(RestTags.TITLE)); - content.setInstruction(toolContentJSON.getString(RestTags.INSTRUCTIONS)); + content.setTitle(JsonUtil.optString(toolContentJSON, RestTags.TITLE)); + content.setInstruction(JsonUtil.optString(toolContentJSON, RestTags.INSTRUCTIONS)); content.setContentInUse(false); content.setDefineLater(false); content.setNotifyTeachersOnFileSubmit( - JsonUtil.opt(toolContentJSON, "notifyTeachersOnFileSubmit", Boolean.FALSE)); + JsonUtil.optBoolean(toolContentJSON, "notifyTeachersOnFileSubmit", Boolean.FALSE)); content.setNotifyLearnersOnMarkRelease( - JsonUtil.opt(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); - content.setReflectInstructions((String) JsonUtil.opt(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS, null)); - content.setReflectOnActivity(JsonUtil.opt(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); - content.setLockOnFinished(JsonUtil.opt(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); - content.setLimitUpload(JsonUtil.opt(toolContentJSON, "limitUpload", Boolean.FALSE)); - content.setUseSelectLeaderToolOuput(JsonUtil.opt(toolContentJSON, "useSelectLeaderToolOuput", Boolean.FALSE)); - content.setLimitUploadNumber(JsonUtil.opt(toolContentJSON, "limitUploadNumber", 0)); + JsonUtil.optBoolean(toolContentJSON, "notifyLearnersOnMarkRelease", Boolean.FALSE)); + content.setReflectInstructions(JsonUtil.optString(toolContentJSON, RestTags.REFLECT_INSTRUCTIONS)); + content.setReflectOnActivity(JsonUtil.optBoolean(toolContentJSON, RestTags.REFLECT_ON_ACTIVITY, Boolean.FALSE)); + content.setLockOnFinished(JsonUtil.optBoolean(toolContentJSON, RestTags.LOCK_WHEN_FINISHED, Boolean.FALSE)); + content.setLimitUpload(JsonUtil.optBoolean(toolContentJSON, "limitUpload", Boolean.FALSE)); + content.setUseSelectLeaderToolOuput( + JsonUtil.optBoolean(toolContentJSON, "useSelectLeaderToolOuput", Boolean.FALSE)); + content.setLimitUploadNumber(JsonUtil.optInt(toolContentJSON, "limitUploadNumber", 0)); // submissionDeadline is set in monitoring SubmitUser user = getContentUser(toolContentID, userID); if (user == null) { - user = createContentUser(userID, toolContentJSON.getString("firstName"), - toolContentJSON.getString("lastName"), toolContentJSON.getString("loginName"), toolContentID); + user = createContentUser(userID, JsonUtil.optString(toolContentJSON, "firstName"), + JsonUtil.optString(toolContentJSON, "lastName"), JsonUtil.optString(toolContentJSON, "loginName"), + toolContentID); } content.setCreatedBy(user); saveOrUpdateContent(content); @@ -1413,7 +1471,7 @@ if (leader == null) { Long leaderUserId = toolService.getLeaderUserId(toolSessionId, user.getUserID().intValue()); if (leaderUserId != null) { - leader = submitUserDAO.getLearner(toolSessionId, (Integer) leaderUserId.intValue()); + leader = submitUserDAO.getLearner(toolSessionId, leaderUserId.intValue()); // create new user in a DB if (leader == null) { log.debug("creating new user with userId: " + leaderUserId); Index: lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/web/action/MonitoringAction.java =================================================================== diff -u -r366986460de0696853ade940daf5408f55352d47 -r266434d5ec15cc4026c93a740c3110c046b1d88a --- lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/web/action/MonitoringAction.java (.../MonitoringAction.java) (revision 366986460de0696853ade940daf5408f55352d47) +++ lams_tool_sbmt/src/java/org/lamsfoundation/lams/tool/sbmt/web/action/MonitoringAction.java (.../MonitoringAction.java) (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -48,9 +48,6 @@ import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.DynaActionForm; -import org.apache.tomcat.util.json.JSONArray; -import org.apache.tomcat.util.json.JSONException; -import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.tool.sbmt.SbmtConstants; import org.lamsfoundation.lams.tool.sbmt.SubmissionDetails; import org.lamsfoundation.lams.tool.sbmt.SubmitFilesContent; @@ -74,6 +71,10 @@ import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.util.HtmlUtils; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author Manpreet Minhas */ @@ -155,7 +156,7 @@ /** Ajax call to populate the tablesorter */ public ActionForward getUsers(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws JSONException, IOException { + HttpServletResponse response) throws IOException { Long sessionID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID)); Long contentId = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID); @@ -184,8 +185,8 @@ List users = service.getUsersForTablesorter(sessionID, page, size, sorting, searchString, spreadsheet.isReflectOnActivity()); - JSONArray rows = new JSONArray(); - JSONObject responsedata = new JSONObject(); + ArrayNode rows = JsonNodeFactory.instance.arrayNode(); + ObjectNode responsedata = JsonNodeFactory.instance.objectNode(); responsedata.put("total_rows", service.getCountUsersBySession(sessionID, searchString)); SubmitUser groupLeader = new SubmitUser(); if (spreadsheet.isUseSelectLeaderToolOuput()) { @@ -194,35 +195,36 @@ } for (Object[] userAndReflection : users) { - JSONObject responseRow = new JSONObject(); + ObjectNode responseRow = JsonNodeFactory.instance.objectNode(); SubmitUser user = (SubmitUser) userAndReflection[0]; responseRow.put(SbmtConstants.ATTR_USER_UID, user.getUid()); responseRow.put(SbmtConstants.USER_ID, user.getUserID()); responseRow.put(SbmtConstants.ATTR_USER_FULLNAME, HtmlUtils.htmlEscape(user.getFullName())); - if (userAndReflection.length > 2) { + + if (userAndReflection.length > 2) { responseRow.put(SbmtConstants.ATTR_PORTRAIT_ID, (Integer)userAndReflection[1]); } - + if (userAndReflection.length > 3) { - responseRow.put(SbmtConstants.ATTR_USER_NUM_FILE, - (Integer)userAndReflection[2] - (Integer)userAndReflection[3]); + responseRow.put(SbmtConstants.ATTR_USER_NUM_FILE, + (Integer) userAndReflection[2] - (Integer) userAndReflection[3]); } if (userAndReflection.length > 4) { responseRow.put(SbmtConstants.ATTR_USER_FILE_MARKED, (Integer) userAndReflection[4] > 0); } if (userAndReflection.length > 5) { - responseRow.put(SbmtConstants.ATTR_USER_REFLECTION, userAndReflection[5]); + responseRow.put(SbmtConstants.ATTR_USER_REFLECTION, (String) userAndReflection[5]); } if(!spreadsheet.isUseSelectLeaderToolOuput()|| (spreadsheet.isUseSelectLeaderToolOuput() && groupLeader==user)){ - rows.put(responseRow); - } + rows.add(responseRow); } + } - responsedata.put("rows", rows); + responsedata.set("rows", rows); response.setContentType("application/json;charset=utf-8"); response.getWriter().print(new String(responsedata.toString())); return null; @@ -257,10 +259,10 @@ request.setAttribute("statisticList", statistics); } else{ - statistics.addAll(submitFilesService.getStatisticsBySession(contentID)); - request.setAttribute("statisticList", statistics); - } + statistics.addAll(submitFilesService.getStatisticsBySession(contentID)); + request.setAttribute("statisticList", statistics); } + } /** * Release mark @@ -523,7 +525,8 @@ .append("file as file does not exist. Requested by user ").append(currentUser.getUserID()) .append(" for file ").append(detailID).append(" for user ").append(learnerUserID); log.error(builder.toString()); - throw new ServletException("Invalid call to "+(remove ? "remove" : "restore")+" file. See the server log for more details."); + throw new ServletException("Invalid call to " + (remove ? "remove" : "restore") + + " file. See the server log for more details."); } else { if (!fileToProcess.getSubmitFileSession().getSessionID().equals(sessionID) @@ -533,17 +536,19 @@ .append(currentUser.getUserID()).append(" for file ").append(detailID).append(" for user ") .append(learnerUserID).append(" in session ").append(sessionID); log.error(builder.toString()); - throw new ServletException("Invalid call to "+(remove ? "remove" : "restore")+" file. See the server log for more details."); + throw new ServletException("Invalid call to " + (remove ? "remove" : "restore") + + " file. See the server log for more details."); } else { if (remove) { submitFilesService.removeLearnerFile(detailID, currentUser); - notifyRemoveRestore(fileToProcess, "event.file.restore.subject", "event.file.restore.body", "restore file"); + notifyRemoveRestore(fileToProcess, "event.file.restore.subject", "event.file.restore.body", + "restore file"); - } else { submitFilesService.restoreLearnerFile(detailID, currentUser); - notifyRemoveRestore(fileToProcess, "event.file.delete.subject", "event.file.delete.body", "delete file"); + notifyRemoveRestore(fileToProcess, "event.file.delete.subject", "event.file.delete.body", + "delete file"); } } @@ -557,36 +562,41 @@ return mapping.findForward("listMark"); } - /** Notify the user by email of the file change. Need to do it here rather than in the service so that any issues are caught and logged - * without stuffing up the transaction. + /** + * Notify the user by email of the file change. Need to do it here rather than in the service so that any issues are + * caught and logged + * without stuffing up the transaction. */ - public void notifyRemoveRestore(SubmissionDetails detail, String i18nSubjectKey, String i18nBodyKey, String errorSubject) { + public void notifyRemoveRestore(SubmissionDetails detail, String i18nSubjectKey, String i18nBodyKey, + String errorSubject) { Long contentID = detail.getSubmitFileSession().getContent().getContentID(); Integer learnerID = detail.getLearner().getUserID(); - // Can't just create a new subscription then call triggerForSingleUser() as - // it needs a subscription id, which doesn't exist for a subscription created in the same + // Can't just create a new subscription then call triggerForSingleUser() as + // it needs a subscription id, which doesn't exist for a subscription created in the same // transaction. So reuse the existing RELEASE MARKS event and subscription (created when // a file is uploaded) and override both the subject and the message. try { - boolean eventExists = submitFilesService.getEventNotificationService().eventExists(SbmtConstants.TOOL_SIGNATURE, - SbmtConstants.EVENT_NAME_NOTIFY_LEARNERS_ON_MARK_RELEASE, contentID); + boolean eventExists = submitFilesService.getEventNotificationService().eventExists( + SbmtConstants.TOOL_SIGNATURE, SbmtConstants.EVENT_NAME_NOTIFY_LEARNERS_ON_MARK_RELEASE, contentID); if (eventExists) { submitFilesService.getEventNotificationService().triggerForSingleUser(SbmtConstants.TOOL_SIGNATURE, SbmtConstants.EVENT_NAME_NOTIFY_LEARNERS_ON_MARK_RELEASE, contentID, learnerID, submitFilesService.getLocalisedMessage(i18nSubjectKey, null), submitFilesService.getLocalisedMessage(i18nBodyKey, new Object[] { detail.getFilePath() })); } else { - log.error("Unable to notify user of "+errorSubject+". contentID="+contentID+" learner="+learnerID+" file "+detail.getFilePath()+" as "+SbmtConstants.EVENT_NAME_NOTIFY_LEARNERS_ON_MARK_RELEASE+" event is missing"); + log.error("Unable to notify user of " + errorSubject + ". contentID=" + contentID + " learner=" + + learnerID + " file " + detail.getFilePath() + " as " + + SbmtConstants.EVENT_NAME_NOTIFY_LEARNERS_ON_MARK_RELEASE + " event is missing"); } - } catch ( Exception e) { - log.error("Unable to notify user of "+errorSubject+". contentID="+contentID+" learner="+learnerID+" file "+detail.getFilePath()+" due to exception "+e.getMessage(),e); - } + } catch (Exception e) { + log.error("Unable to notify user of " + errorSubject + ". contentID=" + contentID + " learner=" + learnerID + + " file " + detail.getFilePath() + " due to exception " + e.getMessage(), e); + } } - // ********************************************************** // Private methods // ********************************************************** @@ -629,5 +639,5 @@ // request.setAttribute(AttributeNames.PARAM_TOOL_SESSION_ID,sessionID); request.setAttribute("sessions", sessions); } - + } \ No newline at end of file Index: lams_tool_zoom/.classpath =================================================================== diff -u --- lams_tool_zoom/.classpath (revision 0) +++ lams_tool_zoom/.classpath (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/model/ZoomApi.java =================================================================== diff -u --- lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/model/ZoomApi.java (revision 0) +++ lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/model/ZoomApi.java (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -0,0 +1,108 @@ +/**************************************************************** + * Copyright (C) 2005 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 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.tool.zoom.model; + +import org.lamsfoundation.lams.util.JsonUtil; + +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * + */ +public class ZoomApi { + + private Long uid; + + private String email; + + private String key; + + private String secret; + + public ZoomApi() { + // default constructor + } + + public ZoomApi(String email, String key, String value) { + this.email = email; + this.key = key; + this.secret = value; + } + + public ZoomApi(ObjectNode apiJSON) { + this.uid = JsonUtil.optLong(apiJSON, "uid"); + this.email = JsonUtil.optString(apiJSON, "email"); + this.key = JsonUtil.optString(apiJSON, "key"); + this.secret = JsonUtil.optString(apiJSON, "secret"); + } + + /** + * + */ + public Long getUid() { + return uid; + } + + public void setUid(Long uid) { + this.uid = uid; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + /** + * + * @return + */ + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getSecret() { + return secret; + } + + public void setSecret(String value) { + this.secret = value; + } + + public ObjectNode toJSON() { + ObjectNode result = JsonNodeFactory.instance.objectNode(); + result.put("uid", uid); + result.put("email", email); + result.put("key", key); + result.put("secret", secret); + return result; + } +} Index: lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/service/IZoomService.java =================================================================== diff -u --- lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/service/IZoomService.java (revision 0) +++ lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/service/IZoomService.java (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -0,0 +1,163 @@ +/**************************************************************** + * Copyright (C) 2005 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 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.tool.zoom.service; + +import java.io.IOException; +import java.util.List; + +import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.tool.zoom.model.Zoom; +import org.lamsfoundation.lams.tool.zoom.model.ZoomApi; +import org.lamsfoundation.lams.tool.zoom.model.ZoomSession; +import org.lamsfoundation.lams.tool.zoom.model.ZoomUser; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; + +/** + * Defines the services available to the web layer from the Zoom Service + */ +public interface IZoomService { + /** + * Makes a copy of the default content and assigns it a newContentID + * + * @params newContentID + * @return + */ + public Zoom copyDefaultContent(Long newContentID); + + /** + * Returns an instance of the Zoom tools default content. + * + * @return + */ + public Zoom getDefaultContent(); + + /** + * @param toolSignature + * @return + */ + public Long getDefaultContentIdBySignature(String toolSignature); + + /** + * @param toolContentID + * @return + */ + public Zoom getZoomByContentId(Long toolContentID); + + /** + * @param toolContentID + * @return + */ + public boolean isGroupedActivity(long toolContentID); + + /** + * Audit log the teacher has started editing activity in monitor. + * + * @param toolContentID + */ + void auditLogStartEditingActivityInMonitor(long toolContentID); + + /** + * @param zoom + */ + public void saveOrUpdateZoom(Zoom zoom); + + /** + * @param toolSessionId + * @return + */ + public ZoomSession getSessionBySessionId(Long toolSessionId); + + /** + * @param zoomSession + */ + public void saveOrUpdateZoomSession(ZoomSession zoomSession); + + /** + * + * @param userId + * @param toolSessionId + * @return + */ + public ZoomUser getUserByUserIdAndSessionId(Integer userId, Long toolSessionId); + + /** + * + * @param uid + * @return + */ + public ZoomUser getUserByUID(Long uid); + + /** + * + * @param zoomUser + */ + public void saveOrUpdateZoomUser(ZoomUser zoomUser); + + /** + * + * @param user + * @param zoomSession + * @return + */ + public ZoomUser createZoomUser(UserDTO user, ZoomSession zoomSession); + + Long createNotebookEntry(Long id, Integer idType, String signature, Integer userID, String entry); + + NotebookEntry getNotebookEntry(Long uid); + + void updateNotebookEntry(NotebookEntry notebookEntry); + + void updateNotebookEntry(Long uid, String entry); + + /** + * Choose API keys for a new meeting. + * NULL means that there are none available. + * false means that keys have been chosen but they seem to be in use + * true means that keys have been chosen and they seem to be free + */ + Boolean chooseApi(Long zoomUid) throws IOException; + + /** + * Create a new Zoom meeting using API + * + * @return start URL for browser to call and start the meeting + */ + String createMeeting(Long zoomUid) throws IOException; + + /** + * Register user for a meeting. Use session name in last name if the activity is grouped. + * + * @return personalised join link + */ + String registerUser(Long zoomUid, Long userUid, String sessionName) throws IOException; + + List getApis(); + + void saveApis(List apis); + + /** + * Checks if given API responds correctly + */ + boolean pingZoomApi(Long uid) throws IOException; +} \ No newline at end of file Index: lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/service/ZoomService.java =================================================================== diff -u --- lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/service/ZoomService.java (revision 0) +++ lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/service/ZoomService.java (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -0,0 +1,849 @@ +/**************************************************************** + * Copyright (C) 2005 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 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.tool.zoom.service; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.net.HttpURLConnection; +import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TimeZone; +import java.util.TreeMap; + +import javax.net.ssl.HttpsURLConnection; + +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; +import org.lamsfoundation.lams.confidencelevel.ConfidenceLevelDTO; +import org.lamsfoundation.lams.contentrepository.client.IToolContentHandler; +import org.lamsfoundation.lams.learning.service.ILearnerService; +import org.lamsfoundation.lams.learningdesign.service.ExportToolContentException; +import org.lamsfoundation.lams.learningdesign.service.IExportToolContentService; +import org.lamsfoundation.lams.learningdesign.service.ImportToolContentException; +import org.lamsfoundation.lams.notebook.model.NotebookEntry; +import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants; +import org.lamsfoundation.lams.notebook.service.ICoreNotebookService; +import org.lamsfoundation.lams.tool.ToolCompletionStatus; +import org.lamsfoundation.lams.tool.ToolContentManager; +import org.lamsfoundation.lams.tool.ToolOutput; +import org.lamsfoundation.lams.tool.ToolOutputDefinition; +import org.lamsfoundation.lams.tool.ToolSessionExportOutputData; +import org.lamsfoundation.lams.tool.ToolSessionManager; +import org.lamsfoundation.lams.tool.exception.DataMissingException; +import org.lamsfoundation.lams.tool.exception.ToolException; +import org.lamsfoundation.lams.tool.service.ILamsToolService; +import org.lamsfoundation.lams.tool.zoom.dao.IZoomDAO; +import org.lamsfoundation.lams.tool.zoom.model.Zoom; +import org.lamsfoundation.lams.tool.zoom.model.ZoomApi; +import org.lamsfoundation.lams.tool.zoom.model.ZoomSession; +import org.lamsfoundation.lams.tool.zoom.model.ZoomUser; +import org.lamsfoundation.lams.tool.zoom.util.ZoomConstants; +import org.lamsfoundation.lams.tool.zoom.util.ZoomException; +import org.lamsfoundation.lams.usermanagement.User; +import org.lamsfoundation.lams.usermanagement.dto.UserDTO; +import org.lamsfoundation.lams.util.JsonUtil; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import sun.net.www.protocol.https.HttpsURLConnectionImpl; + +/** + * An implementation of the IZoomService interface. + * + * As a requirement, all LAMS tool's service bean must implement ToolContentManager and ToolSessionManager. + */ + +public class ZoomService implements ToolSessionManager, ToolContentManager, IZoomService { + + private static final Logger logger = Logger.getLogger(ZoomService.class); + + private IZoomDAO zoomDAO = null; + + private ILearnerService learnerService; + + private ILamsToolService toolService; + + private IToolContentHandler zoomToolContentHandler = null; + + private IExportToolContentService exportContentService; + + private ICoreNotebookService coreNotebookService; + + /* Methods from ToolSessionManager */ + @Override + public void createToolSession(Long toolSessionId, String toolSessionName, Long toolContentId) throws ToolException { + if (ZoomService.logger.isDebugEnabled()) { + ZoomService.logger.debug("entering method createToolSession:" + " toolSessionId = " + toolSessionId + + " toolSessionName = " + toolSessionName + " toolContentId = " + toolContentId); + } + + ZoomSession session = new ZoomSession(); + session.setSessionId(toolSessionId); + session.setSessionName(toolSessionName); + // learner starts + Zoom zoom = getZoomByContentId(toolContentId); + session.setZoom(zoom); + zoomDAO.insertOrUpdate(session); + } + + @Override + public String leaveToolSession(Long toolSessionId, Long learnerId) throws DataMissingException, ToolException { + return learnerService.completeToolSession(toolSessionId, learnerId); + } + + @Override + public ToolSessionExportOutputData exportToolSession(Long toolSessionId) + throws DataMissingException, ToolException { + return null; + } + + @SuppressWarnings("rawtypes") + @Override + public ToolSessionExportOutputData exportToolSession(List toolSessionIds) + throws DataMissingException, ToolException { + return null; + } + + @Override + public void removeToolSession(Long toolSessionId) throws DataMissingException, ToolException { + zoomDAO.deleteByProperty(ZoomSession.class, "sessionId", toolSessionId); + } + + @Override + public SortedMap getToolOutput(List names, Long toolSessionId, Long learnerId) { + return new TreeMap(); + } + + @Override + public ToolOutput getToolOutput(String name, Long toolSessionId, Long learnerId) { + return null; + } + + @Override + public List getToolOutputs(String name, Long toolContentId) { + return new ArrayList(); + } + + @Override + public List getConfidenceLevels(Long toolSessionId) { + return null; + } + + @Override + public void forceCompleteUser(Long toolSessionId, User user) { + //no actions required + } + + /* Methods from ToolContentManager */ + + @Override + public void copyToolContent(Long fromContentId, Long toContentId) throws ToolException { + + if (ZoomService.logger.isDebugEnabled()) { + ZoomService.logger.debug("entering method copyToolContent:" + " fromContentId=" + fromContentId + + " toContentId=" + toContentId); + } + + if (toContentId == null) { + String error = "Failed to copy tool content: toContentID is null"; + throw new ToolException(error); + } + + Zoom fromContent = null; + if (fromContentId != null) { + fromContent = getZoomByContentId(fromContentId); + } + if (fromContent == null) { + // create the fromContent using the default tool content + fromContent = getDefaultContent(); + } + Zoom toContent = Zoom.newInstance(fromContent, toContentId, zoomToolContentHandler); + saveOrUpdateZoom(toContent); + } + + @Override + public void resetDefineLater(Long toolContentId) { + } + + @Override + public void removeToolContent(Long toolContentId) throws ToolException { + Zoom zoom = getZoomByContentId(toolContentId); + if (zoom == null) { + ZoomService.logger.warn("Can not remove the tool content as it does not exist, ID: " + toolContentId); + return; + } + + for (ZoomSession session : zoom.getZoomSessions()) { + List entries = coreNotebookService.getEntry(session.getSessionId(), + CoreNotebookConstants.NOTEBOOK_TOOL, ZoomConstants.TOOL_SIGNATURE); + for (NotebookEntry entry : entries) { + coreNotebookService.deleteEntry(entry); + } + } + + zoomDAO.delete(zoom); + } + + @Override + public void removeLearnerContent(Long toolContentId, Integer userId) throws ToolException { + if (ZoomService.logger.isDebugEnabled()) { + ZoomService.logger.debug("Resetting Web Conference completion flag for user ID " + userId + + " and toolContentId " + toolContentId); + } + + Zoom zoom = getZoomByContentId(toolContentId); + if (zoom == null) { + ZoomService.logger + .warn("Did not find activity with toolContentId: " + toolContentId + " to remove learner content"); + return; + } + + for (ZoomSession session : zoom.getZoomSessions()) { + for (ZoomUser user : session.getZoomUsers()) { + if (user.getUserId().equals(userId)) { + if (user.getNotebookEntryUID() != null) { + NotebookEntry entry = coreNotebookService.getEntry(user.getNotebookEntryUID()); + zoomDAO.delete(entry); + user.setNotebookEntryUID(null); + } + user.setFinishedActivity(false); + zoomDAO.update(user); + } + } + } + } + + /** + * Export the XML fragment for the tool's content, along with any files needed for the content. + * + * @throws DataMissingException + * if no tool content matches the toolSessionId + * @throws ToolException + * if any other error occurs + */ + + @Override + public void exportToolContent(Long toolContentId, String rootPath) throws DataMissingException, ToolException { + Zoom zoom = getZoomByContentId(toolContentId); + if (zoom == null) { + zoom = getDefaultContent(); + } + if (zoom == null) { + throw new DataMissingException("Unable to find default content for the zoom tool"); + } + + // set ResourceToolContentHandler as null to avoid copy file node in + // repository again. + zoom = Zoom.newInstance(zoom, toolContentId, null); + zoom.setToolContentHandler(null); + zoom.setZoomSessions(null); + zoom.setApi(null); + try { + exportContentService.exportToolContent(toolContentId, zoom, zoomToolContentHandler, rootPath); + } catch (ExportToolContentException e) { + throw new ToolException(e); + } + } + + /** + * Import the XML fragment for the tool's content, along with any files needed for the content. + * + * @throws ToolException + * if any other error occurs + */ + @Override + public void importToolContent(Long toolContentId, Integer newUserUid, String toolContentPath, String fromVersion, + String toVersion) throws ToolException { + try { + // register version filter class + exportContentService.registerImportVersionFilterClass(ZoomImportContentVersionFilter.class); + + Object toolPOJO = exportContentService.importToolContent(toolContentPath, zoomToolContentHandler, + fromVersion, toVersion); + if (!(toolPOJO instanceof Zoom)) { + throw new ImportToolContentException( + "Import Zoom tool content failed. Deserialized object is " + toolPOJO); + } + Zoom zoom = (Zoom) toolPOJO; + + // reset it to new toolContentId + zoom.setToolContentId(toolContentId); + zoom.setCreateBy(new Long(newUserUid.longValue())); + zoom.setApi(null); + + saveOrUpdateZoom(zoom); + } catch (ImportToolContentException e) { + throw new ToolException(e); + } + } + + @SuppressWarnings("rawtypes") + @Override + public Class[] getSupportedToolOutputDefinitionClasses(int definitionType) { + return null; + } + + /** + * Get the definitions for possible output for an activity, based on the toolContentId. These may be definitions + * that are always available for the tool (e.g. number of marks for Multiple Choice) or a custom definition created + * for a particular activity such as the answer to the third question contains the word Koala and hence the need for + * the toolContentId + * + * @return SortedMap of ToolOutputDefinitions with the key being the name of each definition + */ + @Override + public SortedMap getToolOutputDefinitions(Long toolContentId, int definitionType) + throws ToolException { + return new TreeMap(); + } + + @Override + public String getToolContentTitle(Long toolContentId) { + return getZoomByContentId(toolContentId).getTitle(); + } + + @Override + public boolean isContentEdited(Long toolContentId) { + return getZoomByContentId(toolContentId).isDefineLater(); + } + + @Override + public boolean isReadOnly(Long toolContentId) { + Zoom content = getZoomByContentId(toolContentId); + for (ZoomSession session : content.getZoomSessions()) { + for (ZoomUser user : session.getZoomUsers()) { + if (user.getNotebookEntryUID() != null) { + // we don't remove users in removeLearnerContent() + // we just set their notebook entry to NULL + return true; + } + } + } + + return false; + } + + @Override + public String getContributionURL(Long toolContentId) { + return ZoomConstants.TOOL_CONTRIBUTE_URL + toolContentId; + } + + /* IZoomService Methods */ + + @Override + public Long createNotebookEntry(Long id, Integer idType, String signature, Integer userID, String entry) { + return coreNotebookService.createNotebookEntry(id, idType, signature, userID, "", entry); + } + + public NotebookEntry getEntry(Long id, Integer idType, String signature, Integer userID) { + List list = coreNotebookService.getEntry(id, idType, signature, userID); + if ((list == null) || list.isEmpty()) { + return null; + } else { + return list.get(0); + } + } + + @Override + public NotebookEntry getNotebookEntry(Long uid) { + return coreNotebookService.getEntry(uid); + } + + @Override + public void updateNotebookEntry(Long uid, String entry) { + coreNotebookService.updateEntry(uid, "", entry); + } + + @Override + public void updateNotebookEntry(NotebookEntry notebookEntry) { + coreNotebookService.updateEntry(notebookEntry); + } + + @Override + public Long getDefaultContentIdBySignature(String toolSignature) { + return toolService.getToolDefaultContentIdBySignature(toolSignature); + } + + @Override + public Zoom getDefaultContent() { + Long defaultContentID = getDefaultContentIdBySignature(ZoomConstants.TOOL_SIGNATURE); + Zoom defaultContent = getZoomByContentId(defaultContentID); + if (defaultContent == null) { + String error = "Could not retrieve default content record for this tool"; + ZoomService.logger.error(error); + } + return defaultContent; + } + + @Override + public Zoom copyDefaultContent(Long newContentID) { + if (newContentID == null) { + String error = "Cannot copy the Zoom tools default content: + " + "newContentID is null"; + ZoomService.logger.error(error); + } + + Zoom defaultContent = getDefaultContent(); + // create new zoom using the newContentID + Zoom newContent = new Zoom(); + newContent = Zoom.newInstance(defaultContent, newContentID, zoomToolContentHandler); + saveOrUpdateZoom(newContent); + return newContent; + } + + @Override + @SuppressWarnings("unchecked") + public Zoom getZoomByContentId(Long toolContentID) { + List list = zoomDAO.findByProperty(Zoom.class, "toolContentId", toolContentID); + if (list.isEmpty()) { + return null; + } else { + return list.get(0); + } + } + + @Override + public boolean isGroupedActivity(long toolContentID) { + return toolService.isGroupedActivity(toolContentID); + } + + @Override + public void auditLogStartEditingActivityInMonitor(long toolContentID) { + toolService.auditLogStartEditingActivityInMonitor(toolContentID); + } + + @Override + @SuppressWarnings("unchecked") + public ZoomSession getSessionBySessionId(Long toolSessionId) { + List list = zoomDAO.findByProperty(ZoomSession.class, "sessionId", toolSessionId); + if (list.isEmpty()) { + return null; + } else { + return list.get(0); + } + } + + @Override + @SuppressWarnings("unchecked") + public ZoomUser getUserByUserIdAndSessionId(Integer userId, Long toolSessionId) { + Map map = new HashMap(); + map.put("userId", userId); + map.put("zoomSession.sessionId", toolSessionId); + List list = zoomDAO.findByProperties(ZoomUser.class, map); + if (list.isEmpty()) { + return null; + } else { + return list.get(0); + } + } + + @Override + @SuppressWarnings("unchecked") + public ZoomUser getUserByUID(Long uid) { + List list = zoomDAO.findByProperty(ZoomUser.class, "uid", uid); + if (list.isEmpty()) { + return null; + } else { + return list.get(0); + } + } + + @Override + public void saveOrUpdateZoom(Zoom zoom) { + zoomDAO.insertOrUpdate(zoom); + } + + @Override + public void saveOrUpdateZoomSession(ZoomSession zoomSession) { + zoomDAO.insertOrUpdate(zoomSession); + } + + @Override + public void saveOrUpdateZoomUser(ZoomUser zoomUser) { + zoomDAO.insertOrUpdate(zoomUser); + } + + @Override + public ZoomUser createZoomUser(UserDTO user, ZoomSession zoomSession) { + ZoomUser zoomUser = new ZoomUser(user, zoomSession); + saveOrUpdateZoomUser(zoomUser); + return zoomUser; + } + + /** + * Set the description, throws away the title value as this is not supported in 2.0 + */ + public void setReflectiveData(Long toolContentId, String title, String description) + throws ToolException, DataMissingException { + + ZoomService.logger.warn( + "Setting the reflective field on a zoom. This doesn't make sense as the zoom is for reflection and we don't reflect on reflection!"); + Zoom zoom = getZoomByContentId(toolContentId); + if (zoom == null) { + throw new DataMissingException("Unable to set reflective data titled " + title + + " on activity toolContentId " + toolContentId + " as the tool content does not exist."); + } + + zoom.setReflectOnActivity(Boolean.TRUE); + zoom.setReflectInstructions(description); + } + + // ========================================================================================= + /* Used by Spring to "inject" the linked objects */ + + public IZoomDAO getZoomDAO() { + return zoomDAO; + } + + public void setZoomDAO(IZoomDAO zoomDAO) { + this.zoomDAO = zoomDAO; + } + + public IToolContentHandler getZoomToolContentHandler() { + return zoomToolContentHandler; + } + + public void setZoomToolContentHandler(IToolContentHandler zoomToolContentHandler) { + this.zoomToolContentHandler = zoomToolContentHandler; + } + + public ILamsToolService getToolService() { + return toolService; + } + + public void setToolService(ILamsToolService toolService) { + this.toolService = toolService; + } + + public ILearnerService getLearnerService() { + return learnerService; + } + + public void setLearnerService(ILearnerService learnerService) { + this.learnerService = learnerService; + } + + public IExportToolContentService getExportContentService() { + return exportContentService; + } + + public void setExportContentService(IExportToolContentService exportContentService) { + this.exportContentService = exportContentService; + } + + public ICoreNotebookService getCoreNotebookService() { + return coreNotebookService; + } + + public void setCoreNotebookService(ICoreNotebookService coreNotebookService) { + this.coreNotebookService = coreNotebookService; + } + + @Override + public ToolCompletionStatus getCompletionStatus(Long learnerId, Long toolSessionId) { + ZoomUser learner = getUserByUserIdAndSessionId(learnerId.intValue(), toolSessionId); + if (learner == null) { + return new ToolCompletionStatus(ToolCompletionStatus.ACTIVITY_NOT_ATTEMPTED, null, null); + } + + return new ToolCompletionStatus(learner.isFinishedActivity() ? ToolCompletionStatus.ACTIVITY_COMPLETED + : ToolCompletionStatus.ACTIVITY_ATTEMPTED, null, null); + } + + @Override + public Boolean chooseApi(Long zoomUid) throws IOException { + Zoom zoom = (Zoom) zoomDAO.find(Zoom.class, zoomUid); + List apis = getApis(); + if (apis.isEmpty()) { + return null; + } + ZoomApi chosenApi = null; + TreeMap liveApis = new TreeMap(); + for (ZoomApi api : apis) { + String meetingListURL = "users/" + api.getEmail() + "/meetings?type=live"; + HttpURLConnection connection = ZoomService.getZoomConnection(meetingListURL, "GET", null, api); + ObjectNode resultJSON = ZoomService.getReponse(connection); + boolean noLiveMeetings = resultJSON != null && JsonUtil.optInt(resultJSON, "total_records") == 0; + if (noLiveMeetings) { + // found a free API + chosenApi = api; + break; + } + // find the oldest live meeting + // string comparing of dates works fine + String oldestMeetingStartTime = null; + + ArrayNode meetingsJSON = JsonUtil.optArray(resultJSON, "meetings"); + for (int meetingIndex = 0; meetingIndex < meetingsJSON.size(); meetingIndex++) { + ObjectNode meetingJSON = (ObjectNode) meetingsJSON.get(meetingIndex); + String meetingStartTime = JsonUtil.optString(meetingJSON, "start_time"); + if (meetingStartTime == null) { + meetingStartTime = JsonUtil.optString(meetingJSON, "created_at"); + } + if (oldestMeetingStartTime == null || meetingStartTime.compareTo(oldestMeetingStartTime) < 0) { + oldestMeetingStartTime = meetingStartTime; + } + } + liveApis.put(oldestMeetingStartTime, api); + } + + boolean result = chosenApi != null; + if (!result) { + chosenApi = liveApis.firstEntry().getValue(); + } + zoom.setApi(chosenApi); + zoomDAO.update(zoom); + return result; + } + + @Override + public String createMeeting(Long zoomUid) throws IOException { + Zoom zoom = (Zoom) zoomDAO.find(Zoom.class, zoomUid); + if (zoom.getMeetingId() != null) { + return zoom.getMeetingStartUrl(); + } + if (zoom.getApi() == null) { + throw new ZoomException("Can not create a meeting without API keys chosen"); + } + ObjectNode bodyJSON = JsonNodeFactory.instance.objectNode(); + Date currentTime = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + String startTime = sdf.format(currentTime); + bodyJSON.put("topic", zoom.getTitle()); + bodyJSON.put("type", 2); + bodyJSON.put("start_time", startTime); + HttpURLConnection connection = ZoomService.getZoomConnection("users/" + zoom.getApi().getEmail() + "/meetings", + "POST", bodyJSON.toString(), zoom.getApi()); + ObjectNode responseJSON = ZoomService.getReponse(connection); + String meetingId = String.valueOf(JsonUtil.optString(responseJSON, "id")); + zoom.setMeetingId(meetingId); + + ZoomService.configureMeeting(zoom); + + zoomDAO.update(zoom); + if (logger.isDebugEnabled()) { + logger.debug("Created meeting: " + meetingId); + } + return zoom.getMeetingStartUrl(); + } + + @Override + public String registerUser(Long zoomUid, Long userUid, String sessionName) throws IOException { + ZoomUser user = (ZoomUser) zoomDAO.find(ZoomUser.class, userUid); + if (user.getMeetingJoinUrl() != null) { + return user.getMeetingJoinUrl(); + } + Zoom zoom = (Zoom) zoomDAO.find(Zoom.class, zoomUid); + + ObjectNode bodyJSON = JsonNodeFactory.instance.objectNode(); + String lastName = user.getLastName(); + if (isGroupedActivity(zoom.getToolContentId())) { + lastName += " (" + sessionName + ")"; + } + bodyJSON.put("email", user.getEmail()).put("first_name", user.getFirstName()).put("last_name", lastName); + HttpURLConnection connection = ZoomService.getZoomConnection("meetings/" + zoom.getMeetingId() + "/registrants", + "POST", bodyJSON.toString(), zoom.getApi()); + ObjectNode responseJSON = ZoomService.getReponse(connection); + String meetingJoinURL = JsonUtil.optString(responseJSON, "join_url"); + user.setMeetingJoinUrl(meetingJoinURL); + zoomDAO.update(user); + if (logger.isDebugEnabled()) { + logger.debug("Registerd user with UID: " + user.getUid() + " for meeting: " + zoom.getMeetingId()); + } + return meetingJoinURL; + } + + @SuppressWarnings("unchecked") + @Override + public List getApis() { + return zoomDAO.findAll(ZoomApi.class); + } + + @Override + public void saveApis(List apis) { + List existingApis = getApis(); + Set delete = new HashSet(); + Set saved = new HashSet(); + for (ZoomApi existingApi : existingApis) { + boolean found = false; + for (ZoomApi api : apis) { + if (existingApi.getEmail().equalsIgnoreCase(api.getEmail())) { + found = true; + saved.add(api.getEmail()); + if (!existingApi.getKey().equals(api.getKey()) + || !existingApi.getSecret().equals(api.getSecret())) { + existingApi.setKey(api.getKey()); + existingApi.setSecret(api.getSecret()); + zoomDAO.update(existingApi); + } + break; + } + } + if (!found) { + delete.add(existingApi.getUid()); + } + } + for (Long uidToDelete : delete) { + zoomDAO.deleteById(ZoomApi.class, uidToDelete); + } + for (ZoomApi api : apis) { + if (!saved.contains(api.getEmail())) { + zoomDAO.insert(api); + } + } + } + + @Override + public boolean pingZoomApi(Long uid) throws IOException { + ZoomApi api = (ZoomApi) zoomDAO.find(ZoomApi.class, uid); + HttpURLConnection connection = ZoomService.getZoomConnection("users/email?email=" + api.getEmail(), "GET", null, + api); + ObjectNode resultJSON = ZoomService.getReponse(connection); + return resultJSON != null && JsonUtil.optBoolean(resultJSON, "existed_email"); + } + + private static String generateJWT(ZoomApi api) { + Date expiration = new Date(System.currentTimeMillis() + ZoomConstants.JWT_EXPIRATION_MILISECONDS); + return Jwts.builder().setHeaderParam("typ", "JWT").setIssuer(api.getKey()).setExpiration(expiration) + .signWith(SignatureAlgorithm.HS256, api.getSecret().getBytes()).compact(); + } + + private static HttpURLConnection getZoomConnection(String urlSuffix, String method, String body, ZoomApi api) + throws IOException { + URL url = new URL(ZoomConstants.ZOOM_API_URL + urlSuffix); + HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); + connection.setRequestProperty("Authorization", "Bearer " + ZoomService.generateJWT(api)); + switch (method) { + case "PATCH": + ZoomService.setRequestMethod(connection, method); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setDoOutput(true); + break; + case "POST": + connection.setRequestMethod(method); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setDoOutput(true); + break; + default: + connection.setRequestMethod(method); + break; + } + if (body != null) { + OutputStream os = connection.getOutputStream(); + OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8"); + osw.write(body); + osw.flush(); + osw.close(); + os.close(); + } + return connection; + } + + /** + * Put extra options which can not be set when creating a meeting + */ + private static void configureMeeting(Zoom zoom) throws IOException { + ObjectNode bodyJSON = JsonNodeFactory.instance.objectNode(); + ObjectNode settings = JsonNodeFactory.instance.objectNode(); + // this setting can not be set during creation, thus we need another call + settings.put("registrants_confirmation_email", false); + // these settings could have been set during creation, but this call would have overwritten them, so we set them here + settings.put("approval_type", 0); + settings.put("join_before_host", !zoom.isStartInMonitor()); + bodyJSON.set("settings", settings); + if (zoom.getDuration() != null) { + bodyJSON.put("duration", zoom.getDuration()); + } + HttpURLConnection connection = ZoomService.getZoomConnection("meetings/" + zoom.getMeetingId(), "PATCH", + bodyJSON.toString(), zoom.getApi()); + ZoomService.getReponse(connection); + // verify changes and get the new start URL + connection = ZoomService.getZoomConnection("meetings/" + zoom.getMeetingId(), "GET", null, zoom.getApi()); + ObjectNode responseJSON = ZoomService.getReponse(connection); + String startURL = JsonUtil.optString(responseJSON, "start_url"); + zoom.setMeetingStartUrl(startURL); + + if (logger.isDebugEnabled()) { + logger.debug("Configured meeting: " + zoom.getMeetingId()); + } + } + + private static void setRequestMethod(HttpURLConnection connection, String method) { + try { + final Object target; + if (connection instanceof HttpsURLConnectionImpl) { + final Field delegate = HttpsURLConnectionImpl.class.getDeclaredField("delegate"); + delegate.setAccessible(true); + target = delegate.get(connection); + } else { + target = connection; + } + final Field f = HttpURLConnection.class.getDeclaredField("method"); + f.setAccessible(true); + f.set(target, method); + } catch (IllegalAccessException | NoSuchFieldException ex) { + throw new AssertionError(ex); + } + } + + private static ObjectNode getReponse(HttpURLConnection connection) throws IOException { + ObjectNode responseJSON = null; + try { + connection.connect(); + int code = connection.getResponseCode(); + String response = null; + + if (code < 300) { + StringWriter writer = new StringWriter(); + IOUtils.copy(connection.getInputStream(), writer); + response = writer.toString(); + if (response != null && response.startsWith("{")) { + responseJSON = JsonUtil.readObject(response); + } + } + + if (logger.isDebugEnabled()) { + logger.debug("Server response: " + code + " " + connection.getResponseMessage() + " " + response); + } + } finally { + connection.disconnect(); + } + return responseJSON; + } +} \ No newline at end of file Index: lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/util/ZoomUtil.java =================================================================== diff -u --- lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/util/ZoomUtil.java (revision 0) +++ lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/util/ZoomUtil.java (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -0,0 +1,61 @@ +/**************************************************************** + * Copyright (C) 2005 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 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.tool.zoom.util; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.struts.action.ActionErrors; +import org.apache.struts.action.ActionMessage; +import org.apache.struts.action.ActionMessages; +import org.lamsfoundation.lams.tool.zoom.model.Zoom; +import org.lamsfoundation.lams.tool.zoom.service.IZoomService; + +public class ZoomUtil { + + /** + * Creates and starts a Zoom meeting + */ + public static ActionErrors startMeeting(IZoomService zoomService, Zoom zoom, HttpServletRequest request) + throws IOException { + ActionErrors errors = new ActionErrors(); + String meetingURL = zoom.getMeetingStartUrl(); + if (meetingURL == null) { + Boolean apiOK = zoomService.chooseApi(zoom.getUid()); + if (apiOK == null) { + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.api.none.configured")); + request.setAttribute("skipContent", true); + } else { + if (!apiOK) { + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.api.reuse")); + } + meetingURL = zoomService.createMeeting(zoom.getUid()); + } + } + + request.setAttribute(ZoomConstants.ATTR_MEETING_URL, meetingURL); + return errors; + } +} \ No newline at end of file Index: lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/web/actions/AdminAction.java =================================================================== diff -u --- lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/web/actions/AdminAction.java (revision 0) +++ lams_tool_zoom/src/java/org/lamsfoundation/lams/tool/zoom/web/actions/AdminAction.java (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -0,0 +1,104 @@ +/**************************************************************** + * Copyright (C) 2005 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 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.tool.zoom.web.actions; + +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.apache.struts.action.ActionErrors; +import org.apache.struts.action.ActionForm; +import org.apache.struts.action.ActionForward; +import org.apache.struts.action.ActionMapping; +import org.apache.struts.action.ActionMessage; +import org.apache.struts.action.ActionMessages; +import org.apache.struts.actions.DispatchAction; +import org.lamsfoundation.lams.tool.zoom.model.ZoomApi; +import org.lamsfoundation.lams.tool.zoom.service.IZoomService; +import org.lamsfoundation.lams.tool.zoom.service.ZoomServiceProxy; +import org.lamsfoundation.lams.util.JsonUtil; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; + +public class AdminAction extends DispatchAction { + + private IZoomService zoomService; + + private static final Logger logger = Logger.getLogger(AdminAction.class); + + @Override + public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + // set up zoomService + zoomService = ZoomServiceProxy.getZoomService(this.getServlet().getServletContext()); + return super.execute(mapping, form, request, response); + } + + @Override + public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + List apis = zoomService.getApis(); + ArrayNode apisJSON = JsonNodeFactory.instance.arrayNode(); + for (ZoomApi api : apis) { + apisJSON.add(api.toJSON()); + } + request.setAttribute("apis", apisJSON); + return mapping.findForward("success"); + } + + public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws Exception { + String apisJSONString = request.getParameter("apisJSON"); + ArrayNode apisJSON = JsonUtil.readArray(apisJSONString); + List apis = new LinkedList(); + for (int index = 0; index < apisJSON.size(); index++) { + ObjectNode apiJSON = (ObjectNode) apisJSON.get(index); + ZoomApi api = new ZoomApi(apiJSON); + apis.add(api); + } + zoomService.saveApis(apis); + request.setAttribute("saveOK", true); + if (logger.isDebugEnabled()) { + logger.debug("Saved " + apis.size() + " Zoom APIs"); + } + + ActionErrors errors = new ActionErrors(); + apis = zoomService.getApis(); + for (ZoomApi api : apis) { + if (!zoomService.pingZoomApi(api.getUid())) { + errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("error.api.ping", api.getEmail())); + } + } + if (!errors.isEmpty()) { + this.addErrors(request, errors); + } + + return unspecified(mapping, form, request, response); + } +} \ No newline at end of file Index: lams_tool_zoom/web/WEB-INF/web.xml =================================================================== diff -u --- lams_tool_zoom/web/WEB-INF/web.xml (revision 0) +++ lams_tool_zoom/web/WEB-INF/web.xml (revision 266434d5ec15cc4026c93a740c3110c046b1d88a) @@ -0,0 +1,316 @@ + + + + + + javax.servlet.jsp.jstl.fmt.localizationContext + org.lamsfoundation.lams.tool.zoom.ApplicationResources + + + + contextConfigLocation + classpath:/org/lamsfoundation/lams/tool/zoom/dbupdates/autopatchContext.xml + + + locatorFactorySelector + classpath:/org/lamsfoundation/lams/beanRefContext.xml + + + parentContextKey + context.central + + + + SystemSessionFilter + + org.lamsfoundation.lams.web.session.SystemSessionFilter + + + + hibernateFilter + + org.springframework.orm.hibernate5.support.OpenSessionInViewFilter + + + sessionFactoryBeanName + coreSessionFactory + + + + LocaleFilter + + org.lamsfoundation.lams.web.filter.LocaleFilter + + + + + SystemSessionFilter + /* + + + hibernateFilter + /* + + + LocaleFilter + /* + + + + + org.springframework.web.context.ContextLoaderListener + + + + + action + org.apache.struts.action.ActionServlet + + config + /WEB-INF/struts-config.xml + + + debug + 999 + + + detail + 2 + + + validate + true + + 1 + + + + + + Connector + net.fckeditor.connector.ConnectorServlet + + baseDir + /UserFiles/ + + + debug + false + + 1 + + + + + Attachment Download + Attachment Download + download + org.lamsfoundation.lams.contentrepository.client.ToolDownload + + toolContentHandlerBeanName + zoomToolContentHandler + + 3 + + + + + action + *.do + + + + + Connector + /ckeditor/filemanager/browser/default/connectors/jsp/connector + + + + download + /download/* + + + + + 500 + /error.jsp + + + 403 + /403.jsp + + + 404 + /404.jsp + + + + + + + + + tags-bean + /WEB-INF/tlds/struts/struts-bean.tld + + + tags-html + /WEB-INF/tlds/struts/struts-html.tld + + + tags-logic + /WEB-INF/tlds/struts/struts-logic.tld + + + tags-tiles + /WEB-INF/tlds/struts/struts-tiles.tld + + + + + + tags-fmt + /WEB-INF/tlds/jstl/fmt.tld + + + tags-core + /WEB-INF/tlds/jstl/c.tld + + + tags-function + /WEB-INF/tlds/jstl/fn.tld + + + tags-xml + /WEB-INF/tlds/jstl/x.tld + + + + + + tags-permittedTaglibs + /WEB-INF/tlds/jstl/permittedTaglibs.tld + + + tags-scriptfree + /WEB-INF/tlds/jstl/scriptfree.tld + + + + + + tags-lams + /WEB-INF/tlds/lams/lams.tld + + + + + + + + + + Secure content + /* + GET + POST + + + LEARNER + MONITOR + AUTHOR + SYSADMIN + + + + + + Authoring content + /authoring/* + /pages/authoring/* + /authoring.do + GET + POST + + + AUTHOR + MONITOR + SYSADMIN + + + + + Staff content + /pages/monitoring/* + /monitoring.do + GET + POST + + + MONITOR + SYSADMIN + + + + + + Admin content + /admin/* + /pages/admin/* + GET + POST + + + SYSADMIN + + + + + + FORM + LAMS + + /login.jsp + /login.jsp?failed=y + + + + + Student + LEARNER + + + + Authors Learning Designs + AUTHOR + + + + Member of Staff + MONITOR + + + + Group Manager + GROUP MANAGER + + + Group Administrator + GROUP ADMIN + + + LAMS System Adminstrator + SYSADMIN + + \ No newline at end of file