Exposing user details to JS

In our projects we are currently looking at how we can improve our solutions to be more adaptive to users, specifically looking at how we can make changes to improve the experience with say dyslexia or varying forms of colour blindness.

Now the bodge solution to this is to offer the user an option to pick from a dropdown on the site that we inject, however it'd be great if a user could specify in their profile settings these requirements and then in the JS be able to access a User object which contains their basic details along with any of these other settings such as additional requirements they have that we can catch in our code to provide those necessary changes.

So could we get:

  1. Settings in the user profile where they can include additional needs they have
  2. A user object exposed in JS that we can access this detail, along with the other basic details (name, phone, email)
  • Thomson Reuters Thomson Reuters staff member

    Ryan McDonough I think I'm missing something here... We have a User endpoint which effectively gives you the entire user object? Is that not sufficient for your use case? Did you want something different?

    You can't add custom attributes, but you could easily twist some of the preexisting ones, (i'd think under the 'about me section' in the UI, would be the most appropriate):

  • Peter Simpson So for this I'm talking about something which doesn't require calling the actual API, more than in the same way that I can access in the global scope on any page:

    I'd like to be able to access say: CurrentUser and be able to get CurrentUser.FullName CurentUser.Email

    Unless the endpoint you're talking about is a .action endpoint I can call from just standard JS without having to get an API key for the current user?
     

  • Thomson Reuters Thomson Reuters staff member

    Ryan McDonough Thanks I understand. So just an enhancement to bake a bit more detail in those global variables? Imran Aziz does this fall into your scope or is it a different team?

  • Peter Simpson Yeah exactly, having some more details about the user, their groups etc would really help when extending some functionality in HighQ.

  • Ryan McDonough, example library attached that can retrieve some user details asynchronously from within Collaborate (without using API)...this is taken from code written 5yrs ago, I had a quick test and it still seems to be working as expected. Should also be IE11 compliant (if required).

    Usage:

    
    	// user ID
    	CommunityExamples.User.getDetails(userID).then(function(details) {
    		console.log(details;
    	});
    	
    	// or encrypted user ID
    	CommunityExamples.User.getDetails(encryptedUserID).then(function(details) {
    		console.log(details;
    	});
    	
    

    Doesn't include any User Group permissions, this you'll have to infer some other way.

    Andrew

    /*  
       Copyright (c) Corrs Technology Solutions
    
       Permission is hereby granted, free of charge, to any person
       obtaining a copy of this software and associated documentation
       files (the "Software"), to deal in the Software without
       restriction, including without limitation the rights to use,
       copy, modify, merge, publish, distribute, sublicense, and/or sell
       copies of the Software, and to permit persons to whom the
       Software is furnished to do so, subject to the following
       conditions:
    
       The above copyright notice and this permission notice shall be
       included in all copies or substantial portions of the Software.
    
       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
       OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
       NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
       WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
       FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
       OTHER DEALINGS IN THE SOFTWARE.
    */
    ;(function($, window, document, _, undefined) {
    
       var Utils = {
          getToken: function(encoded) {
             if (!window["collab_csrfTokenName"]) {
                console.error("CommunityExamples: getToken - No CSRF Token defined!");
                return null;
             }
             encoded = (encoded === undefined) ? false : !!encoded;
             return (encoded)
                ? { name: window["collab_csrfTokenName"], value: window["collab_csrfTokenValue"] }
                : { name: window["collab_nonEncodedCsrfTokenName"], value: window["collab_nonEncodedCsrfTokenValue"] };
          },
          cleanText: function(text) {
             return text.replace(/[\t\n]*/gmi, "");
          },
          getUserEncryptedID: function(userID) {
             var token = Utils.getToken(true);
             return $.ajax({
                method: "GET",
                url: "./userInfoForMiniCard.action?metaData.targetUserID={{USER_ID}}&{{CSRF_TOKEN_NAME}}={{CSRF_TOKEN_VALUE}}"
                   .replace(/{{USER_ID}}/ig, userID)
                   .replace(/{{CSRF_TOKEN_NAME}}/ig, token["name"])
                   .replace(/{{CSRF_TOKEN_VALUE}}/ig, token["value"])
             }).then(function(data, status, xhr) {
                
                var encryptedUserID = "",
                   $link = $(data).find("a.usertitle");
    
                if (!!$link.length) {
                   // find encrypted text within link
                   var re = /=.*&metaData/ig;
                   var matches = $link.attr("href").match(re);
                   if (!!matches.length) {
                      encryptedUserID = matches[0].replace("&metaData","").substr(1); // and use
                   }
                }
    
                // fail promise if no encrypted ID
                return (!!encryptedUserID.length) ? encryptedUserID :
                   $.Deferred().reject(data, "Invalid User ID", xhr).promise();
             });
          }
       };
       
       window.CommunityExamples = window.CommunityExamples || {};
       window.CommunityExamples.User = window.CommunityExamples.User || {};
    
       // expose library public functions...
       window.CommunityExamples.User.getDetails = function(userID) {
    
          // if encrypted userID provided, use it
          // otherwise find the encrypted userID
          var isEncrypted = Number.isNaN(+userID),
             deferred = !!isEncrypted
                ? $.Deferred().resolve(userID)               
                : Utils.getUserEncryptedID(userID);
       
          return deferred.then(function(encryptedUserID) {
             var token = Utils.getToken(true);
             var ts = new Date().valueOf();
             return $.ajax({
                method: "POST",
                mimeType: "application/x-www-form-urlencoded",
                url: "./getUserProfileSummary.action?{{CSRF_TOKEN_NAME}}={{CSRF_TOKEN_VALUE}}"
                   .replace(/{{CSRF_TOKEN_NAME}}/ig, token["name"])
                   .replace(/{{CSRF_TOKEN_VALUE}}/ig, token["value"]),
                data: {
                   "metaData.encryptTargetUserID":encryptedUserID,
                   "check":true,
                   "metaData.screenWidth":window.screen.availWidth,
                   "ts":ts
                }
             }).then(function(result) {
                // look for details in (html) response...
                var $result = $(result), details = {};
                details.userID = +$result.find("#msTeamTargetSummaryUserId").val();
                details.encryptedUserID = encryptedUserID;
                details.name = Utils.cleanText($result.find("#userProfilefullName").text());
                details.email = Utils.cleanText($result.find("div.profileUserData a[href*='mailto:']").attr("title"));
                details.jobTitle = Utils.cleanText($result.find("div.profileUserData #function > strong").html());
                details.location = $result.find("div.profileUserData #officeAdd").text().replace(/\t*/mig, "").split("\n");
                details.phone = Utils.cleanText($result.find("div.profileUserData p.margBott2 a").text());
                details.mobile = Utils.cleanText($result.find("div.profileUserData p.margBott5 a").text());
                details.bio = Utils.cleanText($result.find("#userBioData pre").text());
                details.avatar = "./downloadUserAvatar.action?user.userId={{USER_ID}}&user.avatarWidth=256&user.lastModifiedTime={{TIMESTAMP}}"
                   .replace(/{{USER_ID}}/ig, details.userID)
                   .replace(/{{TIMESTAMP}}/ig, ts);
                details.specialities = [];
                $result.find("div.tagSection > div.tagContainer > a").each(function(){
                   details.specialities.push($(this).text());
                });
                return details;
             });         
          });
       };
    
    })(jQuery.noConflict(), window, document, _);

  • Andrew Quinn Thanks for that, that was the approach I was planning to take to get the basics - one of those where I'd prefer not to but needs must eh!

     

  • Hey Ryan McDonough,

    Great to see you thinking about user experience improvements. A user profile settings section sounds like a solid plan. To tackle the accessibility tweaks for dyslexia and color blindness, consider adding a feature where users can specify their preferences in their profiles.

    Now, about the JS part – having a User object accessible in JS is a nifty idea. It could hold not just the basics like name and contact info, but also these specific user preferences. This way, your code can adapt and provide a seamless experience based on individual needs.

    I implemented a similar solution in one of my projects and it made a splash in terms of personalization. Andersen's (the company for which I created this project) experience in software development and user-centric solutions played an important role in this success. Just make sure that sensitive user data is handled securely.

    Good luck :)