Skip navigation

Hello Jive Devs,

 

Today we launched a new web tool for creating an OAuth 2.0 clients for your Jive instance. Previously, your options were to use the Node.JS Jive-SDK or build the add-on from scratch, well this tool allows for greater customization in your zip in fewer steps. You simply need to enter a redirect URL in the field and give your add-on a title, description, and square icon (it will be resized automatically into 3 separate sizes). Try it out, get some tokens and build your next add-on with secure REST API calls: OAuth 2.0 Client Builder - Jive Developers

 

Screen Shot 2015-10-07 at 1.17.56 PM.png

 

We've also updated some of our old documentation to provide one resource for your Jive OAuth2 questions: OAuth 2.0—Creating a Client and Managing Access

 

Hope you find the tool useful. Post your feedback, suggestions, questions in the comments below!

 

 

//Rashed

Introduction

sfdc-report-wide-upgrade2.pngIn this example we're going to walk through how to build a tile in Jive that displays data from a Salesforce report. We'll use a custom view tile to be able to fully control the user interface, and we'll configure the tile with external data provider option to use data sent from our add-on integration service. For background info on custom view tiles, check out Creating Custom View Tiles.

 

The diagram below shows main components of this integration and screenshot on right shows the tile with data from a sample report in Salesforce developer instance.

sfdc-report-tile-arch.001.png

When using external data provider option, the add-on service can periodically query report data and send that to Jive to be available for tile rendering. This means each time a tile is displayed, it is rendered using latest data sent to Jive and no requests are made to the add-on service.

 


 

Getting started

To get us started off, you'll first need to have the following ready:

 

Download Sample on GitHub

Download the sample project at: https://github.com/jivesoftware/sfdc-report-tile

 

Installing Salesforce API Key

To get access to Salesforce API, go to your Salesforce developer account and configure the integration at Setup, Create, Apps, and use OAuth scope settings from screenshot below. The callback URL needs to point to the OAuth endpoint on your Node.JS/Jive-SDK add-on service.

 

Here's how to access the Setup menu

Screen Shot 2015-10-06 at 14.04.22.png

 

Here are the OAuth settings

sfdc-report-oauth-app.png

 

The Consumer key and secret from Salesforce app definition are set in /jiveclientconfiguration.json

"oauth2-sfdc": {

  "originServerAuthorizationUrl": "https://login.salesforce.com/services/oauth2/authorize",

  "originServerTokenRequestUrl": "https://login.salesforce.com/services/oauth2/token",

  "clientOAuth2CallbackUrl": "http://localhost:8090/oauth/oauth2Callback",

  "oauth2ConsumerKey": "3MVG9y6x0357Hlee8TDL6y5tOH95AsjUFac6us6C.8e0KncuDmapBf6UaRVA._.xKjlMw_0HA80SXGIi6Frvq",

  "oauth2ConsumerSecret": ""

}

 


 

Tile setup

The sample project has two tile definitions, one for wide tile layout slot and one for narrow. We use two definitions only to detect layout slot type for display handling and actual tile implementation is all under sfdc-report-wide tile. Here is the definition for the wide tile, see tiles/sfdc-report-wide/definition.json:

{

    "config": "/sfdc-report-wide/config?type=wide",

    "displayName": "Salesforce Report Wide",

    "name": "sfdc-report-wide",

    "style": "CUSTOM_VIEW",

    "displayWidth": "WIDE",

    "view": "/sfdc-report-wide/view?type=wide",

    "action": "/sfdc-report-wide/action?type=wide",

    "dataProviderKey": "external",

...

}

The field "style":"CUSTOM_VIEW" defines that tile is rendered with HTML from "view" endpoint, and "dataProviderKey":"external" means that data push from external add-on service is provided to the tile javascript startup function.

 

Tile Configuration

When configuring the tile, user will login to Salesforce and grant API access for this app according to standard OAuth 2.0 web server authentication flow, resulting in a token used to make Salesforce API calls. To accomplish this our add-on needs to implement an OAuth Client, which is done by including "oauth2client.js" in your configuration page and calling OAuth2ServerFlow() on page load. Note that oauth2client.js is provided by the Jive-SDK and is not included as a file in the sample project.

 

/tiles/sfdc-report-wide/public/config.html

<script src="/javascripts/oauth2client.js"></script>

...

<button type="button" id="grant-button">Grant Access</button>

 

/tiles/sfdc-report-wide/public/javascripts/config.js

$(document).ready( function() {

  var options = {

    grantDOMElementID: '#grant-button',

    authorizeUrl: '/oauth/authorizeUrl',

    ...

  };

  OAuth2ServerFlow( options ).launch();

});

 

 

