You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by sh...@apache.org on 2017/10/31 16:24:01 UTC

incubator-unomi git commit: UNOMI-133 Add (GDPR) consents to visitor profiles - Add new consents object attached to visitor profile - Added a new event to update multiple consents - Added a condition to match the event - Added an action to modify the con

Repository: incubator-unomi
Updated Branches:
  refs/heads/master 629284e4c -> de5dea661


UNOMI-133 Add (GDPR) consents to visitor profiles
- Add new consents object attached to visitor profile
- Added a new event to update multiple consents
- Added a condition to match the event
- Added an action to modify the consents

This is not yet complete we still need a rule to match the event to the action, as well as internal events to be able to react to individual consent changes.

Signed-off-by: Serge Huber <sh...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/incubator-unomi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-unomi/commit/de5dea66
Tree: http://git-wip-us.apache.org/repos/asf/incubator-unomi/tree/de5dea66
Diff: http://git-wip-us.apache.org/repos/asf/incubator-unomi/diff/de5dea66

Branch: refs/heads/master
Commit: de5dea66154dc8454d89430e23f5fb4ae460ac01
Parents: 629284e
Author: Serge Huber <sh...@apache.org>
Authored: Tue Oct 31 17:23:54 2017 +0100
Committer: Serge Huber <sh...@apache.org>
Committed: Tue Oct 31 17:23:54 2017 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/unomi/api/Consent.java | 72 ++++++++++++++++++++
 .../java/org/apache/unomi/api/ConsentGrant.java | 22 ++++++
 .../org/apache/unomi/api/ContextResponse.java   | 23 +++++++
 .../main/java/org/apache/unomi/api/Profile.java | 48 +++++++++++--
 .../actions/ModifyConsentsAction.java           | 67 ++++++++++++++++++
 .../cxs/actions/modifyConsentsAction.json       | 16 +++++
 .../modifyConsentsEventCondition.json           | 23 +++++++
 .../resources/OSGI-INF/blueprint/blueprint.xml  |  8 +++
 .../org/apache/unomi/web/ContextServlet.java    |  1 +
 9 files changed, 276 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/de5dea66/api/src/main/java/org/apache/unomi/api/Consent.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/Consent.java b/api/src/main/java/org/apache/unomi/api/Consent.java
