{"id":762,"date":"2019-06-20T09:20:23","date_gmt":"2019-06-20T08:20:23","guid":{"rendered":"http:\/\/wollef.org\/?p=762"},"modified":"2019-06-20T09:20:23","modified_gmt":"2019-06-20T08:20:23","slug":"le-module-de-gestion-de-la-connexion-de-salesforce-vers-mercedes-cloud","status":"publish","type":"post","link":"https:\/\/wollef.org\/blog\/le-module-de-gestion-de-la-connexion-de-salesforce-vers-mercedes-cloud\/","title":{"rendered":"Le module de gestion de la connexion de Salesforce vers Mercedes Cloud (2\/3) : La connexion"},"content":{"rendered":"<p>Dans les Posts pr\u00e9c\u00e9dents, nous avons examin\u00e9 comment appeler le serveur Mercedes Cloud &#8216;\u00e0 la main&#8217; dans la console de programmation Salesforce. Le but de ce Post est d&#8217;expliquer comment impl\u00e9menter le code de mani\u00e8re \u00e0 ce qu&#8217;il soit utilisable par un utilisateur normal.<\/p>\n<h1><a name=\"_Toc6859845\"><\/a>1.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Un nouvel objet pour stocker les infos de connexion<\/h1>\n<p>On vient de travailler \u2018\u00e0 la main\u2019 dans la console. Mais si on veut que ce soit facile de travailler avec tous ces codes, ce serait bien de les enregistrer quelque part.<\/p>\n<p>Pour cela on va cr\u00e9er un objet SF qui sert \u00e0 m\u00e9moriser les informations de la connexion vers Mercedes, on a besoin de :<\/p>\n<ul>\n<li>client id =txt<\/li>\n<li>client secret=txt<\/li>\n<li>authorisation code=txt<\/li>\n<li>access token=txt<\/li>\n<li>expiration date = date\/time<\/li>\n<li>scope = texte<\/li>\n<li>refresh token = texte<\/li>\n<\/ul>\n<p>On va cr\u00e9er les champs de cet objet connexion avec le menu setup, comme on avait fait pour l\u2019objet voiture.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-765\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2019\/06\/mod1-300x204.png\" alt=\"\" width=\"457\" height=\"311\" \/><\/p>\n<p>On peut du coup saisir les informations de connexion dans Salesforce<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-766\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2019\/06\/mod2-300x134.png\" alt=\"\" width=\"459\" height=\"205\" \/><\/p>\n<p>Et aussi faire les requ\u00eates avec du code SOQL comme on l\u2019a fait avant pour les voitures\u00a0:<\/p>\n<pre><code>SELECT Id, Mercedes_API_Client_ID__c, Mercedes_API_Client_Secret__c FROM Mercedes_API_Connection__c<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-767\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2019\/06\/mod3-300x292.png\" alt=\"\" width=\"447\" height=\"435\" \/><\/p>\n<h1><a name=\"_Toc6859846\"><\/a>2.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Comment savoir pour quelle connexion on a demand\u00e9 l\u2019autorisation\u00a0?<\/h1>\n<p>Quand le serveur Mercedes renvoie vers la page SF, on ne peut pas passer de param\u00e8tre. Il n\u2019est pas possible de savoir quelle Mercedes Connection a \u00e9t\u00e9 autoris\u00e9e s\u2019il y en a plusieurs configur\u00e9es dans SF.<\/p>\n<p>On va donc devoir \u00ab\u00a0marquer\u00a0\u00bb dans la base SF quelle connexion est concern\u00e9e avant l\u2019appel de la page d\u2019autorisation Mercedes, pour que quand l\u2019utilisateur revient dans SF sur la page d\u2019apr\u00e8s-autorisation on retrouve la connexion concern\u00e9e.<\/p>\n<p>On a ajout\u00e9 deux champs \u00e0 l\u2019objet Mercedes Connection\u00a0:<\/p>\n<ul>\n<li>Last_Autorisation_Request_Time__c\u00a0: la derni\u00e8re fois qu\u2019un utilisateur a demand\u00e9 l\u2019autorisation<\/li>\n<li>Last_Autorisation_Request_User__c\u00a0: quel utilisateur a demand\u00e9 l\u2019autorisation<\/li>\n<\/ul>\n<p>Avant d\u2019aller vers la page d\u2019autorisation Mercedes, on va marquer la connexion ainsi en m\u00e9morisant que la connexion vient d\u2019\u00eatre demand\u00e9e par l\u2019utilisateur et que cela vient de se faire.<\/p>\n<h1><a name=\"_Toc6859847\"><\/a>3.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Page pour demander la connexion<\/h1>\n<p>On va cr\u00e9er un composant visuel qui sera plac\u00e9 sur les objets Mercedes Api Connection.<\/p>\n<p>Ce composant va permettre de cliquer sur un bouton pour aller sur le serveur Mercedes pour activer la connexion.<\/p>\n<h2>a)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Le composant visuel<\/h2>\n<p>C\u2019est un simple composant qui affiche l\u2019Id de la connexion et un bouton pour appeler la page de connexion<\/p>\n<pre><code>&lt;template&gt;\n\n&lt;lightning-card title=\"Connection Information\" icon-name=\"standard:people\"&gt;\n&lt;div class=\"slds-m-around_medium\"&gt;\n&lt;p&gt;The connection is &lt;\/p&gt;\n&lt;ul&gt;\n&lt;li&gt;SF ID : {recordId}&lt;\/li&gt;\n&lt;\/ul&gt;\n\u00a0\n&lt;\/div&gt;\n&lt;lightning-button label=\"Activate Connection\" onclick={handleActivateConnection} variant=\"brand\"&gt;&lt;\/lightning-button&gt;\n&lt;\/lightning-card&gt;\n\u00a0\n&lt;\/template&gt;<\/code><\/pre>\n<h2>b)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Le code javascript du composant<\/h2>\n<p>Dans le code javascript du composant, ce qu\u2019il y a de particulier est que\u00a0:<\/p>\n<ul>\n<li>Le code <strong>handleActivateConnection<\/strong> appelle d\u2019abord une m\u00e9thode <strong>memorizeAutorisationRequestContext<\/strong> du serveur (Apex) pour stocker le fait qu\u2019on vient de lancer le processus pour cette connexion (voir paragraphe suivant)<\/li>\n<\/ul>\n<pre><code>memorizeAutorisationRequestContext( {aConnectionId :\u00a0 this.recordId })<\/code><\/pre>\n<ul>\n<li>Quand cela a march\u00e9, dit d\u2019aller vers la page de connexion Mercedes (l\u2019URL est calcul\u00e9e par le code cot\u00e9 serveur)\u00a0:<\/li>\n<\/ul>\n<pre><code>this[NavigationMixin.Navigate]({\n\"type\" : \"standard__webPage\",\nattributes: {\n\"url\" : this.autorisationPageURL.data\n}\n}<\/code><\/pre>\n<p>Cela donne le code suivant pour le javascript du composant :<\/p>\n<pre><code>import { LightningElement, api, wire } from 'lwc';\nimport { getRecord \/*, getFieldValue *\/ } from 'lightning\/uiRecordApi';\nimport { ShowToastEvent } from 'lightning\/platformShowToastEvent';\nimport { NavigationMixin } from 'lightning\/navigation';\n\nimport memorizeAutorisationRequestContext from '@salesforce\/apex\/MercedesAPI.memorizeAutorisationRequestContext';\n\nimport getAuthorizationPageURL from '@salesforce\/apex\/MercedesAPI.getAuthorizationPageURL';\n\nimport CONNECTION_SALEFORCE_ID from '@salesforce\/schema\/Mercedes_API_Connection__c.Id';\n\nimport CONNECTION_CLIENT_ID from '@salesforce\/schema\/Mercedes_API_Connection__c.Mercedes_API_Client_ID__c';\n\nimport CONNECTION_CLIENT_SECRET from '@salesforce\/schema\/Mercedes_API_Connection__c.Mercedes_API_Client_Secret__c';\n\nimport CONNECTION_ACCESS_TOKEN from '@salesforce\/schema\/Mercedes_API_Connection__c.Mercedes_API_Acces_Token__c';\n\n\nconst connectionFields = [\nCONNECTION_SALEFORCE_ID,\nCONNECTION_CLIENT_ID,\nCONNECTION_CLIENT_SECRET,\nCONNECTION_ACCESS_TOKEN\n];\n\nexport default class MercedesConnectionManager extends NavigationMixin(LightningElement)\n{\n\n@api recordId; \/\/ Connection Id\n@wire(getRecord, { recordId: '$recordId', fields: connectionFields })\nmercedesConnection;\n\n@wire(getAuthorizationPageURL, {\u00a0 aConnectionId: '$recordId' })\nautorisationPageURL;\nget urlInfos() {\nreturn JSON.stringify(this.autorisationPageURL);\n}\n\nhandleActivateConnection() {\nmemorizeAutorisationRequestContext( {aConnectionId :\u00a0 this.recordId })\n.then(result =&gt; {\n\/\/ small event message\nconst evt = new ShowToastEvent({\ntitle: 'Connection Context Memorized',\nmessage: 'The connection context has been successfully memorized for '+result,\nvariant: 'success',\n});\nthis.dispatchEvent(evt);\n\/\/ go to page\nthis[NavigationMixin.Navigate]({\n\"type\" : \"standard__webPage\",\nattributes: {\n\"url\" : this.autorisationPageURL.data\n}\n},\n{\nreplace: true\n}\n);\n})\n.catch(error =&gt; {\nconst evt = new ShowToastEvent({\ntitle: 'Connection Context Not Memorized',\nmessage: 'An error occured '+JSON.stringify(error),\nvariant: 'error',\n});\nthis.dispatchEvent(evt);\n});\n}\n}<\/code><\/pre>\n<h2>c)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Le code Apex<\/h2>\n<p>C\u2019est le code du c\u00f4t\u00e9 Salesforce qui fait les calculs et les sauvegarde (dans la classe MercedesAPI).<\/p>\n<p>Avant d\u2019aller vers la page d\u2019autorisation Mercedes, on marque la connexion ainsi\u00a0:<\/p>\n<pre><code>@AuraEnabled(cacheable=false)\npublic static id <strong>memorizeAutorisationRequestContext<\/strong>(Id aConnectionId) {\n\/\/ recupere la connection\nMercedes_API_Connection__c theConnection = [\nSELECT\nId,\nName,\nLast_Autorisation_Request_User__c,\nLast_Autorisation_Request_Time__c\nFROM Mercedes_API_Connection__c\nwhere id = :aConnectionId\n];\n\n\/\/ memorise qui et quand\ntheConnection.Last_Autorisation_Request_User__c = UserInfo.getUserId();\ntheConnection.Last_Autorisation_Request_Time__c = System.now();\n\n\/\/ sauve le resultat\nupdate theConnection;\n\nreturn aConnectionId;\n}<\/code><\/pre>\n<p>Et le code qui calcule la page pour demander l\u2019autorisation d\u2019acc\u00e8s \u00e0 Mercedes<\/p>\n<pre><code>@AuraEnabled(cacheable=true)\npublic static String <strong>getAuthorizationPageURL<\/strong>(Id aConnectionId) {\nMercedes_API_Connection__c myConnection = [\nSELECT\nId,\nMercedes_API_Client_ID__c\nFROM Mercedes_API_Connection__c\nWHERE id = :aConnectionId\n];\n\nreturn API_URL_Authorization\n+ '?response_type=code'\n+ '&amp;client_id=' + myConnection.Mercedes_API_Client_ID__c\n+ '&amp;redirect_uri='+redirectURI\n+ '&amp;scope='+requestedScope;\n\n}<\/code><\/pre>\n<h2>d)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Les informations du composant pour indiquer qu\u2019il est affichable sur les pages \u2018Mercedes Api Connection\u2019<\/h2>\n<pre><code>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n\n&lt;LightningComponentBundle xmlns=\"http:\/\/soap.sforce.com\/2006\/04\/metadata\" fqn=\"mercedesConnectionManager\"&gt;\n\n&lt;apiVersion&gt;45.0&lt;\/apiVersion&gt;\n\n&lt;isExposed&gt;true&lt;\/isExposed&gt;\n\n&lt;targets&gt;\n&lt;target&gt;lightning__RecordPage&lt;\/target&gt;\n&lt;\/targets&gt;\n\n&lt;targetConfigs&gt;\n&lt;targetConfig targets=\"lightning__RecordPage\"&gt;\n&lt;objects&gt;\n&lt;object&gt;Mercedes_API_Connection__c&lt;\/object&gt;\n&lt;\/objects&gt;\n&lt;\/targetConfig&gt;\n\n&lt;\/targetConfigs&gt;\n\n&lt;\/LightningComponentBundle&gt;<\/code><\/pre>\n<h2>e)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Le composant ajout\u00e9 \u00e0 la page de l\u2019objet API Connection<\/h2>\n<p>On ajoute le composant \u00e0 la page comme on avait fait avant pour le composant qui affichait la couleur d\u2019une voiture.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-768\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2019\/06\/mod4-300x79.png\" alt=\"\" width=\"482\" height=\"127\" \/><\/p>\n<h1><a name=\"_Toc6859848\"><\/a>4.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Page qui r\u00e9cup\u00e8re les informations de demande d\u2019autorisation<\/h1>\n<p>Quand on clique sur le lien, on arrive chez Mercedes o\u00f9 on peut valider qu&#8217;on autorise l&#8217;acc\u00e8s, puis Mercedes redirige sur la page Mercedes API Authorization (ce qu\u2019on avait fait dans la partie d\u2019avant)<\/p>\n<p>Il faut maintenant faire que cette page utilise le code d\u2019autorisation qu&#8217;elle a r\u00e9cup\u00e9r\u00e9<\/p>\n<h2>a)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 La page<\/h2>\n<p>Pour cela on ajoute un bouton sur la page<\/p>\n<pre><code>&lt;apex:page controller=\"Mercedes_API_Authorization_Ctrl\" &gt;\nAuthorization : {! authorizationCode}\n&lt;apex:form &gt;\n<strong>\u00a0 &lt;apex:commandButton value=\"validate connection request\" action=\"{!saveAuthorizationCode}\" \/&gt;<\/strong>\n&lt;\/apex:form&gt;\n&lt;\/apex:page&gt;<\/code><\/pre>\n<p>Le bouton appelle une action <strong>saveAuthorizationCode<\/strong> dans le contr\u00f4leur de la page (Mercedes_API_Authorization_Ctrl )<\/p>\n<h2>b)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Le code Apex<\/h2>\n<p>Du coup, quand on revient dans l\u2019environnement SF de l\u2019utilisateur on peut retrouver la bonne connexion pour y sauver les informations de session (token, etc.)\u00a0: on prend la derni\u00e8re connexion modifi\u00e9e par cet utilisateur<\/p>\n<pre><code>public PageReference <strong>saveAuthorizationCode<\/strong>() {\n\nmercedesConnection = [\nSELECT\nId,\nName,\nMercedes_API_Client_ID__c,\nMercedes_API_Client_Secret__c,\nMercedes_API_Autorization_Code__c\nFROM Mercedes_API_Connection__c\nwhere\nLast_Autorisation_Request_User__c= : UserInfo.getUserId()\norder by Last_Autorisation_Request_Time__c desc\nlimit 1\n];\n\n\u2026.\n\n}<\/code><\/pre>\n<ol>\n<li>c) On utilise le code de connexion qu&#8217;on avait auparavant recopi\u00e9 dans une classe MercedesAPI pour pouvoir le r\u00e9utiliser.<\/li>\n<\/ol>\n<pre><code>MercedesAPI api = new MercedesAPI(\ntheConnection.Mercedes_API_Client_ID__c,\ntheConnection.Mercedes_API_Client_Secret__c\n);\napi.initSession(authorizationCode);<\/code><\/pre>\n<ol>\n<li>d) On stocke l&#8217;autorisation et les tokens obtenus<\/li>\n<\/ol>\n<pre><code>theConnection.Mercedes_API_Autorization_Code__c = authorizationCode;\ntheConnection.Mercedes_API_Acces_Token__c = api.access_token;\n\/\/ sauver les autres champs ici\nupdate theConnection;<\/code><\/pre>\n<p>Et voil\u00e0 la connexion est \u00e9tablie !<\/p>\n<p>Voici le code avec tous les morceaux mis ensemble.<\/p>\n<pre><code>\u00a0\npublic PageReference saveAuthorizationCode() {\n\nMercedes_API_Connection__c theConnection = [\nSELECT\nId,\nMercedes_API_Client_ID__c,\nMercedes_API_Client_Secret__c,\nMercedes_API_Autorization_Code__c\nFROM Mercedes_API_Connection__c\n\/\/ where id = :monID\nlimit 1\n];\n\nMercedesAPI api = new MercedesAPI(\ntheConnection.Mercedes_API_Client_ID__c,\ntheConnection.Mercedes_API_Client_Secret__c\n);\n\napi.initSession(authorizationCode);\napi.getVehicules();\n\ntheConnection.Mercedes_API_Autorization_Code__c = authorizationCode;\ntheConnection.Mercedes_API_Acces_Token__c = api.access_token;\n\n\/\/ sauver les autres champs ici\nupdate theConnection;\n\nvehiculeTexte = api.vehiculesJson;\nreturn null;\n}<\/code><\/pre>\n<p>Et on peut demander \u00e0 rafra\u00eechir cette partie de page apr\u00e8s le clic sur le bouton<\/p>\n<pre><code>&lt;apex:commandButton value=\"validate connection request\" action=\"{!saveAuthorizationCode}\" reRender=\"vehiculesPanel\"\/&gt;<\/code><\/pre>\n<p>Voici ce qu\u2019on voit quand on arrive sur la page \u2018redirect url\u2019 apr\u00e8s \u00eatre pass\u00e9 sur le serveur Mercedes\u00a0:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-771\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2019\/06\/mod5-300x124.png\" alt=\"\" width=\"477\" height=\"197\" \/><\/p>\n<p>Puis ce qu\u2019on voit quand on clique sur \u2018Validate\u2019<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-770\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2019\/06\/mod6-300x129.png\" alt=\"\" width=\"470\" height=\"202\" \/><\/p>\n<p>La connexion est maintenant active et le token de session est enregistr\u00e9.<\/p>\n<h1><a name=\"_Toc6859849\"><\/a>5.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Rafraichissement automatique du token de connexion<\/h1>\n<p><em>Normalement, le jeton de session n\u2019est valide qu\u2019une heure. Il faudrait faire un code qui appel l\u2019API pour rafra\u00eechir automatiquement le token toutes les heures. <\/em><\/p>\n<p><em>Je ne l\u2019ai pas fait dans le temps de mon Trape.<\/em><\/p>\n<p><em>C\u2019est une am\u00e9lioration \u00e0 faire. Pour le moment, il faut recliquer sur ces \u00e9crans toutes les heures.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dans les Posts pr\u00e9c\u00e9dents, nous avons examin\u00e9 comment appeler le serveur Mercedes Cloud &#8216;\u00e0 la main&#8217; dans la console de programmation Salesforce. Le but de ce Post est d&#8217;expliquer comment impl\u00e9menter le code de mani\u00e8re \u00e0 ce qu&#8217;il soit utilisable par un utilisateur normal. 1.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Un nouvel objet pour stocker les infos de connexion On <a class=\"read-more\" href=\"https:\/\/wollef.org\/blog\/le-module-de-gestion-de-la-connexion-de-salesforce-vers-mercedes-cloud\/\">Continue Reading<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[30,33,48,49,18,20],"tags":[],"class_list":["post-762","post","type-post","status-publish","format-standard","hentry","category-cars-and-clouds","category-apex","category-lightning-web-component","category-mercedes","category-salesforce","category-soql"],"_links":{"self":[{"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/posts\/762","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/comments?post=762"}],"version-history":[{"count":0,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/posts\/762\/revisions"}],"wp:attachment":[{"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/media?parent=762"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/categories?post=762"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/tags?post=762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}