OAuth Configuration

OAuth2ServerFlow function defines a callback for the button defined with grantDOMElementID option, and when clicked, initiates the authentication flow with Salesforce.

sfdc-report-config-oauth-grant.png

The authorizeUrl option points to an endpoint on your add-on service that handles communication and token storage. This is implemented by extending OAuth util class from the Jive-SDK.

 

/services/sampleOauth.js

var jive = require('jive-sdk');

var oauthUtil = jive.util.oauth;

var tokenStore = jive.service.persistence();

 

// overrides jive-sdk/routes/oauth.js to store access token

var myOauth = Object.create(jive.service.routes.oauth);

module.exports = myOauth;

 

myOauth.fetchOAuth2Conf = function() {

    return jive.service.options['oauth2-sfdc'];

};

 

myOauth.oauth2SuccessCallback = function( state, originServerAccessTokenResponse, callback ) {

    var content = originServerAccessTokenResponse['entity'];

    tokenStore.save('tokens', state['viewerID'], {

        ticket : state['viewerID'],

        accessToken: content['access_token'],

        refreshToken: content['refresh_token'],

        instanceUrl: content['instance_url']

    })

    .then( function() {

        callback({'ticket': state['viewerID'] });

    });

};

 

myOauth.getTokenStore = function() {

    return tokenStore;

};

 

When user has completed the OAuth flow, configuration page uses add-on service endpoints to get recently selected reports, and to search for reports. User interface controls were implemented with JQuery UI Dialog and Autocomplete.

Screen+Shot+2015-08-24+at+11.42.28.png

 

Selecting a report

The config page uses JQuery autocomplete to display results for searched reports. Results are retrieved with a call to osapi.http.get() which proxies the call via Jive server, and targets an endpoint on add-on service.

 

/tiles/sfdc-report-wide/public/javascripts/config.js

osapi.http.get({

  'href': SERVICE_BASE_URL + '/sfdc-report-wide/search?' +

          'ticketId=' + ticketId +

          '&term=' + encodeURIComponent(searchTerm),

  'format': 'json',

  'authz': 'signed'

}).execute(function( response ) {

  ... show search results

})

 

Implementing the search endpoint route on server

/tiles/sfdc-report-wide/backend/routes/search/get.js

exports.search_route = function (req, res) {

  var url_parts = url.parse(req.url, true);

  var queryPart = url_parts.query;

  var term = queryPart["term"];

  var ticketId = queryPart["ticketId"];

 

  sfdc.getReportsBySearchTerm(term, ticketId)

  .then(function (entity) {

    // success response

  }).catch(function (err) {

    // error

  });

};

 

See next section for details on how getReportsBySearchTerm function is implemented.

 

When user has selected a report, and clicks apply to save tile configuration, the page saves report ID, name and instance URL from Salesforce with a call to jive.tile.close(). This triggers Jive to register the tile instance with add-on service with the provided configuration.

 

/tiles/sfdc-report-wide/public/javascripts/config.js

$("#configure").click(function() {

  ...

  jive.tile.close({

    reportId: reportId,

    reportName: reportName,

    instanceUrl: sfdcInstanceUrl,

    ticketId: ticketId

  });

});

 


 

Getting report data

 

Using Salesforce API

When querying for data, the ticket id from tile instance configuration is used to find OAuth token from data storage, and then Salesforce Reporting API  is used to get report data. OAuth token is sent in Authorization header of each request and error response codes are handled to refresh the token and detect if a report has been removed from Salesforce (see the full code sample for this error handling).

 

/services/sfdc-client.js

var API_PATH = '/services/data/v33.0';

 

exports.getReport = function(reportId, ticketId) {

    return doGet("/analytics/reports/" + reportId + "?includeDetails=true", ticketId)

    .then( function(response) {

        return response.entity;

    });

};

...

function doGet(uri, ticketID) {

    var tokenData;

    return getAuthToken(ticketID)

    .then(function(found) {

        if (found) {

            tokenData = found;

            var headers = {'Authorization': 'Bearer ' + found.accessToken};

            return jive.util.buildRequest(found.instanceUrl + API_PATH + uri, 'GET', null, headers, null);

        }

    });

}

 

In a similar way, Salesforce Query API is used to search for reports based on name.

exports.getReportsBySearchTerm = function(term, ticketId) {

    var query = "select Id, Name, Format from Report where Name like '%" + term + "%' limit 50";

    return doQuery(query, ticketId)

    .then( function(entity) {

        return entity;

    })

};

...

function doQuery(query, ticketId) {

    return doGet("/query?q=" + encodeURIComponent(query), ticketId)

    .then( function(response) {

        return response.entity;

    });

}

 

