Hi Jivers,

Recently we had a requirement from group admins to enable them to add user's as email followers to a group (associate group with user's email enabled stream so that they receive communication in gmail).

We had this admin essential add-on by Ryan Rutan which allowed us to add user as member, not as a email follower though.

We could extend this add-on to fit our requirements. And also could utilize system webhooks to enhance this.

 

 

The customization and google groups

We have google groups integrated with jive using custom streamonce. What this means is we have a two way sync between jive and google groups.

People can now start discussion on jive or google group and it reaches people living in both jive and gmail world.

 

Now jive has its own email notification system and email preferences.

Due to the integration we wanted the email prefs in sync between google and jive.

When a user joins a jive group as member, he starts following group in Connections, which by default is not email enabled.

People have to either enable email for this stream or create a new email enabled stream and follow group in that stream to get emails.

Complex. We simplified this for our users.

 

Our Approach: An email enabled stream for all users

 

First we decided to create an email enabled stream for all existing users and also for every new user account using webhooks.

And then if user followed a group in this (or any other) email enabled stream, he gets added to the corresponding google group.

If he unfollows group from email enabled stream, then he gets removed from the google group.

 

If he follows/un-follows a group from an non email enabled stream, nothing happens on google group.

Our java plugin has the google logic right now which will be moved to add-on soon.

 

Jive's system webhooks notifies about every new user account created/enabled on jive.

I used this trigger to create a new email stream.

 

Webhooks based logic

Before getting into changes to Ryan's app, here's what I did with webhooks initially

 

Create the example webhook by running command "jive-sdk create example-webhooks".

In this example go to explicit_routes.js in folder services-->webhooks-->backend-->routes.

In exports.postWebhooks check forr following activity

 

if(activity['verb'] === "jive:user_account_created" || activity['verb'] === "jive:user_account_enabled"){.....}

 

This event gives me api url for the new user account created.

var api_url = activity['object']['id'].

Now is the time to create new stream.

 

var postRequest = {
            'authz': "signed",
            url: api_url+"/streams",
            method:'POST',
            'auth': env.auth,
            body:'{"name":"Email Watches","source":"custom","receiveEmails":"true"}'
        };

var request = require('request');
request(postRequest, function (error, response, body){......});

I used this same api call to create stream for existing users too.

 

Associating group with user's Email watches stream

You all would have already check Ryan Rutan's admin essential add-on available at jiveapps/addons/admin-essentials at master · jivesoftware/jiveapps · GitHub.

 

Check method clickPickerAddMembers() in  group-addmembers.js in this code.

The method looks like this

 

clickPickerAddMembers : function() {
        var appObj = this;
        var batchRequests = osapi.newBatch();

        $("div.selected-user span.userid").each(function( index ) {
            batchRequests.add(
                $(this).attr("pos"),
                appObj.currentCtx.createMember({
                    "person" : $(this).text(),
                    "state" : "member"
                },
                {
                    "fields" : "username"
                }
                )
            );
        });

        batchRequests.execute(appObj.handlePickerAddMembers);
    },

 

This adds user as member in the group.

This is where I changed the logic

 

Here is my method which uses jive's connects api to call my node service

 

 

clickPickerAddMembers : function() {
        var appObj = this;

        var batchRequests = osapi.newBatch();
        $("div.selected-user span.userid").each(function( index ) {
            batchRequests.add(
                $(this).attr("pos"),
                osapi.jive.connects.post({
                    authz:"signed",
                    alias: "forceAddUserService",
                    headers : { "Content-Type" : "application/json" },
                    format: 'json',
                    "body": {"groupid": $("#currentGroup").attr("data-groupid") ,"userid":$(this).text()}
                })
            );
        });

        batchRequests.execute(appObj.handlePickerAddMembers);
    },

Now my node.js service has a route to accept this request params groupid and userid.

Using webhooks code I already have Email watches for every user (a user might decide to delete this though which my app detects and notifies about).

 

Now that the control is on my node.js service. I use jive REST api do following stuff :

  • Add user to the group as member (this is what Ryan's app was doing using javascript api)'
  • Checking if user has the email enabled email watches stream.
  • Associating the group with user's email watches stream
  • The email stream association event triggers our custom plugin which add's user to google group. I am in process of moving that part to jive add-on.

 

Post request for user membership to group

 

var addMemberRequest = {
            'authz': "signed",
            url: 'jive_url/api/core/v3/members/places/"+groupid,
            method:'POST',
            'auth': env.auth,
            body:'{"person":"jive_url/api/core/v3/people/"+userid,","state" : "member"}'
        };

 

Post request for associating group with email stream

First we need to find the Email Watches stream for the user.

We get all stream of users using this get request and find the streamid for email watches

 

var getRequest = {
            'authz': "signed",
            url:'ive_url/api/core/v3/people'+userid+'streams'',
            method:'GET',
            'auth': env.auth
        };

 

And the the post request to associate group with stream

 

var associationRequest = {
            'authz': "signed",
            url: 'jive_url/api/core/v3/streams/'+streamId+'/associations',
            method:'POST',
            'auth': env.auth,
            body:'["' + jive_url/api/core/v3/places/'+placeId + '"]'
        };

At this  point right now our plugin gets triggered which adds user to corresponding google group.

This same plugin also takes care to adding/removing user from google group when that users follows/unfollows corresponding jive group in an email enabled stream.

We are in process of moving that to add-on.

 

Thats all what my extended version of Ryan Rutan's add-on does.

 

Going back to client side from where the request to my server is made.

We had to move this app from path "jive/settings/places/group" to "jive/actions/places/group" so that its easy to access for users.

Unfortunately there is no way to restrict app link to admins/super admins.

So I wrote some client side logic to achieve this.

I wrote some promises to get current groupID, current user's ID, group's admin and super admin.

 

I would like to share the simple jquery promises (I know Q is better) i wrote for this.

Here are the promises:

 

var jivePromises = {
    isSuperAdmin : function(){
        var adminPromise = $.Deferred();
        osapi.jive.corev3.securityGroups.get({"id": "1001"}).execute(function(data){
            if(data.status != '403' && data.type && data.type.toUpperCase() == 'SECURITYGROUP'){
                adminPromise.resolve(true);
            } else {
                adminPromise.reject(false);
            }
        });
        return adminPromise
    },
    getGroupAdmins: function(group){
        var groupAdminPromise = $.Deferred();
        group.getMembers({"state":"owner"}).execute(
            function (groupAdmins) {
                groupAdminPromise.resolve(groupAdmins);
            },
            function(error){
                groupAdminPromise.reject(error);
            }
        );
        return groupAdminPromise;
    },
    getGroup: function(groupId){
        var groupPromise = $.Deferred();
        osapi.jive.corev3.places.get({ entityDescriptor: 700 + "," + groupId }).execute(
            function(response) {
                groupPromise.resolve(response.list[0]);
            },
            function(error){
                groupPromise.reject(error);
            }
        );
        return groupPromise;
    },
   getCurrentUser:function(){
        var currentUserPromise = $.Deferred();
        osapi.people.getViewer().execute(
            function (currentUser) {
                currentUserPromise.resolve(currentUser.id);
            },
            function(error) {
                currentUserPromise.reject(error);
            }
        );
        return currentUserPromise;
    }
}

Thats all. One more nice example of what node.js based jive add-on can do.