From 5009609dcbe6e5b7ff1cea753b47205d3996726c Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 30 Nov 2020 13:12:00 +0100 Subject: [PATCH] Introduce form submission listener. --- .../OSGI-INF/odkSubmissionServlet.xml | 1 + knowledge/org.argeo.support.odk/pom.xml | 5 +++ .../odk/servlet/OdkSubmissionServlet.java | 41 ++++++++++++++++--- .../xforms/FormSubmissionListener.java | 10 +++++ .../src/org/argeo/suite/SuiteUtils.java | 28 +++++++++---- .../suite/core/SuiteMaintenanceService.java | 2 + .../src/org/argeo/suite/ui/SuiteApp.java | 2 +- 7 files changed, 76 insertions(+), 13 deletions(-) create mode 100644 knowledge/org.argeo.support.xforms/src/org/argeo/support/xforms/FormSubmissionListener.java diff --git a/knowledge/org.argeo.support.odk/OSGI-INF/odkSubmissionServlet.xml b/knowledge/org.argeo.support.odk/OSGI-INF/odkSubmissionServlet.xml index 1e1bcb1..bce66c4 100644 --- a/knowledge/org.argeo.support.odk/OSGI-INF/odkSubmissionServlet.xml +++ b/knowledge/org.argeo.support.odk/OSGI-INF/odkSubmissionServlet.xml @@ -8,4 +8,5 @@ + diff --git a/knowledge/org.argeo.support.odk/pom.xml b/knowledge/org.argeo.support.odk/pom.xml index 69cc95e..36861fe 100644 --- a/knowledge/org.argeo.support.odk/pom.xml +++ b/knowledge/org.argeo.support.odk/pom.xml @@ -18,5 +18,10 @@ org.argeo.suite.core 2.1.16-SNAPSHOT + + org.argeo.suite + org.argeo.support.xforms + 2.1.16-SNAPSHOT + diff --git a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java index f1a1d84..23317c8 100644 --- a/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java +++ b/knowledge/org.argeo.support.odk/src/org/argeo/support/odk/servlet/OdkSubmissionServlet.java @@ -5,6 +5,8 @@ import java.time.Instant; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; +import java.util.HashSet; +import java.util.Set; import javax.jcr.ImportUUIDBehavior; import javax.jcr.Node; @@ -21,12 +23,14 @@ import javax.servlet.http.Part; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.api.NodeUtils; +import org.argeo.cms.auth.CmsSession; import org.argeo.cms.servlet.ServletAuthUtils; -import org.argeo.entity.EntityNames; -import org.argeo.entity.EntityType; import org.argeo.jcr.Jcr; import org.argeo.jcr.JcrUtils; +import org.argeo.suite.SuiteUtils; import org.argeo.support.odk.OrxType; +import org.argeo.support.xforms.FormSubmissionListener; /** Receives a form submission. */ public class OdkSubmissionServlet extends HttpServlet { @@ -40,6 +44,8 @@ public class OdkSubmissionServlet extends HttpServlet { private Repository repository; + private Set submissionListeners = new HashSet<>(); + @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/xml; charset=utf-8"); @@ -50,9 +56,24 @@ public class OdkSubmissionServlet extends HttpServlet { Session session = ServletAuthUtils.doAs(() -> Jcr.login(repository, null), req); try { - Node submissions = JcrUtils.mkdirs(session, - "/" + EntityType.form.get() + "/" + EntityNames.SUBMISSIONS_BASE); - Node submission = submissions.addNode(submissionNameFormatter.format(Instant.now()), +// Node submissions = JcrUtils.mkdirs(session, +// "/" + EntityType.form.get() + "/" + EntityNames.SUBMISSIONS_BASE); + CmsSession cmsSession = ServletAuthUtils.getCmsSession(req); + + ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(ServletAuthUtils.class.getClassLoader()); + Session adminSession = null; + try { + // TODO centralise at a deeper level + adminSession = NodeUtils.openDataAdminSession(repository, null); + SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession); + } finally { + Jcr.logout(adminSession); + Thread.currentThread().setContextClassLoader(currentContextCl); + } + + Node cmsSessionNode = SuiteUtils.getCmsSessionNode(session, cmsSession); + Node submission = cmsSessionNode.addNode(submissionNameFormatter.format(Instant.now()), OrxType.submission.get()); for (Part part : req.getParts()) { if (log.isDebugEnabled()) @@ -77,6 +98,9 @@ public class OdkSubmissionServlet extends HttpServlet { } } session.save(); + for (FormSubmissionListener submissionListener : submissionListeners) { + submissionListener.formSubmissionReceived(submission); + } } catch (RepositoryException e) { e.printStackTrace(); resp.setStatus(503); @@ -93,4 +117,11 @@ public class OdkSubmissionServlet extends HttpServlet { this.repository = repository; } + public synchronized void addSubmissionListener(FormSubmissionListener listener) { + submissionListeners.add(listener); + } + + public synchronized void removeSubmissionListener(FormSubmissionListener listener) { + submissionListeners.remove(listener); + } } diff --git a/knowledge/org.argeo.support.xforms/src/org/argeo/support/xforms/FormSubmissionListener.java b/knowledge/org.argeo.support.xforms/src/org/argeo/support/xforms/FormSubmissionListener.java new file mode 100644 index 0000000..e23ef36 --- /dev/null +++ b/knowledge/org.argeo.support.xforms/src/org/argeo/support/xforms/FormSubmissionListener.java @@ -0,0 +1,10 @@ +package org.argeo.support.xforms; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; + +/** Called when a user has received a new form submission. */ +public interface FormSubmissionListener { + /** Called after a form submission has been stored in the user area. */ + void formSubmissionReceived(Node node) throws RepositoryException; +} diff --git a/org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java b/org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java index f264bdf..18c91a1 100644 --- a/org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java +++ b/org.argeo.suite.core/src/org/argeo/suite/SuiteUtils.java @@ -6,9 +6,11 @@ import javax.jcr.Session; import javax.jcr.nodetype.NodeType; import javax.jcr.security.Privilege; import javax.naming.ldap.LdapName; +import javax.security.auth.x500.X500Principal; import org.argeo.cms.auth.CmsSession; import org.argeo.entity.EntityType; +import org.argeo.jackrabbit.security.JackrabbitSecurityUtils; import org.argeo.jcr.JcrException; import org.argeo.jcr.JcrUtils; import org.argeo.naming.LdapAttrs; @@ -33,6 +35,10 @@ public class SuiteUtils { userNode.setProperty(LdapAttrs.distinguishedName.property(), userDn.toString()); userNode.setProperty(LdapAttrs.uid.property(), uid); adminSession.save(); + JackrabbitSecurityUtils.denyPrivilege(adminSession, userNode.getPath(), SuiteRole.coworker.dn(), + Privilege.JCR_READ); + JcrUtils.addPrivilege(adminSession, userNode.getPath(), new X500Principal(userDn.toString()).getName(), + Privilege.JCR_ALL); } else { userNode = usersBase.getNode(uid); } @@ -42,7 +48,15 @@ public class SuiteUtils { } } - public static Node getOrCreateSessionDir(Session adminSession, CmsSession cmsSession) { + public static Node getCmsSessionNode(Session session, CmsSession cmsSession) { + try { + return session.getNode(getUserNodePath(cmsSession.getUserDn()) + '/' + cmsSession.getUuid().toString()); + } catch (RepositoryException e) { + throw new JcrException("Cannot get session dir for " + cmsSession, e); + } + } + + public static Node getOrCreateCmsSessionNode(Session adminSession, CmsSession cmsSession) { try { LdapName userDn = cmsSession.getUserDn(); // String uid = userDn.get(userDn.size() - 1); @@ -58,17 +72,17 @@ public class SuiteUtils { // userNode = usersBase.getNode(uid); // } String cmsSessionUuid = cmsSession.getUuid().toString(); - Node userDir; + Node cmsSessionNode; if (!userNode.hasNode(cmsSessionUuid)) { - userDir = userNode.addNode(cmsSessionUuid, NodeType.NT_UNSTRUCTURED); - userDir.addMixin(NodeType.MIX_CREATED); + cmsSessionNode = userNode.addNode(cmsSessionUuid, NodeType.NT_UNSTRUCTURED); + cmsSessionNode.addMixin(NodeType.MIX_CREATED); adminSession.save(); - JcrUtils.addPrivilege(adminSession, userDir.getPath(), cmsSession.getUserDn().toString(), + JcrUtils.addPrivilege(adminSession, cmsSessionNode.getPath(), cmsSession.getUserRole(), Privilege.JCR_ALL); } else { - userDir = userNode.getNode(cmsSessionUuid); + cmsSessionNode = userNode.getNode(cmsSessionUuid); } - return userDir; + return cmsSessionNode; } catch (RepositoryException e) { throw new JcrException("Cannot create session dir for " + cmsSession, e); } diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java index db6ac91..685e993 100644 --- a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java +++ b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteMaintenanceService.java @@ -12,6 +12,7 @@ import org.argeo.api.NodeConstants; import org.argeo.entity.EntityType; import org.argeo.jcr.JcrUtils; import org.argeo.maintenance.AbstractMaintenanceService; +import org.argeo.suite.SuiteRole; /** Initialises an Argeo Suite backend. */ public class SuiteMaintenanceService extends AbstractMaintenanceService { @@ -33,6 +34,7 @@ public class SuiteMaintenanceService extends AbstractMaintenanceService { public void configurePrivileges(Session adminSession) throws RepositoryException { JcrUtils.addPrivilege(adminSession, EntityType.user.basePath(), NodeConstants.ROLE_USER_ADMIN, Privilege.JCR_ALL); + JcrUtils.addPrivilege(adminSession, "/", SuiteRole.coworker.dn(), Privilege.JCR_READ); } } diff --git a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java index e363a62..31763fe 100644 --- a/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java +++ b/org.argeo.suite.ui/src/org/argeo/suite/ui/SuiteApp.java @@ -136,7 +136,7 @@ public class SuiteApp extends AbstractCmsApp implements EventHandler { Session adminSession = null; try { adminSession = NodeUtils.openDataAdminSession(getRepository(), null); - Node userDir = SuiteUtils.getOrCreateSessionDir(adminSession, cmsSession); + Node userDir = SuiteUtils.getOrCreateCmsSessionNode(adminSession, cmsSession); ui.initSessions(getRepository(), userDir.getPath()); } finally { Jcr.logout(adminSession); -- 2.30.2