Monday, December 9, 2013

Custom action to a callout in SharePoint 2013


During my POC, I was trying to add custom action to a callout same like, Share and follow.found easy way to do it with following script.

 SP.SOD.executeFunc("callout.js", "Callout", function () {  
  var itemCtx = {};  
  itemCtx.Templates = {};  
  itemCtx.BaseViewID = 'Callout';  
  // Define the list template type  
  itemCtx.ListTemplateType = 101;  
  itemCtx.Templates.Footer = function (itemCtx) {  
    
   return CalloutRenderFooterTemplate(itemCtx, AddCustomAction, true);  
  };  
  SPClientTemplates.TemplateManager.RegisterTemplateOverrides(itemCtx);  
 });  
 function AddCustomAction (renderCtx, calloutActionMenu) {     
  // Add custom action  
  calloutActionMenu.addAction (new CalloutAction ({  
   text: "Custom Action",  
   tooltip: 'This is your custom action',  
   onClickCallback: function() { console.log('Alert from custom action'); }  
  }));  
 }  




We are good to go!!

Sunday, December 8, 2013

PowerShell to Cancel All SharePoint Workflows in Progress

I was struck with requirement were having big list and workflow attached to it, need to cancel all running workflows. 
It could be either manually traverse all the way and stop it, was next to impossible.
Following script helped me to save my time!


$web = Get-SPWeb "http://mysharepointserver.com/subsite";
$web.AllowUnsafeUpdates = $true;    

$list = $web.Lists["CustomListName"];
$count = 0

foreach ($listItem in $list.Items) 
{
 foreach ($workflow in $listItem.Workflows) 
 {
 
  if(($listItem.Workflows | where 
  {$_.InternalState -ne "Completed"}) -ne $null)
  {
   #Cancel Workflows        
   [Microsoft.SharePoint.Workflow.SPWorkflowManager]::
     CancelWorkflow($workflow);      
   write-output "Workflow cancelled for : 
     " $listItem.Title;  
  }
 }
}
$web.Dispose();
Hope this will save your time!

Monday, September 30, 2013

SP2013 : Task list not visible to other users

I came across weird issue, I created a task list with the system account.
This list is not able to view by any other users.
Spent enough time on finding a cause. It was all due to IE, it was working fine with Chrome and other browsers.

To make it work with IE:
1.  Active x and JS permissions has to be enabled.
2. The site has to be in the trusted pool of you internet explorer. 
3. Disable any extra add-ons.

Hope this small piece of information will save time

Wednesday, September 11, 2013

Create a custom view on Workflow Task Status

I came across to the requirement to create a custom view based on workflow status.

Requirement was to show all the approved items.


I found a interesting stuff, Filter will not work if we use words like below image:


we would need use the number rather than the words (e.g. 2 instead of In Progress, 4 instead of Cancelled etc)

Following list might help for this kind of requirement:

Status
Value
Not Started
0
Failed on Start
1

In Progress
2

Error Occurred
3

Canceled
4

Completed

5
Failed on Start (retrying)

6
Error Occurred (retrying)
7

Canceled
15

Approved
16

Rejected

17

Hope this will save your time!


Sunday, June 23, 2013

Provider Hosted App - Azure and Read, Write to SharePoint List with real example

Hi,

After my first blog on simple app,
http://anujabhojani.blogspot.in/2013/06/step-by-step-sharepoint-2013-provider.html

Now will go in detail about how to read and write SharePoint list with Provider Hosted App.

Here to cover all the scenario implementing it with real example by creatingvTrello App.

http://www.trello.com is basically a task management tool. I am developing app which will have following functionality,
1. App will take user token (oauth) from Trello to read all the cards  for current logged in user.
2. Trello will return token, which our app will store in one SharePoint list so next time when user visit the app, will get the token from list and directly get all the cards from trello.

Now, lets start and build this app.

1. Having Default.aspx in my solution, adding following code in page_load to get the access token


  1. public partial class Default : System.Web.UI.Page
  2. {
  3. public static string userToken = string.Empty;
  4. Uri appWeb;
  5. string myAccessToken;
  6. ClientContext clientContext;
  7. protected void Page_Load(object sender, EventArgs e)
  8. {
  9. if (!IsPostBack)
  10. {
  11. TokenHelper.TrustAllCertificates();
  12. var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);
  13. HttpCookie cookie = new HttpCookie("AccessToken");
  14. SharePointContextToken spContextToken = TokenHelper.ReadAndValidateContextToken(contextToken, Request.Url.Authority);
  15. appWeb = new Uri(Page.Request["SPHostUrl"]);
  16. myAccessToken = TokenHelper.GetAccessToken(spContextToken, appWeb.Authority).AccessToken;
  17. cookie.Value = myAccessToken;
  18. Response.Cookies.Add(cookie);
  19. ReadListItems(appWeb.ToString(), myAccessToken);
  20. }
  21. }