new file mode 100644
index 0000000..6359a52
--- /dev/null
+++ b/api/src/main/java/org/apache/unomi/api/Consent.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.api;
+
+import java.util.Date;
+
+/**
+ * A consent is an object attached to a profile that indicates whether the profile has agreed or denied a special
+ * consent type. For example a user might have agreed to receiving a newsletter but might have not agreed to being
+ * tracked.
+ */
+public class Consent extends Item {
+
+    private String typeId; // types are defined and managed externally of Apache Unomi
+    private ConsentGrant grant;
+    private Date grantDate;
+    private Date revokeDate;
+
+    public Consent(String itemId, String typeId, ConsentGrant grant, Date grantDate, Date revokeDate) {
+        super(itemId);
+        this.typeId = typeId;
+        this.grant = grant;
+        this.grantDate = grantDate;
+        this.revokeDate = revokeDate;
+    }
+
+    public void setTypeId(String typeId) {
+        this.typeId = typeId;
+    }
+
+    public String getTypeId() {
+        return typeId;
+    }
+
+    public ConsentGrant getGrant() {
+        return grant;
+    }
+
+    public void setGrant(ConsentGrant grant) {
+        this.grant = grant;
+    }
+
+    public Date getGrantDate() {
+        return grantDate;
+    }
+
+    public void setGrantDate(Date grantDate) {
+        this.grantDate = grantDate;
+    }
+
+    public Date getRevokeDate() {
+        return revokeDate;
+    }
+
+    public void setRevokeDate(Date revokeDate) {
+        this.revokeDate = revokeDate;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/de5dea66/api/src/main/java/org/apache/unomi/api/ConsentGrant.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/ConsentGrant.java b/api/src/main/java/org/apache/unomi/api/ConsentGrant.java
new file mode 100644
index 0000000..a72125d
--- /dev/null
+++ b/api/src/main/java/org/apache/unomi/api/ConsentGrant.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.api;
+
+public enum ConsentGrant {
+    GRANT,
+    DENY
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/de5dea66/api/src/main/java/org/apache/unomi/api/ContextResponse.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/ContextResponse.java b/api/src/main/java/org/apache/unomi/api/ContextResponse.java
index 58bcadd..184586b 100644
--- a/api/src/main/java/org/apache/unomi/api/ContextResponse.java
+++ b/api/src/main/java/org/apache/unomi/api/ContextResponse.java
@@ -21,6 +21,7 @@ import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.services.RulesService;
 
 import java.io.Serializable;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -50,6 +51,8 @@ public class ContextResponse implements Serializable {
 
     private boolean anonymousBrowsing;
 
+    private Map<String, Consent> consents = new LinkedHashMap<>();
+
     /**
      * Retrieves the profile identifier associated with the profile of the user on behalf of which the client performed the context request.
      *
@@ -203,4 +206,24 @@ public class ContextResponse implements Serializable {
     public void setAnonymousBrowsing(boolean anonymousBrowsing) {
         this.anonymousBrowsing = anonymousBrowsing;
     }
+
+    /**
+     * Retrieves the map of consents for the current profile.
+     * @return a Map where the key is the name of the consent identifier, and the value is a consent object that
+     * contains all the consent data such as whether the consent was granted or deny, the date of granting/denying
+     * the date at which the consent will be revoked automatically.
+     */
+    public Map<String, Consent> getConsents() {
+        return consents;
+    }
+
+    /**
+     * Sets the map of consents for the current profile.
+     * @param consents a Map where the key is the name of the consent identifier, and the value is a consent object that
+     * contains all the consent data such as whether the consent was granted or deny, the date of granting/denying
+     * the date at which the consent will be revoked automatically.
+     */
+    public void setConsents(Map<String, Consent> consents) {
+        this.consents = consents;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/de5dea66/api/src/main/java/org/apache/unomi/api/Profile.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/unomi/api/Profile.java b/api/src/main/java/org/apache/unomi/api/Profile.java
index 8c20adc..fa83e39 100644
--- a/api/src/main/java/org/apache/unomi/api/Profile.java
+++ b/api/src/main/java/org/apache/unomi/api/Profile.java
@@ -21,10 +21,7 @@ import org.apache.unomi.api.segments.Scoring;
 import org.apache.unomi.api.segments.Segment;
 
 import javax.xml.bind.annotation.XmlTransient;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 /**
  * A user profile gathering all known information about a given user as well as segments it is part of and scores.
@@ -59,6 +56,8 @@ public class Profile extends Item {
 
     private String mergedWith;
 
+    private Map<String, Consent> consents = new LinkedHashMap<>();
+
     /**
      * Instantiates a new Profile.
      */
@@ -196,12 +195,53 @@ public class Profile extends Item {
         this.scores = scores;
     }
 
+    public Map<String, Consent> getConsents() {
+        return consents;
+    }
+
     @XmlTransient
     public boolean isAnonymousProfile() {
         Boolean anonymous = (Boolean) getSystemProperties().get("isAnonymousProfile");
         return anonymous != null && anonymous;
     }
 
+    @XmlTransient
+    public boolean grantConsent(String consentTypeId, Date grantDate, Date revokeDate) {
+        Consent consent = new Consent(itemId, consentTypeId, ConsentGrant.GRANT, grantDate, revokeDate);
+        consents.put(consentTypeId, consent);
+        return true;
+    }
+
+    @XmlTransient
+    public boolean denyConsent(String consentTypeId, Date grantDate, Date revokeDate) {
+        Consent consent = new Consent(itemId, consentTypeId, ConsentGrant.DENY, grantDate, revokeDate);
+        consents.put(consentTypeId, consent);
+        return true;
+    }
+
+    @XmlTransient
+    public boolean revokeConsent(String consentTypeId) {
+        if (consents.containsKey(consentTypeId)) {
+            consents.remove(consentTypeId);
+            return true;
+        }
+        return false;
+    }
+
+    @XmlTransient
+    public boolean isConsentGiven(String consentTypeId) {
+        if (consents.containsKey(consentTypeId)) {
+            Consent consent = consents.get(consentTypeId);
+            Date nowDate = new Date();
+            if (consent.getGrantDate().before(nowDate) && (consent.getRevokeDate() == null || (consent.getRevokeDate().after(nowDate)))) {
+                if (consent.getGrant().equals(ConsentGrant.GRANT)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     @Override
     public String toString() {
         return new StringBuilder(512).append("{id: \"").append(getItemId()).append("\", segments: ")

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/de5dea66/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentsAction.java
----------------------------------------------------------------------
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentsAction.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentsAction.java
new file mode 100644
index 0000000..84a1d2c
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentsAction.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.plugins.baseplugin.actions;
+
+import org.apache.unomi.api.Consent;
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.actions.Action;
+import org.apache.unomi.api.actions.ActionExecutor;
+import org.apache.unomi.api.services.EventService;
+
+import java.util.List;
+
+/**
+ * This class will process consent modification actions and update the profile's consents accordingly.
+ */
+public class ModifyConsentsAction implements ActionExecutor {
+
+    public static final String GRANTED_CONSENTS = "grantedConsents";
+    public static final String DENIED_CONSENTS = "deniedConsents";
+    public static final String REVOKED_CONSENTS = "revokedConsents";
+
+    @Override
+    public int execute(Action action, Event event) {
+
+        Profile profile = event.getProfile();
+        boolean isProfileUpdated = false;
+
+        List<Consent> grantedConsents = (List<Consent>) event.getProperties().get(GRANTED_CONSENTS);
+        if (grantedConsents != null) {
+            for (Consent consent : grantedConsents) {
+                profile.grantConsent(consent.getTypeId(), consent.getGrantDate(), consent.getRevokeDate());
+            }
+            isProfileUpdated = true;
+        }
+        List<Consent> deniedConsents = (List<Consent>) event.getProperties().get(DENIED_CONSENTS);
+        if (deniedConsents != null) {
+            for (Consent consent : deniedConsents) {
+                profile.denyConsent(consent.getTypeId(), consent.getGrantDate(), consent.getRevokeDate());
+            }
+            isProfileUpdated = true;
+        }
+        List<Consent> revokedConsents = (List<Consent>) event.getProperties().get(REVOKED_CONSENTS);
+        if (revokedConsents != null) {
+            for (Consent consent : revokedConsents) {
+                profile.revokeConsent(consent.getTypeId());
+            }
+            isProfileUpdated = true;
+        }
+
+        return isProfileUpdated ? EventService.PROFILE_UPDATED : EventService.NO_CHANGE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/de5dea66/plugins/baseplugin/src/main/resources/META-INF/cxs/actions/modifyConsentsAction.json
----------------------------------------------------------------------
diff --git a/plugins/baseplugin/src/main/resources/META-INF/cxs/actions/modifyConsentsAction.json b/plugins/baseplugin/src/main/resources/META-INF/cxs/actions/modifyConsentsAction.json
new file mode 100644
index 0000000..2910019
--- /dev/null
+++ b/plugins/baseplugin/src/main/resources/META-INF/cxs/actions/modifyConsentsAction.json
@@ -0,0 +1,16 @@
+{
+  "metadata": {
+    "id": "modifyConsentsAction",
+    "name": "modifyConsentsAction",
+    "description": "Modify profile consents",
+    "systemTags": [
+      "profileTags",
+      "demographic"
+    ],
+    "readOnly": true
+  },
+  "actionExecutor": "modifyConsents",
+  "parameters": [
+
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/de5dea66/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/modifyConsentsEventCondition.json
----------------------------------------------------------------------
diff --git a/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/modifyConsentsEventCondition.json b/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/modifyConsentsEventCondition.json
new file mode 100644
index 0000000..ec1333e
--- /dev/null
+++ b/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/modifyConsentsEventCondition.json
@@ -0,0 +1,23 @@
+{
+  "metadata": {
+    "id": "modifyConsentsEventCondition",
+    "name": "modifyConsentsEventCondition",
+    "description": "",
+    "systemTags": [
+      "profileTags",
+      "event",
+      "condition",
+      "eventCondition"
+    ],
+    "readOnly": true
+  },
+  "parentCondition": {
+    "type": "eventTypeCondition",
+    "parameterValues": {
+      "eventTypeId": "modifyConsents"
+    }
+  },
+
+  "parameters": [
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/de5dea66/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index ac245ac..c2a7012 100644
--- a/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -182,6 +182,14 @@
 
     <service auto-export="interfaces">
         <service-properties>
+            <entry key="actionExecutorId" value="modifyConsents"/>
+        </service-properties>
+        <bean class="org.apache.unomi.plugins.baseplugin.actions.ModifyConsentsAction">
+        </bean>
+    </service>
+
+    <service auto-export="interfaces">
+        <service-properties>
             <entry key="actionExecutorId" value="evaluateProfileSegments"/>
         </service-properties>
         <bean class="org.apache.unomi.plugins.baseplugin.actions.EvaluateProfileSegmentsAction">

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/de5dea66/wab/src/main/java/org/apache/unomi/web/ContextServlet.java
----------------------------------------------------------------------
diff --git a/wab/src/main/java/org/apache/unomi/web/ContextServlet.java b/wab/src/main/java/org/apache/unomi/web/ContextServlet.java
index 245dc94..42d478a 100644
--- a/wab/src/main/java/org/apache/unomi/web/ContextServlet.java
+++ b/wab/src/main/java/org/apache/unomi/web/ContextServlet.java
@@ -373,6 +373,7 @@ public class ContextServlet extends HttpServlet {
         }
 
         data.setAnonymousBrowsing(privacyService.isRequireAnonymousBrowsing(profile.getItemId()));
+        data.setConsents(profile.getConsents());
 
         return changes;
     }