{"id":7113,"date":"2021-03-07T19:46:51","date_gmt":"2021-03-07T17:46:51","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=7113"},"modified":"2021-03-07T19:46:52","modified_gmt":"2021-03-07T17:46:52","slug":"hcl-connections-pruefen-wer-touchpoint-nicht-abgeschlossen-hat","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/hcl-connections-pruefen-wer-touchpoint-nicht-abgeschlossen-hat\/","title":{"rendered":"HCL Connections: Pr\u00fcfen wer Touchpoint (nicht) abgeschlossen hat"},"content":{"rendered":"<p>Mit HCL Connections 6.5 wird Touchpoint automatisch installiert. Hierbei handelt es sich um einen sogenannten<em> Onboarding-Assistenten<\/em>: Er soll auf der einen Seite neue Anwender an die Hand nehmen, ihnen beim ausf\u00fcllen des Profiles, finden von Communitys, anderen Personen etc. helfen. Dar\u00fcber hinaus kann auch eine Datenschutzerkl\u00e4rung inklusive Version eingebunden werden. Der Nutzer muss diese akzeptieren, was wiederum systemseitig gespeichert wird. Touchpoint gab es zuvor schon. Allerdings musste die Anwendung h\u00e4ndisch installiert werden.<\/p>\n<p>Bisher geschah die Einbindung \u00fcber ein JavaScript-Schnipsel in der <strong>header.jsp<\/strong> bzw. <strong>footer.jsp<\/strong> recht transparent. Mit 6.5 wanderte dies ins Backend und es gibt offiziell auch keine Einstellungsm\u00f6glichkeiten f\u00fcr z.B. den Intervall mehr. Erschwerend hinzu kommt, dass der Touchpoint nach Aktivierung aufgrund verschiedener Caches gar nicht oder erst sp\u00e4ter erscheint. <\/p>\n<h2 class=\"wp-block-heading\">Wo speichert Touchpoint seine Daten?<\/h2>\n<p>Es ist daher nur sinnvoll nachzuschauen, ob und wer \u00fcberhaupt den Touchpoint abgeschlossen hat. Leider gibt es hierzu keinerlei Oberfl\u00e4che oder Dokumentation. Alles Folgende basiert daher auf eigener Arbeit, Recherche sowie Reverse Engineering.<\/p>\n<p>Zun\u00e4chst muss man wissen, dass Touchpoint zwei benutzerdefinierte Profilfelder anlegt. Alle Daten befinden sich somit in der Tabelle <strong>EMPINST.PROFILE_EXTENSIONS<\/strong>. Gefiltert werden muss nach den im folgenden erl\u00e4uterten Schl\u00fcsseln.<\/p>\n<h3 class=\"wp-block-heading\">Die Touchpoint Sitzung<\/h3>\n<p>t<strong>ouchpointSession<\/strong> wird beim ersten Aufruf des Touchpoints angelegt. Das System speichert darin ein riesiges JSON-Dokument von ca. 10KB gr\u00f6\u00dfe. Darin sind zahlreiche Informationen \u00fcber das Profil des Nutzers, seine Communitys in denen er Mitglied ist und vieles mehr enthalten. Dar\u00fcber hinaus auch eigene Daten von Touchpoint, wie etwa den zuletzt ge\u00f6ffneten Schritt. Schlie\u00dft ein Nutzer den Touchpoint in Schritt 2, wird er beim n\u00e4chsten Aufrufen wieder dort landen &#8211; statt ihn erneut durchklicken zu m\u00fcssen. Das gespeicherte JSON-Dokument l\u00e4sst sich auch \u00fcber die Profile-API aufrufen:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nhttps:\/\/cnx.host\/profiles\/atom\/profileExtension.do?key=51673ab8-4e38-46ca-83ca-795796074813&amp;amp;extensionId=touchpointSession\n<\/pre>\n<\/div>\n<p>Direkt aus der Datenbank erhalten wir es mit folgender Abfrage (DB2):<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nSELECT PROF_KEY, CAST(PROF_VALUE_EXTENDED as VARCHAR(32672) CCSID UNICODE) as JSON_VALUE\nFROM EMPINST.PROFILE_EXTENSIONS \nWHERE PROF_PROPERTY_ID = &#039;touchpointSession&#039;\n<\/pre>\n<\/div>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik.png\"><img loading=\"lazy\" decoding=\"async\" width=\"509\" height=\"159\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik.png\" alt=\"\" class=\"wp-image-7114\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik.png 509w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-300x94.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-70x22.png 70w\" sizes=\"auto, (max-width: 509px) 100vw, 509px\" \/><\/a><\/figure>\n<p>Wenn wir hier leere Felder erhalten wie in der ersten Zeile, ist vermutlich ein Fehler in der Standardkonfiguration schuld. Die Datei tdisol\/conf\/LotusConnections-config\/profiles-types.xml enth\u00e4lt die beiden Touchpoint-Attribute:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-xml\" data-line=\"\">&lt;property&gt;\n        &lt;ref&gt;privacyAndGuidelines&lt;\/ref&gt;\n        &lt;updatability&gt;readwrite&lt;\/updatability&gt;\n        &lt;hidden&gt;true&lt;\/hidden&gt;\n        &lt;fullTextIndexed&gt;false&lt;\/fullTextIndexed&gt;\n&lt;\/property&gt;\n&lt;property&gt;\n        &lt;ref&gt;touchpointState&lt;\/ref&gt;\n        &lt;updatability&gt;readwrite&lt;\/updatability&gt;\n        &lt;hidden&gt;true&lt;\/hidden&gt;\n        &lt;fullTextIndexed&gt;false&lt;\/fullTextIndexed&gt;\n&lt;\/property&gt;\n&lt;property&gt;\n        &lt;ref&gt;touchpointSession&lt;\/ref&gt;\n        &lt;updatability&gt;readwrite&lt;\/updatability&gt;\n        &lt;hidden&gt;true&lt;\/hidden&gt;\n        &lt;fullTextIndexed&gt;false&lt;\/fullTextIndexed&gt;\n&lt;\/property&gt;<\/code><\/pre>\n<p>Sofern es diese Felder nicht im LDAP gibt und sie dort nicht prim\u00e4r gespeichert werden (worin ich wenig Sinn sehe), m\u00fcssen sie auskommentiert werden. Ansonsten <em>synchronisiert<\/em> der TDI sie bei jedem Durchlauf. Gibt es die Felder nicht im LDAP, werden sie \u00fcberschrieben, auch wenn sich bereits Daten in der Datenbank befanden.<\/p>\n<h3 class=\"wp-block-heading\">Die akzeptierte Datenschutzerkl\u00e4rung und ggf. die Nutzungsbedingungen<\/h3>\n<p>Der Touchpoint kann auch genutzt werden, um die eigene Datenschutzerkl\u00e4rung sowie die Nutzungsbedingungen vom Benutzer best\u00e4tigen zu lassen. Hierzu muss man in der Konfiguration nur <strong>privacyAndGuidelines.enabled<\/strong> auf <strong>true <\/strong>setzen und in den Link-Attributen jeweils eine Link f\u00fcr externe und interne Nutzer hinterlegen. Auf der ersten Seite wird den Nutzern dann eine Checkbox mit den hinterlegten Links angezeigt, die er anhaken muss.<\/p>\n<p>Sinnvolerweise l\u00e4sst sich die Datenschutzerkl\u00e4rung versionieren und Touchpoint speichert, welcher Benutzer welche Version akzeptiert hat. Somit ist dies zum einen nachvollziehbar. Zum anderen lassen sich die Anwender bei ge\u00e4nderten Nutzungsbedingungen dazu auffordern, diese erneut zu akzeptieren. In diesem Falle erh\u00f6ht man beispielsweise die Version von 1.0 (Standard) auf 1.1. \u00dcber den Schl\u00fcssel <strong>privacyAndGuidelines <\/strong>k\u00f6nnen wir aus der gleichen Tabelle auslesen, welche Version akzeptiert wurde:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-sql\" data-line=\"\">SELECT PROF_KEY, PROF_VALUE \nFROM EMPINST.PROFILE_EXTENSIONS privacyExt\nWHERE privacyExt.PROF_PROPERTY_ID = &#039;privacyAndGuidelines&#039;<\/code><\/pre>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"414\" height=\"106\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-2.png\" alt=\"\" class=\"wp-image-7116\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-2.png 414w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-2-300x77.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-2-70x18.png 70w\" sizes=\"auto, (max-width: 414px) 100vw, 414px\" \/><\/a><\/figure>\n<h2 class=\"wp-block-heading\">Welcher Benutzer hat den Touchpoint erhalten und abgeschlossen?<\/h2>\n<p>Mit dem obigen Wissen kann man h\u00e4ndisch ermitteln, ob ein Benutzer den Touchpoint abgeschlossen hat und wenn ja mit welcher Version der Datenschutzerkl\u00e4rung. F\u00fcr die anfangs angesprochene \u00dcbersicht ist dies allerdings wenig hilfreich: Schlie\u00dflich m\u00fcsste man manuell die User-Id heraussuchen und in die Abfrage einf\u00fcgen &#8211; f\u00fcr jeden User. Eine Abfrage aller Daten ist ohne sprechende Benutzer wenig hilfreich. Daher habe ich eine Abfrage erstellt, mit der man alle in meinen Augen wichtigen Informationen erh\u00e4lt:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-sql\" data-line=\"\">SELECT e.PROF_DISPLAY_NAME, JSON_VAL(SYSTOOLS.JSON2BSON(PROF_VALUE), &#039;timestamp&#039; , &#039;l&#039;) AS timestampRaw,\nDATE((((JSON_VAL(SYSTOOLS.JSON2BSON(PROF_VALUE), &#039;timestamp&#039; , &#039;l&#039;) \/ 1000)-5*3600)\/86400)+719163) AS calculatedDate,\n(\n\tSELECT privacyExt.PROF_VALUE \n\tFROM EMPINST.PROFILE_EXTENSIONS privacyExt\n\tWHERE ext.PROF_KEY = privacyExt.PROF_KEY \n\tAND privacyExt.PROF_PROPERTY_ID = &#039;privacyAndGuidelines&#039;\n) AS privacyVersion\nFROM EMPINST.PROFILE_EXTENSIONS ext\nLEFT JOIN EMPINST.EMPLOYEE e ON (e.PROF_KEY = ext.PROF_KEY)\nWHERE PROF_PROPERTY_ID = &#039;touchpointState&#039;\nORDER BY JSON_VAL(SYSTOOLS.JSON2BSON(PROF_VALUE), &#039;timestamp&#039; , &#039;l&#039;) DESC<\/code><\/pre>\n<p>Als Ergebnis erhalten wir eine Tabelle mit Anzeigename, Unix-Timestamp, lesbarem Datum und Version der akzeptierten Datenschutzerkl\u00e4rung &#8211; sortiert nach Abschlussdatum:<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"690\" height=\"106\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-3.png\" alt=\"\" class=\"wp-image-7117\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-3.png 690w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-3-300x46.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/03\/grafik-3-70x11.png 70w\" sizes=\"auto, (max-width: 690px) 100vw, 690px\" \/><\/a><\/figure>\n<h3 class=\"wp-block-heading\">Alte Abfrage<\/h3>\n<p>Meine erste Abfrage war weniger elegant, da ich Probleme mit den JSON-Funktionen hatte. Mittlerweile funktioniert dies und ich habe die obige Anfrage angepasst. Zu Archivzwecken hier noch die alte Abfrage, die alles au\u00dfer dem Zeitstempel mit der String-Funktion <strong>REPLACE <\/strong>entfernt:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-sql\" data-line=\"\">SELECT e.PROF_DISPLAY_NAME, REPLACE(REPLACE(ext.PROF_VALUE, &#039;}&#039;, &#039;&#039;), &#039;{&quot;state&quot;:&quot;complete&quot;,&quot;timestamp&quot;:&#039;, &#039;&#039;) AS timestampRaw,\nDATE((((REPLACE(REPLACE(ext.PROF_VALUE, &#039;}&#039;, &#039;&#039;), &#039;{&quot;state&quot;:&quot;complete&quot;,&quot;timestamp&quot;:&#039;, &#039;&#039;) \/ 1000)-5*3600)\/86400)+719163) AS calculatedDate,\n(\n\tSELECT privacyExt.PROF_VALUE \n\tFROM EMPINST.PROFILE_EXTENSIONS privacyExt\n\tWHERE ext.PROF_KEY = privacyExt.PROF_KEY \n\tAND privacyExt.PROF_PROPERTY_ID = &#039;privacyAndGuidelines&#039;\n) AS privacyVersion\nFROM EMPINST.PROFILE_EXTENSIONS ext\nLEFT JOIN EMPINST.EMPLOYEE e ON (e.PROF_KEY = ext.PROF_KEY)\nWHERE PROF_PROPERTY_ID = &#039;touchpointState&#039;\nORDER BY REPLACE(REPLACE(ext.PROF_VALUE, &#039;}&#039;, &#039;&#039;), &#039;{&quot;state&quot;:&quot;complete&quot;,&quot;timestamp&quot;:&#039;, &#039;&#039;) DESC<\/code><\/pre>\n<p>Zugegeben, technisch ist die Abfrage nicht sauber und durch das ganze Gebastel auch nicht wirklich performant f\u00fcr gro\u00dfe Datenmengen geeignet. Dies liegt prim\u00e4r daran, dass der Touchpoint die generische Attribute-Tabelle nutzt und hier ein JSON-Objekt serialisiert gespeichert wird. Ich hatte kurz mal mit <strong>SYSTOOLS.JSON_VAL<\/strong> experimentiert &#8211; DB2 scheint grunds\u00e4tzlich tats\u00e4chlich in der Lage zu sein, mit JSON-Dokumenten in Tabellenfeldern zu arbeiten. Jedoch kam ich bisher damit zu keinem zufriedenstellenden Ergebnis.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mit HCL Connections 6.5 wird Touchpoint automatisch installiert. Hierbei handelt es sich um einen sogenannten Onboarding-Assistenten: Er soll auf der einen Seite neue Anwender an die Hand nehmen, ihnen beim ausf\u00fcllen des Profiles, finden von Communitys, anderen Personen etc. helfen. Dar\u00fcber hinaus kann auch eine Datenschutzerkl\u00e4rung inklusive Version eingebunden werden. Der Nutzer muss diese akzeptieren, &#8230;<\/p>\n","protected":false},"author":5,"featured_media":7121,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[765],"tags":[854,58,855],"class_list":["post-7113","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hcl-connections","tag-db2","tag-sql","tag-touchpoint"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/7113","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=7113"}],"version-history":[{"count":3,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/7113\/revisions"}],"predecessor-version":[{"id":7120,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/7113\/revisions\/7120"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/7121"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=7113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=7113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=7113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}