2.  Here in SharPoint site I have created one list named "usertoken", with UserName and Token, In ReadListItems will check the Trello token is present for current logged in user or not, if it will be there will get it directly and display the Trello cards assigned to Logged in user.
For Reading List item using REST API to get list items. 

  1. private void ReadListItems(string webUrl, string myAccessToken)
  2. {
  3. string oDataUrl = "/_api/Web/lists/getbytitle('UserToken')/items?$select=Token,UserName";
  4. var requestUrl = new Uri(string.Format("{0}{1}", webUrl, oDataUrl));
  5. HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUrl);
  6. Response.Write(webUrl.ToString() + oDataUrl);
  7. request.Method = "GET";
  8. request.Accept = "application/atom+xml";
  9. request.ContentType = "application/atom+xml;type=entry";
  10. request.Headers.Add("Authorization", "Bearer " + myAccessToken);
  11. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  12. XDocument oDataXML = XDocument.Load(response.GetResponseStream(), LoadOptions.None);
  13. XNamespace atom = "http://www.w3.org/2005/Atom";
  14. XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
  15. XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
  16. List<XElement> entries = oDataXML.Descendants(atom + "entry")
  17. .Elements(atom + "content")
  18. .Elements(m + "properties")
  19. .ToList();
  20. var entryFieldValues = from entry in entries
  21. select new
  22. {
  23. Token = entry.Element(d + "Token").Value,
  24. UserName = entry.Element(d + "UserName").Value
  25. };
  26. var itemCOllection = entryFieldValues.ToList();
  27. clientContext = TokenHelper.GetClientContextWithAccessToken(webUrl, myAccessToken);
  28. Web web = clientContext.Web;
  29. clientContext.Load(web);
  30. clientContext.ExecuteQuery();
  31. clientContext.Load(web.CurrentUser);
  32. clientContext.ExecuteQuery();
  33. var currentUser = clientContext.Web.CurrentUser.Title;
  34. for (int i = 0; i < itemCOllection.Count; i++)
  35. {
  36. Response.Write(itemCOllection[i].Token);
  37. if (itemCOllection[i].UserName == currentUser & itemCOllection[i].Token != string.Empty)
  38. {
  39. userToken = itemCOllection[i].Token.ToString();
  40. }
  41. }
  42. if (userToken == string.Empty)
  43. {
  44. Response.Redirect("https://trello.com/1/authorize?key=fd43232051021f33680eb2c6cf3125b3&name=TrellSharepoint&expiration=never&response_type=token&return_url=<SiteName>/Home.aspx?FromTrello=yes&Web=" + appWeb);
  45. }
  46. else
  47. {
  48. Response.Redirect("<SiteName>/Home.aspx?FromTrello=No&token=" + userToken);
  49. }
  50. }
3. Now as you see, we are moving to Home.aspx with Trello userToken if it will be there in list.
If not present in list will redirect to trello site and get authentication token from there,
In home.aspx we have to add script to get UserToken from trello return url.
 function GetUserToken() {
            var token;
            var url = document.location;
            var strippedUrl = url.toString().split("#");
            if (strippedUrl.length > 1) {
                self.location = strippedUrl[0] + "?" + strippedUrl[1];
            }
        }
will call this function on Body onload.

4. For reading trello cards, I have used Chello.dll which is .net wrapper for trello development.
Add reference of chello in solution.
  1. protected void Page_Load(object sender, EventArgs e)
  2. {
  3. if (Request.QueryString != null && Request.QueryString.Count > 0 && Request.QueryString.AllKeys.Contains("token"))
  4. {
  5. ChelloClient chelloClient = new ChelloClient(System.Configuration.ConfigurationManager.AppSettings["TrelloAppKey"], Request.QueryString["token"]);  
  6. IEnumerable<Board> boards = chelloClient.Boards.ForUser("my");
  7. boardGrid.DataSource = boards;
  8. boardGrid.DataBind(); 
  9. }
  10. if (Request.QueryString.AllKeys.Contains("FromTrello"))
  11. {
  12. var IsRedirectfromTrello = Request.QueryString["FromTrello"];
  13. if (IsRedirectfromTrello == "yes")
  14. {
  15. AddToken();
  16. }
  17. }
  18. }

This will display the boards available for current logged in user, And as you see I have took grid to bind it.  
  1. <ItemTemplate>
  2. <tr style="height:50px;">
  3. <td>
  4. <asp:LinkButton runat="server" ID="linkBoardName" Text="" CommandName="borad"><%#Eval("Name") %></asp:LinkButton></td>
  5. </tr>
  6. </ItemTemplate>
         

This will display the boards available for current logged in user, And as you see I have took grid to bind it.  
  1. <ItemTemplate>
  2. <tr style="height:50px;">
  3. <td>
  4. <asp:LinkButton runat="server" ID="linkBoardName" Text="" CommandName="borad"><%#Eval("Name") %></asp:LinkButton></td>
  5. </tr>
  6. </ItemTemplate>
            
