Sticky

This blog has moved to www.dreamingincrm.com. Please update your feed Url. Thank you.

24 April 2014

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.

/// 
(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.
/// 
define(['pubnub'], function(PUBNUB) {
        var pubnub = PUBNUB.secure({
            publish_key: '<PUBLISH KEY>',
            subscribe_key: '<SUBSCRIBE KEY>',
            ssl: true,
            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.



No comments:

Post a Comment