Sending data to tile

The add-on service will periodically query for Salesforce report data, and send it to Jive for each registered tile. This is done by registering a task with jive.tasks.build() which will be executed by jive-sdk at specified interval. Data is set to Jive with jive.tiles.pushData() function and will then be stored by Jive and will be available when rendering tile.

 

/sfdc-report-wide/backend/services.js

exports.task = new jive.tasks.build(

    function() {

        jive.tiles.findByDefinitionName( 'sfdc-report-wide' ).then( function(instances) {

            instances.forEach( function( instance ) {

                exports.processTileInstance(instance);

            });

        });

    },

    120*60*1000 // 2hr interval

);

...

exports.processTileInstance = function(instance) {

    var reportData;

    var cfg = instance.config;

 

    sfdc.getReport(cfg.reportId, cfg.ticketId)

    .then(function(data) {

        reportData = data;

        return sfdc.getReportProperties(cfg.reportId, cfg.ticketId);

    })

    .then(function(properties) {

        var tileData = {

            title: reportData.reportMetadata.name,

            detailColumnInfo: [],

            groupingColumnInfo: [],

            groupingsDown: reportData.groupingsDown.groupings,

            aggregates: reportData.reportMetadata.aggregates,

            contents: reportData.factMap,

            ...

        };

        .... report data processing

        return jive.tiles.pushData(instance, {data: tileData});

    })

};

 

Salesforce report "fact map" data values are passed here as-is to the tile, but the data payload could be completely custom. Grouping info and aggregate data for summary reports are also sent for rendering groups in tile grid. Metadata about each column containing display label and data type is saved into detailColumnInfo field.

 

Rendering tile

When tile is rendered Jive gets the html page from "view" endpoint defined in tile's definition.json. The page javascript gets latest data push in jive.tile.onOpen() handler and renders it using jqGrid. Tabular report data rows are simply passed to jqGrid for display, but summary reports also require handling of groupings and aggregate values.

 

/tiles/sfdc-report-wide/public/javascripts/view.js

jive.tile.onOpen(function(config, options) {

    var app = new ReportView(config);

    app.init();

});

...

function ReportView(data) {

    this.data = data;

}

...

ReportView.prototype.init = function() {

  var gridOptions = {

    datatype: 'local',

  };

  ...

  if (this.data.type == "TABULAR") {

    $.each(this.data.contents['T!T'].rows, function (n, row) {

      // ...add data rows to grid

    });

  }

  else if (this.data.type == "SUMMARY") {

    gridOptions.grouping = true;

    // ...define summary groupings and aggregates for jqGrid

  }

  ...

  $("#grid").jqGrid(gridOptions);

}

 


 

What's Next?

This fall, we'd released a new update to the Jive Cloud platform (2015.3) and along with that comes a couple of great new features and updates to our REST API. We also brought a couple of new posts and tools to make your integrations richer, built easier and faster than ever before. We did a lot of tidying up with this release and squashed quite a few bugs while we're working hard on the next major release that's sure to completely WOW you—release 2016.1.

 

REST API Improvements

Jive REST API v3.13 → Moderation & Abuse - Get a count of pending moderation items (added)

Jive REST API v3.13 → Content Service - View content that's flagged as featured (added)

Jive REST API v3.13 → Person Service - Get profile field privacy of users (added)

Jive REST API v3.13 → Person Service - Endpoints for CRUD and sorting of profile fields (added)

Jive REST API v3.13 → Video Service - Cleaned up to a canonical package (updated)

Jive REST API v3.13 → Content Service - Resize capabilities to /previewImage API (updated)

 

 

New Documentation & Posts

Deploying Jive SDK Node.JS Solutions with JXcore

Creating a Twitter Widget Custom View Tile with Configuration

Ngrok: Warp Speed for Your Integration Iterations

Dev Tool: Using the Simple Stream Integration Builder with StatusPage.io (1 of 3)

Dev Tool: Build an App w/ the Simple Stream Integration Builder (2 of 3)

Dev Tool: Simple Stream App with Bi-Directional Communication (3 of 3)

 

 

Stay tuned for more news and updates on our next release and keep yourself checking the Jive Developer community often on new guides, documents, blogs, and great support!

 

 

Reminder

Want to Speak at JiveWorld16 Developer Conference?

Las Vegas - Aria Resort & Casino

March 14-16, 2016

 

 

If you've built a Custom View Tile or Simple Stream Integration that you're really proud of and want the chance to talk about it and how you did it to an audience of developers at JiveWorld16, this might be your chance! Go to this thread and see if you're eligible to speak and get a free pass!

 