5. Here in grid we are binding boards name into link button, and on button click having following code
  1. protected void boardGrid_ItemCommand(object sender, ListViewCommandEventArgs e)
  2. {
  3. if (e.CommandName == "borad")
  4. {
  5. LinkButton btn = e.CommandSource as LinkButton;
  6. ChelloClient chelloClient = new ChelloClient(System.Configuration.ConfigurationManager.AppSettings["TrelloAppKey"], Request.QueryString["token"]);
  7. IEnumerable<Chello.Core.List> list = chelloClient.Lists.ForBoard("513584cbf885e0711c0007fe");
  8. IEnumerable<Card> cards = chelloClient.Cards.ForBoard("513584cbf885e0711c0007fe");
  9. myListView.DataSource = list.Take(3);
  10. myListView.DataBind();
  11. ListView1.DataSource = cards.Where(t => t.IdList == list.First().Id);
  12. ListView1.DataBind();
  13. boardGrid.Visible = false;
  14. }
  15. } 
6. As in code I have took Listview to bind cards, Now its time to write Trello token back to list,
So next time when user come will not redirect to Trello site for getting user token. I am writing to SharePoint list by ClientContext to cover both the scenarios:
In page_load we have call AddToken(); 
  1. private void AddToken()
  2. {
  3. var appWeb = new Uri("<Siteurl>");
  4. HttpCookie cookie = new HttpCookie("AcessToken");
  5. cookie = Request.Cookies["AccessToken"];
  6. var myAccessToken = cookie.Value;  
  7. ClientContext clientContext = TokenHelper.GetClientContextWithAccessToken(appWeb.ToString(), myAccessToken);
  8. Web web = clientContext.Web;
  9. clientContext.Load(web);
  10. clientContext.ExecuteQuery();
  11. clientContext.Load(web.CurrentUser);
  12. clientContext.ExecuteQuery();
  13. var currentUser = clientContext.Web.CurrentUser.Title;
  14. Microsoft.SharePoint.Client.List oList = web.Lists.GetByTitle("UserToken");
  15. ListItemCreationInformation itemCreation = new ListItemCreationInformation();
  16. Microsoft.SharePoint.Client.ListItem listItem = oList.AddItem(itemCreation);
  17. listItem["UserName"] = currentUser;
  18. listItem["Token"] = Request.QueryString["token"];
  19. listItem.Update();
  20. clientContext.ExecuteQuery();
  21. }
We are done! Just publish the solutions and will get trello cards on our Azure hosted app.
While publishing I came across few bugs which resolved and described in following blogs which might be helpful :

http://anujabhojani.blogspot.in/2013/06/error-web-deployment-task-failed.html

http://anujabhojani.blogspot.in/2013/06/the-parameter-token-cannot-be-null-or.html

Happy Coding!

Wednesday, June 19, 2013

Step By Step- SharePoint 2013 Provider Hosted App - Azure Hosting

Here In this blog on SharePoint 2013 Provider hosted app will try to cover each and every steps to create provider hosted app.

1. Open Visual Studio 2012.



2. Click on New Project -> Select SharePoint template 


3. Visual studio will prompt to add Office 365 SharePoint Site you are using and select the Provider-hosted from dropdown list.



4.  On selection of Provide Hosted, click Next you will be prompted with following screen.
Select use a client secret option.



5. Now, Click on Finish. visual studio will take some time to prepare solution.



6. Solution has been created with two projects, looks like below image,


7.  App project will be deployed to SharePoint. And AppWeb project will be .Net Web Application. 


8. Now lets Deploy Provider-Hosted App to SharePoint.
 here, I am adding some sample test text in default.aspx as per below code,

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
   
<h2>First Azure Page.</h2>     </div>
    </form>
</body>
</html>

9.  Check the code behind of default.aspx contains code to get Accesstoken from TokenHelper.cs

10. Now,


11. Copy the App Id to AppManifest.xml file in your Visual Studio project. will look like below, you need to modify it by right click and view code.

<?xml version="1.0" encoding="utf-8" ?>

  <Properties>
    <Title>TestApp</Title>
    <StartPage>
http://anuja-bhojani.azurewebsites.net/Pages/Default.aspx?{StandardTokens}</StartPage>
  </Properties>
  <AppPrincipal>
    <RemoteWebApplication ClientId="f3bdddd6-65a1-5g89-acd5-655dddddd94c" />
  </AppPrincipal>
</App>

12. We have to add this to Web.config also.

<appSettings> 
  <add key="ClientId" value="f3bdddd6-65a1-5g89-acd5-655dddddd94c" />
 <add key="ClientSecret" value="damw+Svgx3K999556744332999zmmGmI1C6HKWWKbGU=" />
 
</appSettings>

13. Last step, need to give permission on App, Due to that we can interact with SharePoint. Please look the image below.


14. We are good to go now, Right click on app project -> Publish

