Messaging with PubNub

Users can concurrently work on the same record in Dynamics CRM and simultaneously make changes. This can cause some changes to be overwritten or missed. The users also have no way of knowing who else is working on a record, when they open it. To address these issue, we will use PubNub as a secure message transportation platform to keep users notified of any changes to record that they are currently viewing.
1.)    Signup for a free account at http://www.pubnub.com. For this proof of concept, we can use the free sandbox account.
2.)    Login to the admin portal and note down the keys.
3.)    We will be using requirejs to load the dependent scripts. There are two scripts to load: the form script and the pubnub script. Create new web resources to store these scripts.

4.)  We will be using the main.js to start the loading process. This is the script that has to be added to the form along with requirejs.

Below is the sourcecode for main.js, the loading script. We are loading pubnub from CDN. The local webresource is only used for fallback, if there is any issue with the CDN.

// <reference path="require.js">
(function () {
    var webResourceVersionNumber = '';
    //get the url for the script, so that we can extract the guid to prefix
    [].forEach.call(document.querySelectorAll('script'), function (element) {
        if (element.src.indexOf('main.js') > -1) {
            webResourceVersionNumber = element.src;
        }
    });
    webResourceVersionNumber = webResourceVersionNumber.replace(Xrm.Page.context.getClientUrl(), '').substr(1, 24);
    var defaultConfig = {
        //could also use undocumented WEB_RESOURCE_ORG_VERSION_NUMBER
        baseUrl: '/' + webResourceVersionNumber + '/WebResources/scripts_/form',
        shim: {
            'pubnub': {
                exports: 'PUBNUB'
            }
        },
        deps: ['pubnub', 'form_script'],
        callback: function () {
            console.log('callback before requirejs has been loaded');
        },
        paths: {
            pubnub: ['https://cdn.pubnub.com/pubnub.min', '../library/pubnub.min']
        },
        onError: function (err) {
            console.log(err.requireType);
            if (err.requireType === 'timeout') {
                console.log('modules: ' + err.requireModules);
            }
            throw err;
        }
    };
    if (!window['require']) {
        window['require'] = defaultConfig;
    } else {
        defaultConfig.callback = function () {
            console.log('callback after requirejs has been loaded');
        };
        require.config(defaultConfig);
    }
})();
Below is the sourcecode for form_script.js.Here is what the form displays when another user has opened the same record.
// <reference path="XrmPage-vsdoc.js">
define(['pubnub'], function(PUBNUB) {
        var pubnub = PUBNUB.secure({
            publish_key: '<PUBLISH KEY><publish key="">',
            subscribe_key: '<SUBSCRIBE KEY><subscribe key="">',
            ssl: true,
            cipher_key: '<CIPHER KEY><cipher key="">'
        }),
        pageContext = Xrm.Page.context,
        entity = Xrm.Page.data.entity,
        userName = pageContext.getUserName(),
        entityName = entity.getEntityName(),
        entityId = entity.getId(),
        userId = pageContext.getUserId(),
        FormState = {
            OPEN: 'opened',
            CLOSE: 'updated and closed',
            UPDATE: 'updated'
        },
        FormSaveType = {
            SAVE: 1,
            SAVEANDCLOSE: 2,
            SAVEANDNEW: 59,
            AUTOSAVE: 70
        },
        FormType = {
            CREATE: 1,
            UPDATE: 2,
            READONLY: 3,
            DISABLED: 4,
            QUICKCREATE: 5,
            BULKEDIT: 6,
            READOPTIMISED: 11
        };
    
        if (Xrm.Page.ui.getFormType() === FormType.UPDATE) {
            pubnub.subscribe({
                channel: "form_events",
                message: function (m) {
                    if (m.userId !== userId) {
                        var now = new Date();
                        var message = now.toLocaleString('en-GB') + ': ' + m.userName + ' ' + m.operation + ' this record';
                        Xrm.Page.ui.setFormNotification(message, 'INFO');
                        if (m.operation === FormState.UPDATE) {
                            Xrm.Utility.confirmDialog('This form has been updated by ' + m.userName + ' at ' + now.toLocaleString('en-GB') + '. Do you want to reload the form to see the latest changes?',
                                function() {
                                    Xrm.Page.data.refresh(false);
                                });
                        }
                    }
                }
            });
            pubnub.publish({
                channel: "form_events",
                message: {
                    userName: userName,
                    userId: userId,
                    entityName: entityName,
                    entityId: entityId,
                    operation: FormState.OPEN,
                    uuid: notifications.uuid
                }
            });
            Xrm.Page.data.entity.addOnSave(function onSave(context) {
                pubnub.publish({
                    channel: "form_events",
                    message: {
                        userName: userName,
                        userId: userId,
                        entityName: entityName,
                        entityId: entityId,
                        operation: FormState.UPDATE,
                        uuid: notifications.uuid
                    }
                });
            });
        }
});

Here is what the form displays when another user has opened the same record.

 

Here is what that form displays when another user has made changes and saved the record.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s