Monday, October 26, 2015

Programmatically embed a Yammer feed into a SharePoint Online site

In this post I will show how to use JavaScript and the Yammer SDK for easily embedding a Yammer feed into a SharePoint Online team site.








I will show 2 different approaches and will explain the pros and the cons of each :

- the first approach is the Yammer Embed and is a good initiation to the topic
- the second uses more advanced knowledge regarding the Yammer SDK

1 - Regarding environments
I have also to write something regarding the available environements for testing. Either you have a Yammer available at your company or at your client place, or you have to mount your own environmement (that I did). The important thing is to log to Yammer with an account that is not an external account. Programming with the SDK doesn't work for external accounts any longer since 2015.
Thus, don't think to make this tutorial work by using a trial version of SharePoint Online and a Yammer you can access with an external account. It won't work. (Except for Yammer embed).

If you want to mount a trail environment as I did, you need to subscibe to the Office 365 Enterprise E3 trial offer that is the only one which with you can get Yammer. But be careful. To make SharePoint Online and Yammer works properly with this Office 365 Enterprise E3 trial offer you will have to buy a Domain.

- Here is the part of the Yammer activation guide that explains how to add a company Domain for your Office 365 environment.

- And the Yammer Activation Guide FAQ


2 - The Yammer Embed approach

You will find a lot of post explaining how to add a Yammer Embed to a SharePoint Online page. Here is the official documentation of Microsoft that is also announcing that the Yammer App for SharePoint 2013 will be discontinued and will stop working on September 15th, 2015. Yammer Embed will be our single solution to integrate Yammer feeds into SharePoint.

Yammer Embed is limited. As it is displaying the feed within an Iframe, it is not so easy to customize the feed as you should want, for example change the styles, the fonts size, the font family, color, etc.
However, there is some parameters you can add to the code to modify the way Yammer Embed is displaying. I will illustrate that with and example. Look at a page with the Yammer Embed on it:



You will notice that the header is showing the Domain I had to buy to mount my Office 365 Enterprise E3 trial environment. Assume you want to hide this header. For doing that you have to add to the Yammer Embed code the following instruction:

config :{
header: false
}

Here is the Yammer embed code after having done that :

<script type="text/javascript" src="https://assets.yammer.com/assets/platform_embed.js"></script>
<script type="text/javascript"> yam.connect.embedFeed({
container: "#embedded-feed",
network: "marccharmois.com",
feedType: "group",
feedId: "6574317",
config :{
header: false
}
});
</script>

...and the result...



That gives you already a good idea about the way you can give instructions to Yammer by using the JavaScript SDK. It is like working on fragments of JQuery Ajax request .

3 - The Yammer JavaScript SDK and REST API approcah

Now is the time to examine a more powerful approach that allows you embed a Yammer feed into a SharePoint page while being able to customize things the way you want. For example, in a next post, I will show how to post a message to Yammer from SharePoint Online. When I will have such a feature I won't need the "What are you working on?" input zone any longer. So I have to find a way to embed my Yammer feed without using Yammer Embed to hide this zone.

3.1 Creating a Yammer App

To program for Yammer using the SDK and the REST API, first you have to create a Yammer APP. The Yammer APP will:
  • provide you with a Client Id that you will use in your SharePoint page code.
  • register your SharePoint page within Yamer to avoid the problem of cross-domain requests (CORS), because, even in an Office 365 integrated environment, you will notice that the SharePoint Online hostheader, and the Yammer hostheader are different . For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. Thus you cannot request the Yammer Web Services from a SharePoint Online page using client side code and XMLHTTPRequest. However, using a Yammr App will allow you to do that using the Yammer SDK.

So, let's create the Yammer App. Go to Yammer and locate the APPS menu and click it.



You land on the Apps Directory page. Locate the "My Apps" button and click on it.



You land on the "Registered Applications" page. Here you can click the "Register New App" button to create your Yammer App.



The registration Form is displaying.