Hello JiveMinds,

 

       We have come up with some solution for the ideas mentioned in the https://community.jivesoftware.com/ideas/4183 post. The solution that we have designed contains:

1. Bulk Content Move

2. Bulk Content Deletion

3. Bulk Apply Tags

4. Bulk Apply Categories

The app is called 'Content Manager'

 

        The idea came up as we were getting requests for getting some way to perform multiple operations like moving the content/s, deleting in bulk as deleting content one by one is tedious. Plus categorising content with specific categories and tags makes easy to search and manage. To facilitate the common platform for doing all these operations, we came with a solution - Content Manager.

        I will explain the features that we have developed so that it will easy to understand the functionality and use case.

 

 

All about app:

This app is being designed for groups and spaces meaning it will appear on Group's/Space's tab section.

Before doing any operation user need to select the content and for that we have designed the tabular format to ease up the selection process, it includes:

Content Types: As you can see, the table contains content of various types. But if user wants to perform specific operation on specific content, he/she can select the content type from the 'Content Types Dropdown'

Screen Shot 2015-09-29 at 10.11.19 pm.png

 

 

 

Show All/Owned Content: There can be situation where user wants to apply metadata or update the contents that are owned by him/her. In that case user can select the Show only my content else can continue with show all content otherwise.

Screen Shot 2015-09-29 at 10.15.56 pm.png

 

 

 

Filtering Criteria: The user can filter out the content based on various parameters like Last activity, Created first etc.

Screen Shot 2015-09-29 at 10.19.11 pm.png

 

 

 

 

Features:

1. Bulk Content Move:

  This feature transfers the selected content from source group to selected destination group.

Steps followed to perform the same operation:

1. Select the content to be moved from the table

2. Select the target place from the place picker that will be invoked once you click on move content icon.

3. Once the content and target place selected the conformation will be needed before proceeding :

Screen Shot 2015-09-29 at 10.23.57 pm.png

 

4. Once you confirm the move, the selected content will be moved to selected place. Following view will be displayed:

Screen Shot 2015-09-30 at 10.54.02 am.png

 

Selected content has been moved and highlighted with green. If at all for some reason, move fails the corresponding row will be highlighted in red colour with error message.

What do we do at the backend?

Screen Shot 2015-09-30 at 11.01.43 am.png

 

 

 

2. Bulk Content Deletion:

   This feature deletes the selected content.

Steps followed to perform the same operation:

1. Select the content to be deleted from the table

2. Once selected click on delete icon which would ask for deletion confirmation:

Screen Shot 2015-09-29 at 10.27.54 pm.png

 

3. Clicking on Delete button will delete the content.

What do we do at the backend?

Screen Shot 2015-09-30 at 11.03.22 am.png

 

 

 

 

3. Bulk Apply Tags:

       User can update the content by applying tags. This features suggests related tags to the entered tag once you enter 3 letters in the tag area.

Steps followed to perform the same operation:

1. Select the content to be updated with tags.

2. Click on tags icon which would show:

Screen Shot 2015-09-29 at 10.33.49 pm.png

 

3. Once the tags to be applied on the content, click on 'Add Tags' button.

What do we do at the backend?

Screen Shot 2015-09-30 at 11.04.24 am.png

 

 

 

4. Bulk Apply Categories:

     User can categorise content. This features displays categories available on the group.

Steps followed to perform the same operation:

1. Select the content to be updated with tags.

2. Click on categories icon which would show:

Screen Shot 2015-09-29 at 10.36.55 pm.png

 

3. Content will be updated with selected categories once 'Update Categories' button clicked.

What do we do at the backend?

Screen Shot 2015-09-30 at 11.05.37 am.png

 

 

 

 

 

This is the service side code snippet which does all magic (updating):

Screen Shot 2015-09-30 at 11.07.15 am.png

 

 

Access Levels:

   SuperAdmins: Super-admins have access to all the content of all the groups.

   Group Admins: Group Admins have access to all content to the group he owns.

   Normal User: Normal user will see only his content.

   Group Admins/Normal Users can move the content to the groups which they have access to.  

 

 

Logger:

  We have added logger to log all the operations which includes: operation done, group name, successIds, failureIds, User Id, Time etc

 

 

 

Code structure:

Screen Shot 2015-10-01 at 4.20.51 pm.png

 

                  As you can see in above image, the app is divided into various features. ContentManager is the parent class and other classes define the various features. We have added helper classes which take care of validation or views. JiveWrapper is the wrapper written over jive core apis, which helps to use them in customised manner.

 

This is how we have designed the app.

Please find the code under : siddharthadeshpande89/jive-content-manager · GitHub

This is an open source version licensed under AGPL.

Filter Blog