15. Select Publish Profile from drop down, if not yet downloaded, click on import and from azure site download it.



16. Click Next, you will get automatically feel up ClientID and Secret, Just press Finish.


17. You will see Page where you need to click on "Trust App". Will redirect to azure site where will get our test message.

We are done with simple provider hosted app!

For the advance operation list read and write operation:
http://anujabhojani.blogspot.in/2013/06/provider-hosted-app-azure-and-read.html

Wednesday, June 12, 2013

Error: Web deployment task failed. .. User_UNAUTHORIZED - Provider Hosted App

During development of provider hosted app, while deployment I was greeted with error :

Web deployment task failed. (Connected to the remote computer ("waws-prod-hk1-001.publish.azurewebsites.windows.net") using the Web Management Service, but could not authorize. Make sure that you are using the correct user name and password, that the site you are connecting to exists, and that the credentials represent a user who has permissions to access the site.  Learn more at: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_USER_UNAUTHORIZED.)

After some research came to know need to download the Publish Profile from site and attached new publish profile, helps me to solve this issue.

It was due to changes in site happens are not detected in old publish profile, which leads to this error.

Hope this fix will save you time!


Tuesday, June 11, 2013

The option for the SharePoint 2013 workflow platform is not available because the workflow service is not configured on the server

Hi there,

I have configured SharePoint 2013 and Workflow Manager.
Created new Site Collection. However I was not able to create SharePoint 2013 workflows.
Option for"SharePoint 2013 Workflow" (but SharePoint 2010 workflows works).

Issue was, The site collection was created using blank template, which doesn't include all necessary dependency features for creating workflows.

Fix: we need to enable hidden feature WorkflowServiceStore using PowerShell.

Enable-SPFeature -Identity WorkflowServiceStore –Url $yourUrl

And finally I got option in SharePoint Designer:




Saturday, June 8, 2013

The parameter 'token' cannot be a null or empty string - Provider Hosted App SharePoint 2013

Hi,