Here is an explaination regarding the settings:

  • Application Name : chose an explicit name. In my case, it is a Yammer App to display a Yammer feed into a SharePoint Online Page.
  • Organisation : the one of your Office 365 environment
  • Website : the website that will host the page with the new App information (Client ID) for requesting the Yammer REST API. In my case, https://contososoftware.sharepoint.com/sites/intranet
  • Redirect Url : the website that will host the page with the new App information (Client ID) for requesting the Yammer REST API + "/oauth/callback". In my case : https://contososoftware.sharepoint.com/sites/intranet/oauth/callback

Then, click on the "continue" button for creating the new Yammer App, but it is not finished yet. An important thing to do is to define the JavaScript Origin for the New Yammer App. This is one of the important settings that is needed by Yammer to manage the concern of the HTTP Access Control (CORS). Roughly explained: Yammer needs to know the domain that will request its REST API using the client side code of a web page to tell the browser that a cross domain request is permitted.
So, when your Yammer App is created, click on its name to open the page gathering its informations and settings.



You will notice that one of the informations is the client ID that you will have to reference within the code of your web page when programming.



Then, click the "Basic Info" link in the left menu. On the opening page, locate the "JavaScript Origin" input area, and type domain of the SharePoint Online site that will host the page that will request the Yammer RET API client side. In my case https://contososoftware.sharepoint.com



When all this is done, we can start programming the SharePoint page...


3.2 Programming the SharePoint page for displaying the custom Yammer feed

Now we are going to create the web page that will request the Yammer REST API. It will be a simple html page. When this page will be programmed, displaying the Yammer feed, we will display the custom yammer feed in a SharePoint Web Part page using an Iframe.
So let's create the yammer-app.html page.

Go to SharePoint Online Intranet, navigate to the site contents, then to the "Site Assets" library. In the "Library" tab of the Ribbon locate the "open with explorer" Ribbon.



