Tuesday, 26 November 2013

Freezing Users from Visualforce

One of the new features in the Winter 14 release of Salesforce is the ability to freeze a user, which stops them logging into the system.  The Salesforce help points towards using this functionality when you would like to deactivate a user but additional work is required as the user is part of other configuration, as the default lead owner for example.  This is one use for this functionality, but another occurred to me based on work that I carried out about 20 years ago.

In a former life I used to build deal capture and risk management systems for investment banks.  A requirement of many of the banks was that traders had to take a two-week holiday every year and had to be locked out of all systems for the entire two weeks  The thinking behind this was that if the trader had something to hide, it was likely to surface during this two-week period when they couldn’t take any action to cover it up. 

Freezing users is therefore a great fit for temporarily disabling a user’s access to the system, with the intention of re-instating their access after a period of time.  The downside to the feature is that it can only be accessed from the user record, which means that an administrator has to click into individual user accounts to freeze or unfreeze them. This is fine for the odd user, but becomes time-consuming when it has to be done on a regular basis for a number of users.  

After digging through the Apex Developer’s Guide and experimenting with the execute anonymous element of the developer console it quickly became clear that I couldn’t freeze a user in Apex.  Searching the SOAP API Developer’s Guide proved more productive when I came across the UserLogin object and its associated IsFrozen field.  While this still mean that I couldn’t use Apex, the SOAP API is accessible via the Ajax Toolkit which I can use from a Visualforce page.

It was then short work to create The Freezer - a Visualforce page to output all usernames present in the system and allow them to be frozen/defrosted at the click of a button.  The page is shown below:

Screen Shot 2013 11 03 at 17 49 39

clicking on the Freeze button next to the Customer User pops a dialog to detail the action being taken:

Screen Shot 2013 11 03 at 17 50 00

and a further popup displays the results:

Screen Shot 2013 11 03 at 17 50 14

before the page refreshes itself and displays the Defrost button for the Customer User:

Screen Shot 2013 11 03 at 17 50 26

and just to prove there’s no trickery, here’s the Customer User record with the Unfreeze button present:

Screen Shot 2013 11 03 at 17 51 14

The functionality is provided by a couple of JavaScript functions. The getUserInfo() pulls back all the UserInfo records in the system and stores them in the equivalent of a Map keyed by user id.  It then retrieves all of the active user records in the system, and dynamically builds the table of users including the action buttons:

 
function getUserInfo()
    {
      var userInfoById = {};
    
      var result = sforce.connection.query(
          "Select Id, UserId, IsFrozen, IsPasswordLocked From UserLogin order by UserId");
 
      var it = new sforce.QueryResultIterator(result);
 
      while(it.hasNext())
      {
         var record = it.next();
 
         userInfoById[record.UserId] = record;
      }
      
      
      var output='<table><tr><th>User</th><th>Action</th></tr>';
      
      result = sforce.connection.query(
          "Select Id, FirstName, LastName from User where IsActive=true");
 
      it = new sforce.QueryResultIterator(result);
 
      while(it.hasNext())
      {
        var record = it.next();
        
        if (record.Id in userInfoById)
        {
          var userInfo=userInfoById[record.Id];
          var name=record.FirstName + ' ' + record.LastName;
          output+='<tr><td>' + name + '</td><td>';
          if (userInfo.IsFrozen=='true')
          {
            output+="<button onclick=\"freeze('" + userInfo.Id + "', '" + name + "', false);\">Defrost</button>";
          }
          else
          {
            output+="<button onclick=\"freeze('" + userInfo.Id + "', '" + name + "', true);\">Freeze</button>";
          }
          output+='</td></tr>';
        }
      }
      
      output+='</table>';
      
      document.getElementById('output').innerHTML=output;
    }
  

The freeze function updates the UserLogin for the selected user to freeze or defrost them:

function freeze(id, name, freezerState)
  {
    alert("Freezing " + name);
    var userlogin = new sforce.SObject("UserLogin");
    userlogin.Id = id;
    userlogin.IsFrozen = freezerState;
    var result = sforce.connection.update([userlogin]);
 
    if (result[0].getBoolean("success")) {
        alert(name + " " + (freezerState?'frozen':'defrosted'));
    } else {
        alert("failed to " + name + " " + result[0]);
    }
    
    window.location.reload();
  }

The code is pretty basic - there’s not much error handling and it is unlikely to scale when there are a large number of users, but those elements are left as an exercise for the avid student. You can access the full page at this gist.

  

2 comments:

  1. Neat, I froze few user today and was thinking today itself on how can we do this in bulk. You bought this at right time. Thanks for sharing Keir

    ReplyDelete
  2. How could this be updated to replace the Freeze button on a user record? The freeze button will still freeze the user but also update an IsFrozen flag?

    ReplyDelete