Today while my research on SharePoint Provider hosted app with Azure, after deployment I was greeted with "The parameter 'token' cannot be a null or empty string ".
I was almost crazy behind finding the cause. However finally I found some points which leads me to resolve this error.

  • The ClientID in your AppManifest.xml and in your Web.Config should be same.
  • In AppManifest.xml file domain reference to Azure should be HTTPS rather than HTTP.
  • Should have proper permission on web,list,site collection according to your app.
  •   
    Happy coding!

    Thursday, May 23, 2013

    The form cannot be rendered. This may be due to a misconfiguration of the Microsoft SharePoint Server State Service. For more information, contact your server administrator

    Hi there,

    I was having a requirement to create SharePoint 2013 approval workflow using 2010 template. workflow was attached to content type.
    Issue I was facing, while going to start the workflow it gives error of "The form cannot be rendered. This may be due to a misconfiguration of the Microsoft SharePoint Server State Service. For more information, contact your server administrator"

    After some research came to find the solution,  this is related to state service as mentioned in error above.

    Paste following commands in SharePoint management shell:

     $serviceApp = New-SPStateServiceApplication -Name "State Service"  
     New-SPStateServiceDatabase -Name "StateServiceDatabase" -ServiceApplication $serviceApp  
     New-SPStateServiceApplicationProxy -Name "State Service" -ServiceApplication $serviceApp -DefaultProxyGroup  
    


    And now again I tried to start the workflow, and it started successfully!

    Thursday, May 16, 2013

    SharePoint 2013 Workflow error : Custom outcome column returns default option as a task result


    I was facing weird issue in SharePoint 2013 Designer workflow.
    Scenario was,
    I wanted to create one list workflow where custom list was created programmatically and having my custom workflow task list created through code as well custom content type and outcome columns also created programmatically.
    Now in workflow stage having an Assign task action and in Outcome options using the above created content type and site columns, see the figure below:


    Issue here I was facing, Task result was always showing "TaskOutcome:0" i.e the default Outcome in task inspite of I selected any another option.
    example in above figure result was always coming "Action Plan Created".

    Tried different approaches to make it work:

    -While debugging tried various options to make it work, like installed update http://support.microsoft.com/kb/2767999
    where it mentioned that
    "Assume that you use non-ASCII characters to name a task outcome field in a task in a custom workflow. Then, you change the default value in the task outcome field. In this situation, the task outcome field still displays the default value on the workflow status page."
    but no luck with this as well)

    - Tried to make the schema of custom outcome column same with SharePoint default TaskOutcome having however still same issue

    - Any many other options tried but no luck.

    After a week's debugging finally found the trick to solve this product bug.

    1. Create one global variable after the Assign task step.


    2. Set the global variable value to task outcome column explicitly.


    3. Mapped it with assigned task's TaskID variable.


    4. we are good to go, now we get the task outcome as a result which we select in task form.

    Happy coding!


    Monday, May 13, 2013

    Errors were found when compiling the workflow. The workflow files were saved but cannot run. - SharePoint 2013

    Today while trying to publish the workflow, came across the weird error
    "Errors were found when compiling the workflow. The workflow files were saved but cannot run."



    After digging into it, came to the solution that need to  Re-register service into my site using following commands:


    Register-SPWorkflowService -SPSite 'https://my-host/mysite' -WorkflowHostUri 'https://workflowhost' -AllowOAuthHttp -Force

    I reopened SharePoint Designer again and problem disappeared.

    Hope this will save your time.

    Wednesday, April 3, 2013

    Powershell To Attach workflow on Content Type and create Retention Policy on it - SharePoint 2013

    Hi Friends,

    I got a requirement to create retention policy on Content type and action is to start workflow. as well attach workflow to the content type.

    I choose to go with powershell.

    save the following code into file called SetupRetentionPolicy.ps1

    call like:

     c:\>.\SetupRetentionPolicy.ps1 -url <weburl> -ContentTypeName <Contenttype>  
    



     param(  
     $url=$null,  
     $ContentTypeName=$null)  
     $site = get-spsite $url  
     $web = $site.openweb()  
     Enable-SPFeature –identity "LocationBasedPolicy" -URL $url -ErrorAction SilentlyContinue  
     $Property = "Modified"  
     $Period = 1;  
     $PeriodType = "years"  
     function AddWorkflowToContentType($site, $ctName, $WfName, $WfAssociationName, $TaxTaskList)  
       {  
       [void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SharePoint')   
       [void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.Office.Policy')  
       [Guid]$wfTemplateId = New-Object Guid  
         $web = $site.RootWeb  
         $ct = $web.ContentTypes[$ctName]  
         $culture = New-Object System.Globalization.CultureInfo("en-US")  
         $template = $site.RootWeb.WorkflowTemplates.GetTemplateByName($WfName, $culture)  
         if($template -ne $null)  
         {              
         $tasklist = $TaxTaskList  
         $historylist = "IP Workflow History"  
       # Workflow Association with Content Type  
           $association = [Microsoft.SharePoint.Workflow.SPWorkflowAssociation]::CreateSiteContentTypeAssociation($template, $WfAssociationName, $web.Lists[$tasklist], $web.Lists[$historylist])   
           $association.AllowManual = $false  
           $association.AutoStartCreate = $true  
           $ct.AddWorkflowAssociation($association)  
           $ct.UpdateWorkflowAssociationsOnChildren($true, $true, $true, $false)  
           $association.Enabled=$true  
           $ct.Update()  
           $web.Update()  
         }  
         else  
         {  
         Write-Error "Workflow Template not found"  
               Add-Content $logFileName "Workflow Template not found."  
         }  
       }  
     function StartWorkflow($site, $wfAssociationName, $listName, $contentType, $WfStartColumn)  
     {  
       $contentType = $web.ContentTypes[$contentType]  
       if($contentType)  
       {  
         [Microsoft.Office.RecordsManagement.InformationPolicy.Policy]::CreatePolicy($contentType, $null);  
         $newPolicy = [Microsoft.Office.RecordsManagement.InformationPolicy.Policy]::GetPolicy($contentType);  
          $wfAssociationId = $contentType.WorkflowAssociations.GetAssociationByName($wfAssociationName, 1033).ParentAssociationId.ToString()  
         $newPolicy.Items.Add("Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration",  
          "<Schedules nextStageId='3'>"+  
          "<Schedule type='Default'>"+  
          "<stages>"+  
          "<data stageId='1' stageDeleted='true'></data>"+  
          "<data stageId='2'>"+  
          "<formula id='Microsoft.Office.RecordsManagement.PolicyFeatures.Expiration.Formula.BuiltIn'>"+  
          "<number>"+$Period+"</number>"+"<property>"+$Property+"</property>"+  
          "<period>"+$PeriodType+"</period>"+  
          "</formula>"+  
          "<action type='workflow' id='"+ $wfAssociationId +"' />"+  
          "</data>"+  
          "</stages>"+  
          "</Schedule>"+  
          "</Schedules>");  
         $newPolicy.Items.Add("Microsoft.Office.RecordsManagement.PolicyFeatures.PolicyAudit",  
          "<Audit>"+  
          "<Update />"+  
          "<View />"+  
          "<CheckInOut />"+  
          "<MoveCopy />"+  
          "<DeleteRestore />"+  
          "</Audit>");  
         $newPolicy.Update();  
       }  
       }  
     $web.Dispose()  
     $site.Dispose()  
     echo "Finished!!!"  
      AddWorkflowToContentType -site $site -ctName $ContentTypeName -wfName "DocumentApprovalWorkflow" -WfAssociationName "DocumentApproval" -TaxTaskList "Improvement Tasks";  
      StartWorkflow -site $site -contentType $ContentTypeName -wfAssociationName "DocumentApproval" -listName "Documents" -WfStartColumn "Modified";  
    

    Workflow should be availble on web when you run this script.
    workflow is of sharepoint 2010 reusable type.

    Happy Coding!!

    Monday, March 18, 2013

    How to: Follow documents and sites by using the .NET JavaScript object model in SharePoint 2013

    Scenario is here we will create one sample user control, which will have simple one star which we can place on our page to follow the site/documents using JavaScript object model.

    1. Visual Studio 2012, SharePoint project.
    2. Add new item, web user control and give a name : favoriteControl.ascx
    3.

     <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="FavoriteControl.ascx.cs" Inherits="test.FavoriteControl" %>  
     <div class="favIcon" runat="server" id="favoriteLink"><a href="#" runat="server" id="favorite" onclick="javascript:Follow();"></a></div>  
    
    4. Add Script file to project, named favoritehelper.js and paste the following code:



     $(document).ready(function () {  
       // Ensure that the SP.UserProfiles.js file is loaded before the custom code runs.  
       //SP.SOD.executeOrDelayUntilScriptLoaded(loadUserData, 'sp.userprofiles.js');  
       SP.SOD.executeOrDelayUntilScriptLoaded(function () {  
         SP.SOD.executeOrDelayUntilScriptLoaded(function () {  
           SP.SOD.executeOrDelayUntilScriptLoaded(isAlreadyFollowed, 'SP.UserProfiles.js');  
         }, 'SP.js');  
       }, 'SP.runtime.js');  
     });  
     var clientContext;  
     var socialActor;  
     function isAlreadyFollowed() {  
       clientContext = SP.ClientContext.get_current();  
       socialManager = new SP.Social.SocialFollowingManager(clientContext);  
       socialActor = new SP.Social.SocialActorInfo();  
       var siteContentUrl = window.location;  
       socialActor.set_contentUri(siteContentUrl);  
       var result = socialManager.isFollowed(socialActor);  
       if (result = true) {  
         document.getElementById('ctl00_PlaceHolderMain_favoriteControl1_favoriteLink').className = 'favIconSelected';  
         //alert('Alreadyfollowed');  
       }  
       else {  
         document.getElementById('ctl00_PlaceHolderMain_favoriteControl1_favoriteLink').className = 'favIcon';  
         // alert('alreadynotfollowed');  
       }  
     }  
     function Follow() {  
       if (!isAlreadyFollowed()) {  
         clientContext = SP.ClientContext.get_current();  
         socialManager = new SP.Social.SocialFollowingManager(clientContext);  
         var siteContentUrl = window.location;  
         var siteActorInfo = new SP.Social.SocialActorInfo();  
         siteActorInfo.set_contentUri(siteContentUrl);  
         //4 type is for set of site  
         siteActorInfo.set_actorType(4);  
         socialManager.follow(siteActorInfo);  
         document.getElementById('ctl00_PlaceHolderMain_favoriteControl1_favoriteLink').className = 'favIconSelected';  
         alert('Added into your follow list');  
       }  
     }  
     function StopFollowing() {  
       clientContext = SP.ClientContext.get_current();  
       socialManager = new SP.Social.SocialFollowingManager(clientContext);  
       var siteContentUrl = window.location;  
       var siteActorInfo = new SP.Social.SocialActorInfo();  
       siteActorInfo.set_contentUri(siteContentUrl);  
       siteActorInfo.set_actorType(4);  
       socialManager.stopFollowing(siteActorInfo);  
     }  
     function GetFollowers() {  
       clientContext = SP.ClientContext.get_current();  
       socialManager = new SP.Social.SocialFollowingManager(clientContext);  
       var followersArray = socialManager.getFollowers();  
       return followersArray;  
     }  
     function GetFollowed() {  
       clientContext = SP.ClientContext.get_current();  
       socialManager = new SP.Social.SocialFollowingManager(clientContext);  
       var followedArray = socialManager.GetFollowed(4);  
       return followedArray;  
     }  
     function GetFollowedCount() {  
       clientContext = SP.ClientContext.get_current();  
       socialManager = new SP.Social.SocialFollowingManager(clientContext);  
       var count = socialManager.getFollowedCount(types)  
     }  
    
    5. Add New web form and  register the control and the necessary script references.

    follow the code:
     <%@ Register Src="~/Widgets/FavoriteControl.ascx" TagName="FavoriteControl" TagPrefix="gims" %>  
     <asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">  
     <script src="/_layouts/15/sp.runtime.js" ></script>  
         <script src="/_layouts/15/sp.js" ></script>  
         <script src="/_layouts/15/sp.UserProfiles.js" ></script>  
        <script src="/Scripts/jquery-ui.js"></script>  
       <script src="/Scripts/jquery.min.js"></script>  
     <script src="/Scripts/FavoriteHelper.js" ></script>  
     </asp:Content>  
    
    and in your content area add the control


     <div>  
        <gims:FavoriteControl  ID="favoriteControl1" runat="server" />  
     </div>  
    

    That's it! we are good to go, on page will get star, if it is already followed will be get selected by default, if not than on click of star it will get followed.

    Reference link:

    http://msdn.microsoft.com/en-us/library/jj667824.aspx


    Tuesday, February 12, 2013

    SharePoint 2013 Workflow gets canceled automatically

    Hi,

    I was struck with the error of Workflow gets canceled automatically.
    Scenario was :
    A new SP 2013 installation, one server with SP, WF, etc and the other is simply SQL Server. Went through the installation steps for Workflow including the powershell bits. In designer, I am able to create a simple workflow and select 2013 as the type. When the workflow is run, is shows internal status is canceled and has the following error text below.

    • RequestorId: 55c6990b-c4a6-352c-4a5b-449fc1aecac4. Details: System.ApplicationException: HTTP 401 {"x-ms-diagnostics":["3001000;reason=\"There has been an error authenticating the request.\";category=\"invalid_client\""],"SPRequestGuid":["55c6990b-c4a6-352c-4a5b-449fc1aecac4"],"request-id":["55c6990b-c4a6-352c-4a5b-449fc1aecac4"],"X-FRAME-OPTIONS":["SAMEORIGIN"],"SPRequestDuration":["61"],"SPIisLatency":["1"],"Server":["Microsoft-IIS\/8.0"],"WWW-Authenticate":["Bearer realm=\"61e7a76b-024e-40d5-9185-2887a044d7cc\",client_id=\"00000003-0000-0ff1-ce00-000000000000\",trusted_issuers=\"00000005-0000-0000-c000-000000000000@*,00000003-0000-0ff1-ce00-000000000000@61e7a76b-024e-40d5-9185-2887a044d7cc\"","Negotiate","NTLM"],"X-Powered-By":["ASP.NET"],"MicrosoftSharePointTeamServices":["15.0.0.4420"],"X-Content-Type-Options":["nosniff"],"X-MS-InvokeApp":["1; RequireReadOnly"],"Date":["Tue, 05 Feb 2013 19:17:31 GMT"]} {"error_description":"The server was unable to process the request due to an.....


      Finally nailed it by following steps:

      1. Be sure User profile synchronization is started.

      2. The user by whom you are logged is available in User Profile list. ( In my case it was not, created new profile for the current logged in user and make sure, you are not running workflow with SharePoint system user. Please create a new user in Active directory, and using this user, create/provision workfow
              3. Final step full synchronization of User Profile Application.


    and its started working!!!

    Hope it saves your time

    Wednesday, February 6, 2013

    SharePoint 2013 Taxonomy import using .csv and Setting site navigation to use taxonomy using PowerShell

    Now requirement to import taxonomy from .csv file using PowerShell as well set taxonomy as site navigation with url.

    1. Create .csv file


    2. Create new script and paste below code.



     Param(  
      [string] $siteUrl = $(throw "Error: Parameter siteUrl is required"),  
      [boolean]$emptyfirst  
     )  
     ##Variables that should not be edited  
     $termsetName="My Navigation"  
     function CreateTerm( $parent, $name, $url )  
     {  
      Write-Host "Adding term $($parent.Name) -> $name"  
       $term = $parent.CreateTerm("$name", 1033)  
      $term.IsAvailableForTagging = $false  
      $term.SetLocalCustomProperty("_Sys_Nav_ExcludedProviders", '"CurrentNavigationTaxonomyProvider"')  
      $term.SetLocalCustomProperty("_Sys_Nav_SimpleLinkUrl", $url)  
      #$term.SetLocalCustomProperty("tIME", $url)  
      return $term  
     }  
     function GetTerm($termName, $parent)  
     {  
       $termName = [Microsoft.SharePoint.Taxonomy.TaxonomyItem]::NormalizeName($termName)  
       $term = $null  
      if( $termName -ne "" -and $parent -ne $null ){  
      if( $parent.Terms -ne $null ) {  
       $term = $parent.Terms | Where-Object {$_.Name -eq "$termName"}  
      }  
      if($term -eq $null ){  
       $term = CreateTerm -parent $parent -name "$termName" -url $_.URL  
      }  
      }  
      return $term;  
     }  
     function ImportTermSet([Microsoft.SharePoint.Taxonomy.TermSet]$set, [PSCustomObject]$terms) {   
      $terms | foreach {  
      $level1TermName = $_."Level 1 Term"  
      $level2TermName = $_."Level 2 Term"  
      $level3TermName = $_."Level 3 Term"  
       $level1Term = GetTerm -termName $level1TermName -parent $set  
      $level2Term = GetTerm -termName $level2TermName -parent $level1Term  
      $level3Term = GetTerm -termName $level3TermName -parent $level2Term   
      }  
      $ErrorActionPreference = "Continue";  
     }  
     Write-Host "Loading IIS module"  
     Import-Module WebAdministration  
     Write-Host "Loading SharePoint Commandlets"  
     Add-PSSnapin Microsoft.SharePoint.PowerShell -erroraction SilentlyContinue  
     Write-Host -ForegroundColor Green " Commandlets Loaded ... Loading Variables"  
     Write-Host "Connecting to Term Store"  
     Write-host  
     $termsetName="My Navigation"  
     $site = Get-SPSite $siteUrl  
     $web = $site.RootWeb  
     $session = [Microsoft.SharePoint.Publishing.Navigation.TaxonomyNavigation]::CreateTaxonomySessionForEdit($web)  
     $store = $session.TermStores[0]    
     $group = $session.TermStores.Groups | Where-Object {$_.SiteCollectionAccessIds -eq $site.ID }  
     $navigationSet = $group.TermSets | where { $_.Name -eq $termsetName }  
     if( $navigationSet -ne $null -and $emptyfirst) {  
      Write-Host -ForegroundColor Yellow "Removing existing termset"  
      $navigationSet.Delete()  
      $navigationSet = $null  
     }  
     if( $navigationSet -eq $null) {  
      Write-Host -ForegroundColor Yellow "Creating termset"  
      $navigationSet = $group.CreateTermSet($termsetName)  
     }  
     $navigationSet.SetCustomProperty("_Sys_Nav_IsNavigationTermSet", "True")  
     $navigationSet.SetCustomProperty("_Sys_Nav_AttachedWeb_SiteId", $site.ID.ToString())  
     $navigationSet.SetCustomProperty("_Sys_Nav_AttachedWeb_WebId", $site.RootWeb.ID.ToString())   
     $navigationSet.SetCustomProperty("_Sys_Nav_AttachedWeb_OriginalUrl", $site.RootWeb.Url )  
     #2013-02-05T12:52:07.5250653Z  
     $date = Get-Date -Format "yyyy-MM-ddTHH:mm:ssZ"   
     $navigationSet.SetCustomProperty("_Sys_Nav_AttachedWeb_Timestamp", $date )  
     Write-Host "Importing Term Set CSV File"  
     $scriptpath = $MyInvocation.MyCommand.Path  
     $dir = Split-Path $scriptpath  
     $fileEntries = [IO.Directory]::GetFiles($dir);   
     foreach($fileName in $fileEntries)   
     {   
      $ext=[System.IO.Path]::GetExtension($fileName)  
      if($ext -eq ".csv")  
      {  
      Write-Host -ForegroundColor Green "Processing $fileName"  
      $CSVFILEPATH=$fileName;  
      $terms = Import-Csv -Delimiter ';' $fileName  
      ImportTermSet $navigationSet $terms  
      "All term sets have been imported"  
      Write-Host  
       }  
     }  
     $store.CommitAll()   
     Write-Host "Setting site nav to use taxonomy"  
     $settings = new-object Microsoft.SharePoint.Publishing.Navigation.WebNavigationSettings($web);  
     $settings.GlobalNavigation.Source = [Microsoft.SharePoint.Publishing.Navigation.StandardNavigationSource]::TaxonomyProvider  
     $settings.GlobalNavigation.TermStoreId = $store.Id  
     $settings.GlobalNavigation.TermSetId = $navigationSet.Id  
     $web.Update()  
     $settings.Update($session)  
    


    Note :
    1. Script file and .csv file should be in same folder.
    2. This script supports import for multiple .csv files too. However it has to be in same folder.
    3. Script will look for .csv in the current folder and will do import to Term store.
    4.As well this script will set site navigation to use the taxonomy, It will set the navigation link with provided url to the term.




    Tuesday, February 5, 2013

    SharePoint 2013 TermSet with PowerShell


    Create new script with following code:

    $session = Get-SPTaxonomySession -Site "Your site Url"
    $termStore = $session.TermStores[“Managed Metadata Application”] - change your managed metadata service name
    $group = $termstore.CreateGroup(“My New Group”)
    $group.Description = "My Term Group"
    $termStore.CommitAll()
    $termSet = $group.CreateTermSet(“My TermSet”,1033)
    $termSet.Description = My TermSet
    $termSet.IsAvailableForTagging = $true
    $termSet.IsOpenForTermCreation = $true
    $termStore.CommitAll()

    To enable the term set for navigation, i.e  "Use this Term Set for Site Navigation" 
    use following code to make it enabled.

    $navigationSet = $group.CreateTermSet($termsetName)
     $navigationSet.SetCustomProperty("_Sys_Nav_IsNavigationTermSet", "True")
     $navigationSet.SetCustomProperty("_Sys_Nav_AttachedWeb_SiteId", $site.ID.ToString())
     $navigationSet.SetCustomProperty("_Sys_Nav_AttachedWeb_WebId", $site.RootWeb.ID.ToString())    
     $navigationSet.SetCustomProperty("_Sys_Nav_AttachedWeb_OriginalUrl", $site.RootWeb.Url )
    You can check your new termset inside "My New Group" : go to  site management -> Term Store Management.