Repository: incubator-unomi
Updated Branches:
  refs/heads/master 38b50c6da -> 485a0f1e4


UNOMI-133 Add (GDPR) consents to visitor profiles
- Consents are no longer items, as they are only used inside Profiles
- Added REVOKE ConsentGrant type
- Added Javadocs on Profile and Consent classes
- Moved consent tests methods from Profile to Consent
- New integration test to test consent modifications using events
- Modified the ModifyConsentAction to only work on a single consent
- Renamed the modifyConsents event to modifyConsent to operate on a single 
consent
- Fixed a small problem with the EventCollector that wasn't specifiying a 
consent type for it's output.

Signed-off-by: Serge Huber <[email protected]>


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

Branch: refs/heads/master
Commit: 485a0f1e4b301f5da7897e06b29e51182863f4ba
Parents: 38b50c6
Author: Serge Huber <[email protected]>
Authored: Mon Nov 13 11:35:07 2017 +0100
Committer: Serge Huber <[email protected]>
Committed: Mon Nov 13 11:35:07 2017 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/unomi/api/Consent.java | 160 +++++++++++++++++--
 .../java/org/apache/unomi/api/ConsentGrant.java |   7 +-
 .../main/java/org/apache/unomi/api/Profile.java |  70 ++++----
 .../java/org/apache/unomi/itests/AllITs.java    |   3 +-
 .../apache/unomi/itests/ModifyConsentIT.java    |  99 ++++++++++++
 plugins/baseplugin/pom.xml                      |   5 +
 .../baseplugin/actions/ModifyConsentAction.java |  63 ++++++++
 .../actions/ModifyConsentsAction.java           |  67 --------
 .../cxs/actions/modifyConsentAction.json        |  16 ++
 .../cxs/actions/modifyConsentsAction.json       |  16 --
 .../conditions/modifyConsentEventCondition.json |  23 +++
 .../modifyConsentsEventCondition.json           |  23 ---
 .../META-INF/cxs/rules/modifyConsents.json      |  23 +++
 .../resources/OSGI-INF/blueprint/blueprint.xml  |   4 +-
 .../unomi/web/EventsCollectorServlet.java       |   2 +-
 15 files changed, 426 insertions(+), 155 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/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
index 6359a52..1f60252 100644
--- a/api/src/main/java/org/apache/unomi/api/Consent.java
+++ b/api/src/main/java/org/apache/unomi/api/Consent.java
@@ -16,57 +16,199 @@
  */
 package org.apache.unomi.api;
 
+import javax.xml.bind.annotation.XmlTransient;
+import java.text.DateFormat;
+import java.text.ParseException;
 import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
 /**
  * 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 {
+public class Consent {
 
-    private String typeId; // types are defined and managed externally of 
Apache Unomi
+    private String typeIdentifier; // type identifiers 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;
+    /**
+     * Empty constructor mostly used for JSON (de-) serialization
+     */
+    public Consent() {
+    }
+
+    /**
+     * A constructor to directly build a consent with all it's properties
+     * @param typeIdentifier the identifier of the type this consent applies to
+     * @param grant the type of grant that we are storing for this consent. 
May be one of @ConsentGrant.DENY, @ConsentGrant.GRANT, @ConsentGrant.REVOKE
+     * @param grantDate the starting date at which this consent was given
+     * @param revokeDate the date at which this consent will (automatically) 
revoke
+     */
+    public Consent(String typeIdentifier, ConsentGrant grant, Date grantDate, 
Date revokeDate) {
+        this.typeIdentifier = typeIdentifier;
         this.grant = grant;
         this.grantDate = grantDate;
         this.revokeDate = revokeDate;
     }
 
