Repository: incubator-unomi Updated Branches: refs/heads/feature-DMF-1343 d95aa89ad -> f694dacb2 (forced update)
UNOMI-98 Provide an example of integrating with an externally triggered login - First commit of the login integration example Signed-off-by: Serge Huber <shu...@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/ef860382 Tree: http://git-wip-us.apache.org/repos/asf/incubator-unomi/tree/ef860382 Diff: http://git-wip-us.apache.org/repos/asf/incubator-unomi/diff/ef860382 Branch: refs/heads/feature-DMF-1343 Commit: ef8603824a887c6ebeb8cf56d27f8cd7c6593cd1 Parents: 4f4ade0 Author: Serge Huber <shu...@apache.org> Authored: Mon May 29 13:57:03 2017 +0200 Committer: Serge Huber <shu...@apache.org> Committed: Mon May 29 13:57:03 2017 +0200 ---------------------------------------------------------------------- samples/login-integration/pom.xml | 64 +++++++++ .../META-INF/cxs/rules/exampleLogin.json | 34 +++++ .../src/main/webapp/WEB-INF/web.xml | 24 ++++ .../src/main/webapp/index.html | 70 ++++++++++ .../src/main/webapp/javascript/login-example.js | 136 +++++++++++++++++++ samples/pom.xml | 2 +- 6 files changed, 329 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ef860382/samples/login-integration/pom.xml ---------------------------------------------------------------------- diff --git a/samples/login-integration/pom.xml b/samples/login-integration/pom.xml new file mode 100644 index 0000000..675807f --- /dev/null +++ b/samples/login-integration/pom.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>samples</artifactId> + <groupId>org.apache.unomi</groupId> + <version>1.2.0-incubating-SNAPSHOT</version> + </parent> + + <artifactId>login-integration-sample</artifactId> + <name>Apache Unomi :: Samples :: External Login plugin</name> + <packaging>bundle</packaging> + <description>This is a simple Apache Unomi plugin.</description> + + <dependencies> + <dependency> + <groupId>org.apache.unomi</groupId> + <artifactId>unomi-api</artifactId> + <version>1.2.0-incubating-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>javax.servlet.jsp</groupId> + <artifactId>jsp-api</artifactId> + <version>2.1</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <_wab>src/main/webapp</_wab> + <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency> + <Embed-Directory>WEB-INF/lib</Embed-Directory> + <Web-ContextPath>/login</Web-ContextPath> + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ef860382/samples/login-integration/src/main/resources/META-INF/cxs/rules/exampleLogin.json ---------------------------------------------------------------------- diff --git a/samples/login-integration/src/main/resources/META-INF/cxs/rules/exampleLogin.json b/samples/login-integration/src/main/resources/META-INF/cxs/rules/exampleLogin.json new file mode 100644 index 0000000..6e3604b --- /dev/null +++ b/samples/login-integration/src/main/resources/META-INF/cxs/rules/exampleLogin.json @@ -0,0 +1,34 @@ +{ + "metadata": { + "id": "exampleLogin", + "name": "Example Login", + "description": "Copy event properties to profile properties on login" + }, + "condition": { + "parameterValues": { + "subConditions": [ + { + "parameterValues": { + }, + "type": "loginEventCondition" + } + ], + "operator": "and" + }, + "type": "booleanCondition" + }, + "actions": [ + { + "parameterValues": { + "mergeProfilePropertyValue": "eventProperty::target.properties(email)", + "mergeProfilePropertyName": "mergeIdentifier" + }, + "type": "mergeProfilesOnPropertyAction" + }, + { + "parameterValues": { + }, + "type": "allEventToProfilePropertiesAction" + } + ] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ef860382/samples/login-integration/src/main/webapp/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/samples/login-integration/src/main/webapp/WEB-INF/web.xml b/samples/login-integration/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..dc145f2 --- /dev/null +++ b/samples/login-integration/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,24 @@ +<!-- + ~ 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. + --> +<web-app xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + version="3.0"> + <welcome-file-list> + <welcome-file>index.html</welcome-file> + </welcome-file-list> +</web-app> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ef860382/samples/login-integration/src/main/webapp/index.html ---------------------------------------------------------------------- diff --git a/samples/login-integration/src/main/webapp/index.html b/samples/login-integration/src/main/webapp/index.html new file mode 100644 index 0000000..8b03cbd --- /dev/null +++ b/samples/login-integration/src/main/webapp/index.html @@ -0,0 +1,70 @@ +<!-- +~ 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. +--> +<html> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Login integration example</title> + <!-- Latest compiled and minified CSS --> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" + integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> + <!-- Optional theme --> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" + integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> + <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> + <!-- Latest compiled and minified JavaScript --> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" + integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" + crossorigin="anonymous"></script> + <script src="javascript/login-example.js"></script> +</head> +<body> +<div class="container"> + <h1>Login integration example</h1> + <p>This is a small example of integrating Apache Unomi with an event login in order to merge profile based on emails + as merge keys (see associated rule file in src/main/resources/META-INF/cxs/rules/exampleLogin.json).</p> + <p>Important: note that login events should normally always be sent from the server performing the login, not through + Javascript for security reasons. Here we provide this type of example only for brievety and clarity.</p> + <div id="alert_placeholder"></div> + <form id="loginForm"> + <div class="form-group"> + <label for="firstname">First name</label> + <input type="text" name="firstName" id="firstname" class="form-control" + placeholder="Enter your first name here"/> + </div> + <div class="form-group"> + <label for="lastname">Last name</label> + <input type="text" name="lastName" id="lastname" class="form-control" + placeholder="Enter your last name here"/> + </div> + <div class="form-group"> + <label for="email">Email</label> + <input type="text" name="email" id="email" class="form-control" placeholder="Enter your email here" + > + </div> + <div class="form-group"> + <label for="email">Password</label> + <input type="password" name="password" id="password" class="form-control" + placeholder="Enter your password here"> + </div> + <button id="loginButton" type="submit" class="btn btn-default">Login</button> + </form> +</div> +</body> +</html> http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ef860382/samples/login-integration/src/main/webapp/javascript/login-example.js ---------------------------------------------------------------------- diff --git a/samples/login-integration/src/main/webapp/javascript/login-example.js b/samples/login-integration/src/main/webapp/javascript/login-example.js new file mode 100644 index 0000000..3c01113 --- /dev/null +++ b/samples/login-integration/src/main/webapp/javascript/login-example.js @@ -0,0 +1,136 @@ +/* + * 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. + */ + +(function () { + + // We use this method to generate unique sessions IDs + function generateGuid() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + + s4() + '-' + s4() + s4() + s4(); + } + + // -- COOKIE HELPER METHODS --- + + function createCookie(name, value, days) { + var expires; + + if (days) { + var date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + expires = "; expires=" + date.toGMTString(); + } else { + expires = ""; + } + document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/"; + } + + function readCookie(name) { + var nameEQ = encodeURIComponent(name) + "="; + var ca = document.cookie.split(';'); + for (var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) === ' ') c = c.substring(1, c.length); + if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length, c.length)); + } + return null; + } + + function eraseCookie(name) { + createCookie(name, "", -1); + } + + // -- BOOTSTRAP HELPER METHODS --- + + bootstrapAlert = {}; + bootstrapAlert.success = function (message) { + $('#alert_placeholder').html('<div class="alert alert-success"><a class="close" data-dismiss="alert">Ã</a><span>' + message + '</span></div>') + }; + bootstrapAlert.danger = function (message) { + $('#alert_placeholder').html('<div class="alert alert-danger"><a class="close" data-dismiss="alert">Ã</a><span>' + message + '</span></div>') + }; + + $(document).ready(function () { + + // first we check if we have an existing session ID cookie, if not we generate a new session identifier and + // store it in the cookie. + var unomiSessionId = readCookie('unomi-session-id'); + if (!unomiSessionId) { + unomiSessionId = generateGuid(); + console.log("No existing session cookie found, creating a new one with value " + unomiSessionId); + createCookie('unomi-session-id', unomiSessionId, 1); + } + console.log("Setting up form listener..."); + $("#loginForm").submit(function (event) { + var email = $('#email').val(); + var firstName = $('#firstname').val(); + var lastName = $('#lastname').val(); + var password = $('#password').val(); + if (password != 'test1234') { + bootstrapAlert.danger("Wrong password (default is : test1234)"); + event.preventDefault(); + return false; + } + var contextRequest = { + source: { // the source is required for the request to be process properly + itemId: location.pathname, + itemType: 'webpage', + scope: 'test' // the scope is used to regroup events and sessions into sub-groups (eg sites) + }, + events: [{ // here we provide a simple login event, but as this is actually an array we could provide other events at the same time (page view, clicks, mouse movements, ...) + eventType: "login", + properties: {}, + target: { + itemId: email, + itemType: "exampleUser", + properties: { + preferredLanguage: "en", + email: email, + firstName: firstName, + lastName: lastName + } + } + }], + requiredProfileProperties: ['*'], // this tells Unomi to send us back all the profile properties (by default none are returned) + requiredSessionProperties: ['*'] // this tells Unomi to send us back all the session properties (by default none are returned) + }; + // now let's perform the actual call to Apache Unomi, asking it to process the events and give us back the updated (or created) profile. + // as we have a rule listening to a login event, it will be executed and its actions will be processed. + $.ajax({ + url: "http://localhost:8181/context.json?sessionId=" + unomiSessionId, + type: 'POST', + data: JSON.stringify(contextRequest), // make sure you sent JSON and not form-encoded, otherwise Unomi will generate an error + contentType: 'application/json; charset=utf-8', + dataType: 'json', + async: false, + success: function (data) { + console.log("Unomi response:", data); + bootstrapAlert.success("Successfully sent login event to Apache Unomi ! (profileId=" + data.profileId + ",properties.email=" + data.profileProperties.email + ",nbOfVisits=" + data.profileProperties.nbOfVisits + ")"); + } + }); + event.preventDefault(); + return false; + }); + }); + +})(); + http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/ef860382/samples/pom.xml ---------------------------------------------------------------------- diff --git a/samples/pom.xml b/samples/pom.xml index 8941427..67e0d6f 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -28,7 +28,7 @@ <packaging>pom</packaging> <modules> <module>tweet-button-plugin</module> + <module>login-integration</module> </modules> - </project> \ No newline at end of file