Repository: incubator-unomi Updated Branches: refs/heads/master 664894dc6 -> 758d59496
UNOMI-6: Moved samples to Unomi repository. Replaced existing index.html by the Twitter sample. Project: http://git-wip-us.apache.org/repos/asf/incubator-unomi/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-unomi/commit/758d5949 Tree: http://git-wip-us.apache.org/repos/asf/incubator-unomi/tree/758d5949 Diff: http://git-wip-us.apache.org/repos/asf/incubator-unomi/diff/758d5949 Branch: refs/heads/master Commit: 758d594966092be4d4459d787f99bac3bcda2d59 Parents: 664894d Author: Chris Laprun <[email protected]> Authored: Fri Dec 18 19:20:49 2015 +0100 Committer: Chris Laprun <[email protected]> Committed: Fri Dec 18 19:20:49 2015 +0100 ---------------------------------------------------------------------- pom.xml | 1 + samples/pom.xml | 19 ++ samples/tweet-button-plugin/README.md | 2 + samples/tweet-button-plugin/pom.xml | 67 +++++ .../actions/IncrementTweetNumberAction.java | 89 +++++++ .../cxs/actions/incrementTweetNumberAction.json | 8 + .../cxs/rules/incrementTweetNumber.json | 20 ++ .../resources/OSGI-INF/blueprint/blueprint.xml | 39 +++ .../src/main/resources/messages_en.properties | 2 + wab/src/main/webapp/index.html | 243 +++++++++---------- 10 files changed, 365 insertions(+), 125 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 4690e06..09bf0c8 100644 --- a/pom.xml +++ b/pom.xml @@ -481,6 +481,7 @@ <module>plugins</module> <module>extensions</module> <module>kar</module> + <module>samples</module> </modules> <dependencies> http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/samples/pom.xml ---------------------------------------------------------------------- diff --git a/samples/pom.xml b/samples/pom.xml new file mode 100644 index 0000000..b9ab307 --- /dev/null +++ b/samples/pom.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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"> + <parent> + <artifactId>unomi-root</artifactId> + <groupId>org.apache.unomi</groupId> + <version>1.0.0-incubating-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>samples</artifactId> + <packaging>pom</packaging> + <modules> + <module>tweet-button-plugin</module> + </modules> + + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/samples/tweet-button-plugin/README.md ---------------------------------------------------------------------- diff --git a/samples/tweet-button-plugin/README.md b/samples/tweet-button-plugin/README.md new file mode 100644 index 0000000..64ffc16 --- /dev/null +++ b/samples/tweet-button-plugin/README.md @@ -0,0 +1,2 @@ +# unomi-tweet-button-plugin +A simple plugin to send unomi events when a tweet button is clicked http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/samples/tweet-button-plugin/pom.xml ---------------------------------------------------------------------- diff --git a/samples/tweet-button-plugin/pom.xml b/samples/tweet-button-plugin/pom.xml new file mode 100644 index 0000000..302a370 --- /dev/null +++ b/samples/tweet-button-plugin/pom.xml @@ -0,0 +1,67 @@ +<?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.0.0-incubating-SNAPSHOT</version> + </parent> + + <artifactId>tweet-button-plugin</artifactId> + <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.0.0-incubating-SNAPSHOT</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.3</version> + <configuration> + <source>8</source> + <target>8</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <version>3.0.1</version> + <extensions>true</extensions> + <configuration> + <instructions> + + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/samples/tweet-button-plugin/src/main/java/org/apache/unomi/samples/tweet_button_plugin/actions/IncrementTweetNumberAction.java ---------------------------------------------------------------------- diff --git a/samples/tweet-button-plugin/src/main/java/org/apache/unomi/samples/tweet_button_plugin/actions/IncrementTweetNumberAction.java b/samples/tweet-button-plugin/src/main/java/org/apache/unomi/samples/tweet_button_plugin/actions/IncrementTweetNumberAction.java new file mode 100644 index 0000000..5a2cd7e --- /dev/null +++ b/samples/tweet-button-plugin/src/main/java/org/apache/unomi/samples/tweet_button_plugin/actions/IncrementTweetNumberAction.java @@ -0,0 +1,89 @@ +package org.apache.unomi.samples.tweet_button_plugin.actions; + +/* + * #%L + * Context Server Plugin - Provides request reading actions + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2014 - 2015 Jahia Solutions + * %% + * Licensed 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. + * #L% + */ + +import org.apache.unomi.api.*; +import org.apache.unomi.api.actions.Action; +import org.apache.unomi.api.actions.ActionExecutor; +import org.apache.unomi.api.services.EventService; +import org.apache.unomi.api.services.ProfileService; + +import java.util.ArrayList; +import java.util.List; + +/** + * Increments the number of times the user associated with the profile tweeted. + */ +public class IncrementTweetNumberAction implements ActionExecutor { + private static final String TWEET_NB_PROPERTY = "tweetNb"; + private static final String TWEETED_FROM_PROPERTY = "tweetedFrom"; + private ProfileService service; + + public int execute(Action action, Event event) { + final Profile profile = event.getProfile(); + Integer tweetNb = (Integer) profile.getProperty(TWEET_NB_PROPERTY); + List<String> tweetedFrom = (List<String>) profile.getProperty(TWEETED_FROM_PROPERTY); + + if (tweetNb == null || tweetedFrom == null) { + // create tweet number property type + PropertyType propertyType = new PropertyType(new Metadata(event.getScope(), TWEET_NB_PROPERTY, TWEET_NB_PROPERTY, "Number of times a user tweeted")); + propertyType.setValueTypeId("integer"); + service.createPropertyType(propertyType); + + // create tweeted from property type + propertyType = new PropertyType(new Metadata(event.getScope(), TWEETED_FROM_PROPERTY, TWEETED_FROM_PROPERTY, "The list of pages a user tweeted from")); + propertyType.setValueTypeId("string"); + propertyType.setMultivalued(true); + service.createPropertyType(propertyType); + + tweetNb = 0; + tweetedFrom = new ArrayList<>(); + } + + profile.setProperty(TWEET_NB_PROPERTY, tweetNb + 1); + final String sourceURL = extractSourceURL(event); + if (sourceURL != null) { + tweetedFrom.add(sourceURL); + } + profile.setProperty(TWEETED_FROM_PROPERTY, tweetedFrom); + + return EventService.PROFILE_UPDATED; + } + + public void setProfileService(ProfileService service) { + this.service = service; + } + + private String extractSourceURL(Event event) { + final Item sourceAsItem = event.getSource(); + if (sourceAsItem instanceof CustomItem) { + CustomItem source = (CustomItem) sourceAsItem; + final String url = (String) source.getProperties().get("url"); + if (url != null) { + return url; + } + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/actions/incrementTweetNumberAction.json ---------------------------------------------------------------------- diff --git a/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/actions/incrementTweetNumberAction.json b/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/actions/incrementTweetNumberAction.json new file mode 100644 index 0000000..e65b644 --- /dev/null +++ b/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/actions/incrementTweetNumberAction.json @@ -0,0 +1,8 @@ +{ + "id": "incrementTweetNumberAction", + "actionExecutor": "incrementTweetNumber", + "tags": [ + "event" + ], + "parameters": [] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/rules/incrementTweetNumber.json ---------------------------------------------------------------------- diff --git a/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/rules/incrementTweetNumber.json b/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/rules/incrementTweetNumber.json new file mode 100644 index 0000000..924b1f7 --- /dev/null +++ b/samples/tweet-button-plugin/src/main/resources/META-INF/cxs/rules/incrementTweetNumber.json @@ -0,0 +1,20 @@ +{ + "metadata": { + "id": "smp:incrementTweetNumber", + "name": "Increment tweet number", + "description": "Increments the number of times a user has tweeted after they click on a tweet button" + }, + "raiseEventOnlyOnceForSession": false, + "condition": { + "type": "eventTypeCondition", + "parameterValues": { + "eventTypeId": "tweetEvent" + } + }, + "actions": [ + { + "type": "incrementTweetNumberAction", + "parameterValues": {} + } + ] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/samples/tweet-button-plugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml ---------------------------------------------------------------------- diff --git a/samples/tweet-button-plugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/samples/tweet-button-plugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml new file mode 100644 index 0000000..f2c64f5 --- /dev/null +++ b/samples/tweet-button-plugin/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + #%L + Context Server Plugin - Provides request reading actions + $Id:$ + $HeadURL:$ + %% + Copyright (C) 2014 - 2015 Jahia Solutions + %% + Licensed 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. + #L% + --> + +<blueprint xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> + + <reference id="profileService" interface="org.apache.unomi.api.services.ProfileService"/> + + <!-- Action executor --> + <service id="incrementTweetNumberAction" auto-export="interfaces"> + <service-properties> + <entry key="actionExecutorId" value="incrementTweetNumber"/> + </service-properties> + <bean class="org.apache.unomi.samples.tweet_button_plugin.actions.IncrementTweetNumberAction"> + <property name="profileService" ref="profileService"/> + </bean> + </service> +</blueprint> http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/samples/tweet-button-plugin/src/main/resources/messages_en.properties ---------------------------------------------------------------------- diff --git a/samples/tweet-button-plugin/src/main/resources/messages_en.properties b/samples/tweet-button-plugin/src/main/resources/messages_en.properties new file mode 100644 index 0000000..d3b6f27 --- /dev/null +++ b/samples/tweet-button-plugin/src/main/resources/messages_en.properties @@ -0,0 +1,2 @@ +action.incrementTweetNumberAction.description=Increments the number of times a user has tweeted after they click on a tweet button +action.incrementTweetNumberAction.name=Increment tweet number \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/758d5949/wab/src/main/webapp/index.html ---------------------------------------------------------------------- diff --git a/wab/src/main/webapp/index.html b/wab/src/main/webapp/index.html index 9d705e5..856f25a 100644 --- a/wab/src/main/webapp/index.html +++ b/wab/src/main/webapp/index.html @@ -1,142 +1,135 @@ -<!-- - ~ 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. - --> <!DOCTYPE html> -<html> +<html lang="en"> <head> - <title>Facebook Login JavaScript Example</title> <meta charset="UTF-8"> -</head> -<body> -<script type="text/javascript"> - // This is called with the results from from FB.getLoginStatus(). - function statusChangeCallback(response) { - console.log('statusChangeCallback'); - console.log(response); - // The response object is returned with a status field that lets the - // app know the current login status of the person. - // Full docs on the response object can be found in the documentation - // for FB.getLoginStatus(). - if (response.status === 'connected') { - // Logged into your app and Facebook. - testAPI(); - } else if (response.status === 'not_authorized') { - // The person is logged into Facebook, but not your app. - document.getElementById('status').innerHTML = 'Please log ' + - 'into this app.'; - } else { - // The person is not logged into Facebook, so we're not sure if - // they are logged into this app or not. - document.getElementById('status').innerHTML = 'Please log ' + - 'into Facebook.'; - } - } - - // This function is called when someone finishes with the Login - // Button. See the onlogin handler attached to it in the sample - // code below. - function checkLoginState() { - FB.getLoginStatus(function (response) { - statusChangeCallback(response); - }); - } + <title>Unomi Tweet button integration example</title> + <script type="application/javascript"> + window.twttr = (function (d, s, id) { + var js, fjs = d.getElementsByTagName(s)[0], + t = window.twttr || {}; + if (d.getElementById(id)) return; + js = d.createElement(s); + js.id = id; + js.src = "https://platform.twitter.com/widgets.js"; + fjs.parentNode.insertBefore(js, fjs); - window.fbAsyncInit = function () { - FB.init({ - appId: '499507903483280', - cookie: true, // enable cookies to allow the server to access - // the session - xfbml: true, // parse social plugins on this page - version: 'v2.0' // use version 2.0 - }); + t._e = []; + t.ready = function (f) { + t._e.push(f); + }; - // Now that we've initialized the JavaScript SDK, we call - // FB.getLoginStatus(). This function gets the state of the - // person visiting this page and can return one of three states to - // the callback you provide. They can be: - // - // 1. Logged into your app ('connected') - // 2. Logged into Facebook, but not your app ('not_authorized') - // 3. Not logged into Facebook and can't tell if they are logged into - // your app or not. - // - // These three cases are handled in the callback function. + return t; + }(document, "script", "twitter-wjs")); - FB.getLoginStatus(function (response) { - statusChangeCallback(response); - }); + // Load context from Unomi asynchronously + (function (document, elementToCreate, id) { + var js, fjs = document.getElementsByTagName(elementToCreate)[0]; + if (document.getElementById(id)) return; + js = document.createElement(elementToCreate); + js.id = id; + js.src = "http://localhost:8181/context.js"; + fjs.parentNode.insertBefore(js, fjs); + }(document, 'script', 'context')); - }; + // Wait for the asynchronous resources to load + twttr.ready(function (twttr) { + // Now bind our custom intent events + twttr.events.bind('tweet', function (event) { - // Load the context server script asynchronously - (function (document, elementToCreate, id) { - var js, fjs = document.getElementsByTagName(elementToCreate)[0]; - if (document.getElementById(id)) return; - js = document.createElement(elementToCreate); - js.id = id; - js.src = "/context.js"; - js.type = "text/javascript"; - fjs.parentNode.insertBefore(js, fjs); - }(document, 'script', 'context')); + var defaultErrorCallback = function () { + alert('There was an error making the request.'); + }; - // Load the SDK asynchronously - (function (document, elementToCreate, id) { - var js, fjs = document.getElementsByTagName(elementToCreate)[0]; - if (document.getElementById(id)) return; - js = document.createElement(elementToCreate); - js.id = id; - js.src = "//connect.facebook.net/en_US/sdk.js"; - js.type = "text/javascript"; - fjs.parentNode.insertBefore(js, fjs); - }(document, 'script', 'facebook-jssdk')); + function generateUUID() { + var d = new Date().getTime(); + if (window.performance && typeof window.performance.now === "function") { + d += performance.now(); //use high-precision timer if available + } + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16); + }); + return uuid; + } - // Here we run a very simple test of the Graph API after login is - // successful. See statusChangeCallback() for when this call is made. - function testAPI() { - console.log('Welcome! Fetching your information.... '); - FB.api('/me', function (response) { - console.log('Good to see you, ' + response.name + '.'); - document.getElementById('status').innerHTML = 'Good to see you, ' + - response.name; + function contextRequest(successCallback, errorCallback, payload) { + var data = JSON.stringify(payload); + // if we don't already have a session id, generate one + var sessionId = cxs.sessionId || generateUUID(); + var url = 'http://localhost:8181/context.json?sessionId=' + sessionId; + var xhr = new XMLHttpRequest(); + var isGet = data.length < 100; + if (isGet) { + xhr.withCredentials = true; + xhr.open("GET", url + "&payload=" + encodeURIComponent(data), true); + } else if ("withCredentials" in xhr) { + xhr.open("POST", url, true); + xhr.withCredentials = true; + } else if (typeof XDomainRequest != "undefined") { + xhr = new XDomainRequest(); + xhr.open("POST", url); + } + xhr.onreadystatechange = function () { + if (xhr.readyState != 4) { + return; + } + if (xhr.status == 200) { + var response = xhr.responseText ? JSON.parse(xhr.responseText) : undefined; + if (response) { + cxs.sessionId = response.sessionId; + successCallback(response); + } + } else { + console.log("contextserver: " + xhr.status + " ERROR: " + xhr.statusText); + if (errorCallback) { + errorCallback(xhr); + } + } + }; + xhr.setRequestHeader("Content-Type", "text/plain;charset=UTF-8"); // Use text/plain to avoid CORS preflight + if (isGet) { + xhr.send(); + } else { + xhr.send(data); + } + } - // update digitalData W3 Customer Experience Digital Data structure - digitalData.profile[0].profiles[0].profileInfo.profileName = response.name; - digitalData.profile[0].profiles[0].profileInfo.email = response.email; - digitalData.profile[0].profiles[0].profileInfo.gender = response.gender; - digitalData.profile[0].profiles[0].profileInfo.firstName = response.first_name; - digitalData.profile[0].profiles[0].profileInfo.lastName = response.last_name; + var scope = 'unomi-tweet-button-sample'; + var itemId = btoa(window.location.href); + var source = { + itemType: 'page', + scope: scope, + itemId: itemId, + properties: { + url: window.location.href + } + }; + var contextPayload = { + source: source, + events: [ + { + eventType: 'tweetEvent', + scope: scope, + source: source + } + ], + requiredProfileProperties: [ + 'tweetNb', + 'tweetedFrom' + ] + }; - cxs.saveContext("/context.js", digitalData, function (xhr) { - console.log("Profile context updated successfully.") + contextRequest(function (response) { + console.log("Profile sucessfully updated with tweetNB = " + response.profileProperties.tweetNb + " and tweetedFrom = " + response.profileProperties.tweetedFrom); + console.log(response); + }, defaultErrorCallback, contextPayload); }); }); - } -</script> - -<!-- - Below we include the Login Button social plugin. This button uses - the JavaScript SDK to present a graphical Login button that triggers - the FB.login() function when clicked. ---> - -<fb:login-button scope="public_profile,email" onlogin="checkLoginState();"> -</fb:login-button> - -<div id="status"> -</div> + </script> +</head> +<body> +<a href="https://twitter.com/share" class="twitter-share-button" data-via="jahia" data-related="jahia" data-hashtags="jahia">Tweet</a> </body> </html> \ No newline at end of file