It takes a little time and you have sometimes two warning pop-ups to close until the explorer open and show the SharePoint files. You can then navigate up to the root folder of your intranet site. And you can create a new file (let's say a text document).



Then, you can rename the text document into "yammer-app.html".



And for programming the page you can open it with Notepad ++ or even Visual Studio.



You can find the complete code of the yammer-app.html page within the dedicated GitHub repositery, but here are the key points to understand the code:
  • First, load the Yammer SDK while passing your Yammer App Client ID

    <script> type="text/javascript" data-app-id="aMqiweJ1Co7RQJkHX6TFg" src="https://c64.assets-yammer.com/assets/platform_js_sdk.js"></script>

  • Second, you musn't call the Yammer web services directly using an Ajax request.
    You call the Yammer REST API with the "yam" object. Examples :

    triggering the authentication Pop-up if the user click the Yammer login button

    yam.connect.loginButton('#yammer-login', function (resp) {
    if (resp.authResponse) {
    //User is logged
    // do stuff
    }
    });

    calling Yammer to get the messages of a Yammer group

    yam.platform.request(
    {
    url: "https://api.yammer.com/api/v1/messages/in_group/6574317.json" //replace the group ID with your
    , method: "GET"
    ,success: function (data) {
    //process the Yammer feed data...
    },
    error: function (msg) { alert("error getMyFeed ajax : " + msg.value); }
    })

Last, when your yammer-app.html page is working properly, you have finally to display the custom Yammer feed via a script editor Web Part into a SharePoint Web Part Page, or a SharePoint page customized via an Iframe tag:

<iframe style="height:500px;overflow:visible;" scrolling="no" src="https://contososoftware.sharepoint.com/sites/intranet/yammerapp.html"></iframe>

Note

Note that the messages/in_group/6574317.json web service is maybe not the best one for displaying messages. I read some posts that tell it doesn't retrieve all the messages. It seems that this web service has been removed from the Yammer documentation. I let you go to the Yammer documentation and find the best web service for retrieving the messages depending on your needs...


4 - Regarding the Yammer authentication

It' seems there is a way to enable Single Sign On (SSO) from SharePoint Online to Yammer so as the users authenticated on SharePoint Online don't have to authenticate another time while wanting to access to Yammer.
I didn't try to enable the SSO yet on my trial environment, thus when a user of my environment land on the SharePoint page displaying the custom Yammer Embed feed, I have developped the presence of the Yammer Login Button.



For displaying the Yammer custom Embed feed, the user has to click the Yammer Login button, and has to authentify.



Then, the custom Yammer Embed feed is displaying.



In my environment, if the user is refeshing the page, he doesn't have to authentify again, but in my company and in my client Office 365 environments, when refreshing the page, the user HAS to authentify again.
There is a way to avoid this. You have to store the Yammer oauth token and reuse it when the page is refreshing.


4.1 Storing the Yammer oauth token to reuse it

When the user is authentified you store the token in the localStorage property that is compliant with most of the browsers. It is an amazing way to simulate the session variables.
yam.connect.loginButton('#yammer-login', function (resp) {
            if (resp.authResponse) {
        
              localStorage.setItem(1, JSON.stringify(resp.access_token.token).replace(/"/g, ""));
              console.log("token" + localStorage.getItem(1));
              //Hiding the login button because the user is logged in
              document.getElementById('yammer-login').style.display = 'none';
            }
          });
        

Now, when the page is refreshing, there is a way to test if the user is logged or not using the JavaScript SDK of Yammer:

yam.getLoginStatus( function(response) {
                    if (response.authResponse) {
                       //user is logged in
                       //nothing to do
                        
                    } else {
                       //check if a oauth token is stored for this user
                       //if yes,
                       //reload the custom Yammer Embed feed and use the oauth token stored in local storage to authentify the request 
                    }
                });
        

Finally, here is the correct syntax to pass the bearer token to yammer while loading a feed usinf the JavaScript SDK:

function getMyYammerFeed(){
        document.getElementById("yammer-feed").innerHTML="<img src='/sites/portail-dircom/PublishingImages/ajax-loader1.gif' style='margin-top:100px;margin-left:95px;' />";
        var tokenToSend = "Bearer " + localStorage.getItem(1);
        console.log("authorization bearer : " + tokenToSend);
        yam.platform.request(
           { 
              url: "https://api.yammer.com/api/v1/messages/in_group/6572783.json" 
           ,method: "GET"
           ,beforeSend: function (xhr){xhr.setRequestHeader('Authorization', tokenToSend)}
              ,success: function (data) { 
                 try{
                      //process the feed datas
             }catch(error){alert("error getMyFeed process : " + error); }
         },
              error: function (msg) { alert("error getMyFeed ajax : " + msg.value); }
            }
          )
        }
        



6 comments:

Paul_dH said...

Hi Marc,

Thanks for your yous solution, I have a question though. Is it possible to get in contact with you? My skills with html and css are good but Javascript is a bit a challenge. If I can get the page to work would be great, I'll do the styling afterwards.

Hope to hear!

Regards, Paul

Marc Charmois said...

Hi Paul,

thank you for your comment!
ask for any question you have. I will manage to answer.

Marc

ottoh said...

Hello Mr Marc
nice to see your post, very helpfully

but, i have a question when i try request to https://www.yammer.com/api/v1/messages/algo.json?limit=5&threaded%3D[true%20%7C%20extended]=true it doesnt work

but when i request to https://api.yammer.com/api/v1/messages/686885553.json its perfectly work. can you help me Mr.March?

please reply my question at Ottohhidayatullah@gmail.com

Thanks
Regard, Ottoh

Marc Charmois said...

Hi Ottoh,

it is all the difficulty with the Yammer API, some urls work some other don't. I did the same as you, I tested and kept only the stuff that works. You have to do this work since there is not a lot of documentation onto the topic and that's why I did this post.
Furthermore, the Office 365 products API is now changing and we should now use Graph for requesting on the Office 365 Web Services.
I suggest you to read my post where I used the Graph preview to request onto the Outlook API.

Cheers,

Marc

Unknown said...

Hi Mark,

still can't figure out how to make this work...could you perhaps explain how to make this piece work?:

yam.getLoginStatus( function(response) {
if (response.authResponse) {
//user is logged in
//nothing to do

} else {
//check if a oauth token is stored for this user
//if yes,
//reload the custom Yammer Embed feed and use the oauth token stored in local storage to authentify the request
}
});

The code doesn't seem to store the token in local storage no matter what I do...

Thanks

Kiran said...

Will the above embed code work for mobile apps developed in cordova?
Can you please share the documentation to make it work?