-    public void setTypeId(String typeId) {
-        this.typeId = typeId;
+    /**
+     * A constructor from a map used for example when we use the deserialized 
data from event
+     * properties.
+     * @param consentMap a Map that contains the following key-value pairs : 
typeIdentifier:String, grant:String (must
+     *                   be one of GRANT, DENY or REVOKE), grantDate:String 
(ISO8601 date format !), revokeDate:String (ISO8601 date format !)
+     * @param dateFormat a DateFormat instance to convert the date string to 
date objects
+     */
+    public Consent(Map<String,Object> consentMap, DateFormat dateFormat) 
throws ParseException {
+        if (consentMap.containsKey("typeIdentifier")) {
+            setTypeIdentifier((String) consentMap.get("typeIdentifier"));
+        }
+        if (consentMap.containsKey("grant")) {
+            String grantString = (String) consentMap.get("grant");
+            setGrant(ConsentGrant.valueOf(grantString));
+        }
+        if (consentMap.containsKey("grantDate")) {
+            String grantDateStr = (String) consentMap.get("grantDate");
+            if (grantDateStr != null && grantDateStr.trim().length() > 0) {
+                setGrantDate(dateFormat.parse(grantDateStr));
+            }
+        }
+        if (consentMap.containsKey("revokeDate")) {
+            String revokeDateStr = (String) consentMap.get("revokeDate");
+            if (revokeDateStr != null && revokeDateStr.trim().length() > 0) {
+                setRevokeDate(dateFormat.parse(revokeDateStr));
+            }
+        }
+    }
+
+    /**
+     * Set the type identifier. This must be (no validation is done) a unique 
identifier for the consent type. These
+     * are usually externally defined, Apache Unomi has no knowledge of them 
except for this type identifier.
+     * @param typeIdentifier a unique String to identify the consent type
+     */
+    public void setTypeIdentifier(String typeIdentifier) {
+        this.typeIdentifier = typeIdentifier;
     }
 
-    public String getTypeId() {
-        return typeId;
+    /**
+     * Retrieve the consent type identifier for this consent.
+     * @return a String containing the type identifier
+     */
+    public String getTypeIdentifier() {
+        return typeIdentifier;
     }
 
+    /**
+     * Retrieves the grant for this consent. This is of type @ConsentGrant
+     * @return the current value for the grant.
+     */
     public ConsentGrant getGrant() {
         return grant;
     }
 
+    /**
+     * Sets the grant for this consent. A Consent Grant of type REVOKE means 
that this consent is meant to be destroyed.
+     * @param grant the grant to set on this consent
+     */
     public void setGrant(ConsentGrant grant) {
         this.grant = grant;
     }
 
+    /**
+     * Retrieve the date at which this consent was given. If this date is in 
the future the consent should not be
+     * considered valid yet.
+     * @return a valid date or null if this date was not set.
+     */
     public Date getGrantDate() {
         return grantDate;
     }
 
+    /**
+     * Sets the date from which this consent applies.
+     * @param grantDate a valid Date or null if we set not starting date 
(immediately valid)
+     */
     public void setGrantDate(Date grantDate) {
         this.grantDate = grantDate;
     }
 
+    /**
+     * Retrieves the end date for this consent. After this date the consent is 
no longer valid and should be disposed of.
+     * If this date is not set it means the consent will never expire
+     * @return a valid Date or null to indicate an unlimited consent
+     */
     public Date getRevokeDate() {
         return revokeDate;
     }
 
+    /**
+     * Sets the end date for this consent. After this date the consent is no 
longer valid and should be disposed of.
+     * If this date is not set it means the consent will never expire
+     * @param revokeDate a valid Date or null to indicate an unlimited consent
+     */
     public void setRevokeDate(Date revokeDate) {
         this.revokeDate = revokeDate;
     }
+
+    /**
+     * Test if the consent is GRANTED right now.
+     * @return true if the consent is granted using the current date 
(internally a new Date() is created and the
+     * @Consent#isConsentGivenAtDate is called.
+     */
+    @XmlTransient
+    public boolean isConsentGrantedNow() {
+        return isConsentGrantedAtDate(new Date());
+    }
+
+    /**
+     * Tests if the consent is GRANTED at the specified date
+     * @param testDate the date against which to test the consent to be 
granted.
+     * @return true if the consent is granted at the specified date, false 
otherwise.
+     */
+    @XmlTransient
+    public boolean isConsentGrantedAtDate(Date testDate) {
+        if (getGrantDate().before(testDate) && (getRevokeDate() == null || 
(getRevokeDate().after(testDate)))) {
+            if (getGrant().equals(ConsentGrant.GRANT)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This is a utility method to generate a Map based on the contents of the 
consents. The format of the map is the
+     * same as the one used in the Map Consent constructor. For dates you must 
specify a dateFormat that will be used
+     * to format the dates. This dateFormat should usually support ISO8601 to 
make integrate with Javascript clients
+     * easy to integrate.
+     * @param dateFormat a dateFormat instance such as ISO8601DateFormat to 
generate the String formats for the grantDate
+     *                   and revokeDate map entries.
+     * @return a Map that contains the following key-value pairs : 
typeIdentifier:String, grant:String (must
+     *                   be one of GRANT, DENY or REVOKE), grantDate:String 
(generated by the dateFormat), revokeDate:String (generated by the dateFormat)
+     */
+    @XmlTransient
+    public Map<String,Object> toMap(DateFormat dateFormat) {
+        Map<String,Object> map = new LinkedHashMap<>();
+        map.put("typeIdentifier", typeIdentifier);
+        map.put("grant", grant.toString());
+        if (grantDate != null) {
+            map.put("grantDate", dateFormat.format(grantDate));
+        }
+        if (revokeDate != null) {
+            map.put("revokeDate", dateFormat.format(revokeDate));
+        }
+        return map;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("Consent{");
+        sb.append("typeIdentifier='").append(typeIdentifier).append('\'');
+        sb.append(", grant=").append(grant);
+        sb.append(", grantDate=").append(grantDate);
+        sb.append(", revokeDate=").append(revokeDate);
+        sb.append('}');
+        return sb.toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/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
index a72125d..fea2642 100644
--- a/api/src/main/java/org/apache/unomi/api/ConsentGrant.java
+++ b/api/src/main/java/org/apache/unomi/api/ConsentGrant.java
@@ -16,7 +16,12 @@
  */
 package org.apache.unomi.api;
 
+/**
+ * This enum class represents the type of grant a @Consent might have. The 
revoke grant type is a special one used to
+ * remove a consent for a profile.
+ */
 public enum ConsentGrant {
     GRANT,
-    DENY
+    DENY,
+    REVOKE
 }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/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 fa83e39..a6f7ec0 100644
--- a/api/src/main/java/org/apache/unomi/api/Profile.java
+++ b/api/src/main/java/org/apache/unomi/api/Profile.java
@@ -195,57 +195,57 @@ public class Profile extends Item {
         this.scores = scores;
     }
 
+    /**
+     * Returns all the consents, including the revokes ones.
+     * @return a map that contains the consent type ID as key, and the consent 
itself as a value
+     */
     public Map<String, Consent> getConsents() {
         return consents;
     }
 
+    /**
+     * Returns true if this profile is an anonymous profile.
+     */
     @XmlTransient
     public boolean isAnonymousProfile() {
         Boolean anonymous = (Boolean) 
getSystemProperties().get("isAnonymousProfile");
         return anonymous != null && anonymous;
     }
 
+    /**
+     * Set a consent into the profile.
+     * @param consent if the consent is a REVOKE grant, it will try to remove 
a consent with the same type id if it
+     *                exists for the profile.
+     * @return true if the operation was successful (inserted excpetion in the 
case of a revoke grant, in which case
+     * it is successful if there was a consent to revoke).
+     */
     @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;
-                }
+    public boolean setConsent(Consent consent) {
+        if (ConsentGrant.REVOKE.equals(consent.getGrant())) {
+            if (consents.containsKey(consent.getTypeIdentifier())) {
+                consents.remove(consent.getTypeIdentifier());
+                return true;
             }
+            return false;
         }
-        return false;
+        consents.put(consent.getTypeIdentifier(), consent);
+        return true;
     }
 
     @Override
     public String toString() {
-        return new StringBuilder(512).append("{id: 
\"").append(getItemId()).append("\", segments: ")
-                .append(getSegments()).append(", scores: 
").append(getScores()).append(", properties: ")
-                .append(getProperties()).append("}").toString();
+        final StringBuilder sb = new StringBuilder("Profile{");
+        sb.append("properties=").append(properties);
+        sb.append(", systemProperties=").append(systemProperties);
+        sb.append(", segments=").append(segments);
+        sb.append(", scores=").append(scores);
+        sb.append(", mergedWith='").append(mergedWith).append('\'');
+        sb.append(", consents=").append(consents);
+        sb.append(", itemId='").append(itemId).append('\'');
+        sb.append(", itemType='").append(itemType).append('\'');
+        sb.append(", scope='").append(scope).append('\'');
+        sb.append(", version=").append(version);
+        sb.append('}');
+        return sb.toString();
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/itests/src/test/java/org/apache/unomi/itests/AllITs.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/unomi/itests/AllITs.java 
b/itests/src/test/java/org/apache/unomi/itests/AllITs.java
index 4eb8733..bcdedc1 100644
--- a/itests/src/test/java/org/apache/unomi/itests/AllITs.java
+++ b/itests/src/test/java/org/apache/unomi/itests/AllITs.java
@@ -38,7 +38,8 @@ import org.junit.runners.Suite.SuiteClasses;
         ProfileImportRankingIT.class,
         ProfileImportActorsIT.class,
         ProfileExportIT.class,
-        PropertiesUpdateActionIT.class
+        PropertiesUpdateActionIT.class,
+        ModifyConsentIT.class
     })
 public class AllITs {
 }

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/itests/src/test/java/org/apache/unomi/itests/ModifyConsentIT.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/unomi/itests/ModifyConsentIT.java 
b/itests/src/test/java/org/apache/unomi/itests/ModifyConsentIT.java
new file mode 100644
index 0000000..52e60ef
--- /dev/null
+++ b/itests/src/test/java/org/apache/unomi/itests/ModifyConsentIT.java
@@ -0,0 +1,99 @@
+/*
+ * 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.itests;
+
+import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
+import org.apache.unomi.api.Consent;
+import org.apache.unomi.api.ConsentGrant;
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.services.EventService;
+import org.apache.unomi.api.services.ProfileService;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerSuite;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * An integration test for consent modifications using Apache Unomi @Event
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerSuite.class)
+public class ModifyConsentIT extends BaseIT {
+
+    private final static Logger LOGGER = 
LoggerFactory.getLogger(ModifyConsentIT.class);
+
+    private final static String PROFILE_TEST_ID = "profile-consent";
+
+    @Inject
+    protected ProfileService profileService;
+
+    @Inject
+    protected EventService eventService;
+
+    @Before
+    public void setUp() throws IOException {
+        Profile profile = new Profile();
+        profile.setItemId(PROFILE_TEST_ID);
+        profileService.save(profile);
+        LOGGER.info("Profile saved with ID [{}].", profile.getItemId());
+    }
+
+    @Test
+    public void testConsentGrant() throws InterruptedException {
+        Profile profile = profileService.load(PROFILE_TEST_ID);
+        Assert.assertNotNull(profile);
+        Assert.assertTrue(profile.getConsents().size() == 0);
+
+        Event modifyConsentEvent = new Event("modifyConsent", null, profile, 
null, null, profile, new Date());
+        modifyConsentEvent.setPersistent(false);
+
+        ISO8601DateFormat dateFormat = new ISO8601DateFormat();
+        Consent consent1 = new Consent("consentType01", ConsentGrant.GRANT, 
new Date(), null);
+        modifyConsentEvent.setProperty("consent", consent1.toMap(dateFormat));
+        int changes = eventService.send(modifyConsentEvent);
+        Consent consent2 = new Consent("consentType02", ConsentGrant.GRANT, 
new Date(), null);
+        modifyConsentEvent.setProperty("consent", consent2.toMap(dateFormat));
+        changes |= eventService.send(modifyConsentEvent);
+
+        if ((changes & EventService.PROFILE_UPDATED) == 
EventService.PROFILE_UPDATED) {
+            profileService.save(profile);
+        }
+
+        LOGGER.info("Changes of the event : {}", changes);
+
+        Assert.assertTrue(changes > 0);
+
+        //Wait for data to be processed
+        Thread.sleep(10000);
+
+        profile = profileService.load(PROFILE_TEST_ID);
+
+        Assert.assertTrue(profile.getConsents().size() == 2);
+
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/plugins/baseplugin/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/baseplugin/pom.xml b/plugins/baseplugin/pom.xml
index fb1068c..ec0dfff 100644
--- a/plugins/baseplugin/pom.xml
+++ b/plugins/baseplugin/pom.xml
@@ -73,6 +73,11 @@
             <groupId>javassist</groupId>
             <artifactId>javassist</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentAction.java
----------------------------------------------------------------------
diff --git 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentAction.java
 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentAction.java
new file mode 100644
index 0000000..344d5eb
--- /dev/null
+++ 
b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentAction.java
@@ -0,0 +1,63 @@
+/*
+ * 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 com.fasterxml.jackson.databind.util.ISO8601DateFormat;
+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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.ParseException;
+import java.util.Map;
+
+/**
+ * This class will process consent modification actions and update the 
profile's consents accordingly.
+ */
+public class ModifyConsentAction implements ActionExecutor {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(ModifyConsentAction.class.getName());
+
+    public static final String CONSENT_PROPERTY_NAME = "consent";
+
+    @Override
+    public int execute(Action action, Event event) {
+        Profile profile = event.getProfile();
+        boolean isProfileUpdated = false;
+
+        ISO8601DateFormat dateFormat = new ISO8601DateFormat();
+        Map consentMap = (Map) 
event.getProperties().get(CONSENT_PROPERTY_NAME);
+        if (consentMap != null) {
+            if (consentMap.containsKey("typeIdentifier") && 
consentMap.containsKey("grant")) {
+                Consent consent = null;
+                try {
+                    consent = new Consent(consentMap, dateFormat);
+                    isProfileUpdated = profile.setConsent(consent);
+                } catch (ParseException e) {
+                    logger.error("Error parsing date format", e);
+                }
+            } else {
+                logger.warn("Event properties for modifyConsent is missing 
typeIdentifier and grant properties. We will ignore this event.");
+            }
+        }
+        return isProfileUpdated ? EventService.PROFILE_UPDATED : 
EventService.NO_CHANGE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/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
deleted file mode 100644
index 84a1d2c..0000000
--- 
a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/actions/ModifyConsentsAction.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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/485a0f1e/plugins/baseplugin/src/main/resources/META-INF/cxs/actions/modifyConsentAction.json
----------------------------------------------------------------------
diff --git 
a/plugins/baseplugin/src/main/resources/META-INF/cxs/actions/modifyConsentAction.json
 
b/plugins/baseplugin/src/main/resources/META-INF/cxs/actions/modifyConsentAction.json
new file mode 100644
index 0000000..b954afe
--- /dev/null
+++ 
b/plugins/baseplugin/src/main/resources/META-INF/cxs/actions/modifyConsentAction.json
@@ -0,0 +1,16 @@
+{
+  "metadata": {
+    "id": "modifyConsentAction",
+    "name": "modifyConsentAction",
+    "description": "Modify a profile consent",
+    "systemTags": [
+      "profileTags",
+      "demographic"
+    ],
+    "readOnly": true
+  },
+  "actionExecutor": "modifyConsent",
+  "parameters": [
+
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/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
deleted file mode 100644
index 2910019..0000000
--- 
a/plugins/baseplugin/src/main/resources/META-INF/cxs/actions/modifyConsentsAction.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "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/485a0f1e/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/modifyConsentEventCondition.json
----------------------------------------------------------------------
diff --git 
a/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/modifyConsentEventCondition.json
 
b/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/modifyConsentEventCondition.json
new file mode 100644
index 0000000..b24c479
--- /dev/null
+++ 
b/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/modifyConsentEventCondition.json
@@ -0,0 +1,23 @@
+{
+  "metadata": {
+    "id": "modifyConsentEventCondition",
+    "name": "modifyConsentEventCondition",
+    "description": "",
+    "systemTags": [
+      "profileTags",
+      "event",
+      "condition",
+      "eventCondition"
+    ],
+    "readOnly": true
+  },
+  "parentCondition": {
+    "type": "eventTypeCondition",
+    "parameterValues": {
+      "eventTypeId": "modifyConsent"
+    }
+  },
+
+  "parameters": [
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/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
deleted file mode 100644
index ec1333e..0000000
--- 
a/plugins/baseplugin/src/main/resources/META-INF/cxs/conditions/modifyConsentsEventCondition.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "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/485a0f1e/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/modifyConsents.json
----------------------------------------------------------------------
diff --git 
a/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/modifyConsents.json 
b/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/modifyConsents.json
new file mode 100644
index 0000000..34531a7
--- /dev/null
+++ 
b/plugins/baseplugin/src/main/resources/META-INF/cxs/rules/modifyConsents.json
@@ -0,0 +1,23 @@
+{
+  "metadata" : {
+    "id": "modifyConsent",
+    "name": "Modify consent",
+    "description" : "Modify a consent",
+    "readOnly":true
+  },
+
+  "condition" : {
+    "type": "modifyConsentEventCondition",
+    "parameterValues": {
+    }
+  },
+
+  "actions" : [
+    {
+      "type": "modifyConsentAction",
+      "parameterValues": {
+      }
+    }
+  ]
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/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 c2a7012..6778b4f 100644
--- a/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/plugins/baseplugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -182,9 +182,9 @@
 
     <service auto-export="interfaces">
         <service-properties>
-            <entry key="actionExecutorId" value="modifyConsents"/>
+            <entry key="actionExecutorId" value="modifyConsent"/>
         </service-properties>
-        <bean 
class="org.apache.unomi.plugins.baseplugin.actions.ModifyConsentsAction">
+        <bean 
class="org.apache.unomi.plugins.baseplugin.actions.ModifyConsentAction">
         </bean>
     </service>
 

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/485a0f1e/wab/src/main/java/org/apache/unomi/web/EventsCollectorServlet.java
----------------------------------------------------------------------
diff --git a/wab/src/main/java/org/apache/unomi/web/EventsCollectorServlet.java 
b/wab/src/main/java/org/apache/unomi/web/EventsCollectorServlet.java
index 480be81..432a694 100644
--- a/wab/src/main/java/org/apache/unomi/web/EventsCollectorServlet.java
+++ b/wab/src/main/java/org/apache/unomi/web/EventsCollectorServlet.java
@@ -37,7 +37,6 @@ import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
 import java.util.UUID;
 
@@ -214,6 +213,7 @@ public class EventsCollectorServlet extends HttpServlet {
             profileService.saveSession(session);
         }
 
+        response.setContentType("application/json");
         PrintWriter responseWriter = response.getWriter();
         responseWriter.append("{\"updated\":" + changes + "}");
         responseWriter.flush();

Reply via email to