Reassign a workflow task – Task update was not accepted. To edit a task associated with a workflow task process, you must be the person to whom the task is currently assigned.


Hi guys,

Recently one of my client has faced this issue while reassigning a task of default Approval workflow. Here is the screen shot:

      

SharePoint by default only allows the assignee to re-assign the task. If you try to re-assign a task that is not assigned to you, you get the following message:

Task update was not accepted. To edit a task associated with a workflow task process, you must be the person to whom the task is currently assigned.

Solution

To overwrite this behaviour:

  1. Open SharePoint Designer
  2. Open the Workflow you wish to modify.
  3. On the step where you start the workflow task ‘Start <workflow task name> process on Current Item with…’, right click on the task name.
  4. Select Properties and look for the attribute TaskProcessOwner.
  5. Click on the ‘‘ button to select a group or specific user.
  6. You may wish to create a SharePoint group specifically for this purpose. All members of this group will have permissions to re-assign tasks that are assigned to other people.

Hope this post help you to fix this error.

Happy SharePointing.

Advertisements

SharePoint Online/2013 Replace no results default text ‘Nothing here matches your search’ from search results web part


 

As we all aware, SharePoint search have great potential to provide very powerful search solution. Couple of new webparts are added in SharePoint 2013, like Content Search web part for which I should use rather a word “Smart” search web part. With a new rendering mechanism, content search webpart becomes more and more simple to edit and customize. That mechanism is called “Display Templates” and these are based upon simple Json to HTML templates.

I recently has faced a project scenario, where I was asked to replace the part of search result web part and I provided a solution by updating search display template.

Requirement:  When we add a search result web part on any result page along with a search text box web part to enter search keywords. Search results will be displayed in web part if keyword matches any text. When we add both these web parts on page and before entering the search term also the results web part show  “Nothing here matches your search” (as shown in below image), which my users want to modify based on their content and want to add some useful links into it.

Blog1

 

Solution:

Initially, I thought that this may be easily updated using some web part property, but after researching about it, I found that there are html/json files called, display templates, which are responsible for rendering this text. Let me explain how to find them and which Display Template we need to customize in order to achieve our target.

All kind of Display Templates are stored at the one location under master page gallery. Here are the steps to reach out to the html file.

  1. Open the site collection.
  2. Navigate to Site Settings.
  3. Under Web Designer Galleries click on Master pages and page layoutsBlog2
  4. Now click on the folder Display Templates and then Search.     Blog3
  5. Under the search folder you will find html and .Js files present.
  6. We are more intereste d in ‘Control_SearchResults.html’. Make sure you click in html file not JS file with same name.

If you are not familiar with this structure then you must be thinking that “Why JS and HTML files with two names?”

In brief, actually display templates are JS files only but just to the sake of simplicity MS has provided HTML so that it is easier to modify/edit display templates. There is out of box event receiver attached to this list when there is any modification detected in HTML file, a new version of JS will be generated by the event receiver. Display Templates are actually split into two different files, the Control and the Item.

Control Display Template

This is the part of your design that does not get repeated as each items gets loaded in the Search Results. It’s the container around and where you refer to any custom CSS or JS files you may want to use.

Put simply, it’s the box where search results will be loaded.

Item Display Template

This is where you design how each item will look like and which managed properties from the result item will be used and where on the design. If I take my example above, that’s all in the Item Display Template. The size of the rectangle, where the Title goes and where the Description goes as well as the animation itself.

Search Results web part of SharePoint uses ‘Control_SearchResults.html’ display template which is available under Master Page Library –> Display Templates –> Search.

Now lets start actual modification of the template:

  1. Download a copy of ‘Control_SearchResults.html’. Click Control_SearchResults.html template file and Download a Copyblog5
  2. Rename the downloaded file as Control_SearchResults_Custom.html. Open the control template file in any of your preferred editors such as SharePoint Designer and customize the file, as per our need.blog6
  3. Change the Title in this HTML file, this title will be available for selection in web part properties.
  4. Now we want to get the search text entered in to search box web part, for that we will use ctx object as following ctx.DataProvider.get_currentQueryState().k
  5. Search if(ctx.ClientControl.get_shouldShowNoResultMessage()){    line in HTML file (as shown in below image).
    Search_Result_SP_2013_Display_Template_1
  6. Find the unordered list just below that code and modify it according to your need.
  7. For example if you don’t want to show any message until user enters some keyword, replace if statement line with
    var currentQueryTerm = ctx.DataProvider.get_currentQueryState().k; if(ctx.ClientControl.get_shouldShowNoResultMessage() && currentQueryTerm!=””){
    (As shown in below image)
    Search_Result_SP_2013_Display_Template_2
  8. Save the modified HTML file.
  9. Go to Master Page Library –> Display Templates –> Search and upload new control template.
  10. You will see that respective ‘Control_SearchResults_custom.js’ will be created by SharePoint.
  11. Now go to your page where Search Result web part is added, edit Search results web part. Under Display Templates section select newly uploaded display template.( as shown in below image).Select our custom control display template.

  12. Save the changes and that’s it, you will see the  expected result.

Hope this information is helpful for you to modify display templates.

Happy SharePointing 🙂

 

Not able to view result while building Search Query


Hello SharePointers ;),

Here is another quick finding which I just thought should be shared to save someone precious time. If you are dealing with SharePoint 2013 search and Result sources, you must try to test the query template before saving it. If you are not able to see any results instead just a red error saying below text don’t get scared I have quick solution for you.

“The Search display templates are not present on this site collection. To add them, you need to activate the “Search Server Web Parts and Templates” feature on the Site Collection Features page.

Display Error: The display template had an error. You can correct it by fixing the template or by changing the display template used in either the Web Part properties or Result Types.

Template ‘~sitecollection/_Catalogs/masterpage/DisplayTemplates/System/Control_QueryBuilderPreview.js’ not found or has sytax errors. (Load Template: ) ”

Search_Error

You must get frustrated because your search is properly configured, its crawling the data and you are able to see results while searching.  After looking at what was missing I found that in fact there was a feature missing on the Central Administration site collection. The feature is called Search WebParts.

But its not so quick that you just navigate to Site collection feature and activate it. As this feature is present at central admin site collection level so it requires extra privileges to activate it. To fix the problem, simply run the following command in an elevated SharePoint Management Shell:

Enable-SPFeature SearchWebParts -url http://<central admin url>

Bingo!! Just, re-open the “build your query” page, and everything should work properly!

Search_Error

Hope that post was able to help you. Please press like button it that saved your time.

Happy SharePointing 🙂

SharePoint : Custom Task Email with Outlook ribbon control “Open this Task”


Hi Guys,

It was really interesting to work with my latest client. They had an very interesting and innovated idea to automate their manual file approval process.  The requirement was to create a multistage state machine workflow where users have privilege to approve and reject documents with some comments. It was very interesting to work with end client(as they them self don’t know what they actually want).

I will not go deep into the workflow but surly will come back with another post explaining it. This post is more about a requirement which I faced during the development of the workflow. Just wanted to share the design of the Workflow:

WF

Requirement:  As a user, I should have receive an email from workflow with custom subject having document name embedded to the subject where I can directly do some action like approve/reject or comment on the document. I should see a button in email “Open this task” which will redirect me to the page where I can take actions.

1

It looks bit easy but have hidden challenges in it. Most us are aware of the fact that when a task item is created, either directly in the task list or through a Workflow an alert email would be sent saying a task has been assigned to you (provided alerts are enabled). When we look at that email in Outlook we see an additional control in the ribbon “Open this Task” under the group “Open” as shown in above figure. Let me rephrase the requirements:

  1. We have to customize the body and subject as per their request
  2. Ribbon button “Open this Task” should present when the email is sent

The above mentioned two points are two sides of the coin, which means if you are able to see one then second will not be visible to you. So the final solution’s must have some trick to achieve both cases.

Solution: 

One point is clear that we can not go along with the default workflow email feature, we have to use “SmtpClient” or “SPUtility” to create email with custom body and subjects. Now question is how one can get ribbon button using SPUtility send email function.

  • I have used “SPWorkflowTaskProperties” class in the Task Created Event and sent it two properties “SPWorkflowTaskProperties.HasCustomEmailBody = true” and “SPWorkflowTaskProperties.EmailBody= <My Custom HTML Email Body> ” With this I can satisfy requirement 1 & 2 but not 3 (listed above).  Also if I were to create a task and if I want to send an email using Event Handler on item created I may not be able to use this. So for the generic purposes this would not fit in.
  • Next I thought of modifying the alert template but then it would have an impact on all task lists which is not a recommended option.
  • So, I have decided that I have to disable the alerts for that Task list and use “SmtpClient or SPUtility” class instead to send email which can be used at different requirements such as “event handlers/workflows or any other for that matter. With this class we do have control over all the aspects “From, To, Subject, Email Body, etc”. The only problem with this to achieve the requirement # 2 (Ribbon control in outlook). I always wondered how would outlook recognize that an email is for Task, how is this ribbon control activated as soon as it sees an email.

I believed that the alert email sent has some headers which mark this as Task which is understood by outlook and displays the controls accordingly. So now the question is what are those headers. After some research I figured out the Mail message headers. Below is the code for sending an email which also includes those headers and satisfies all the above mentioned requirements (1 & 2)

/// <summary>
/// Method used to send the task created email instead of default SP WF email notification
/// </summary>
/// <param name=”web”></param>
/// <param name=”htmlBody”></param>
/// <param name=”ToEmailId”></param>
/// <param name=”listItem”></param>
/// <param name=”emailSubject”></param>
/// <returns></returns>
public bool SendTaskMail(SPWeb web, string htmlBody, string toEmailId, SPList taskList, string itemId, string emailSubject)
{
try
{
string domain = web.Site.WebApplication.OutboundMailSenderAddress.Remove(0, web.Site.WebApplication.OutboundMailSenderAddress.LastIndexOf(‘@’));
var messageHeaders = new StringDictionary();
messageHeaders.Add(“to”, toEmailId);//author.User.Email);
messageHeaders.Add(“subject”, emailSubject);
messageHeaders.Add(“content-type”, “text/html”);

messageHeaders.Add(“Message-Id”, “<3BD50098E401463AA228377848493927” + Guid.NewGuid().ToString(“D”) + domain + “>”);
messageHeaders.Add(“X-Sharing-Title”, ConvertToBase64String(“Body”));
messageHeaders.Add(“X-AlertTitle”, ConvertToBase64String(“System”));
messageHeaders.Add(“Content-Class”, “MSWorkflowTask”);
messageHeaders.Add(“X-AlertWebUrl”, ConvertToBase64String(web.Url));
messageHeaders.Add(“X-AlertServerType”, “STS”);
messageHeaders.Add(“X-AlertWebSoap”, ConvertToBase64String(web.Url + “/_vti_bin/alerts.asmx”));
messageHeaders.Add(“X-Sharing-Config-Url”, “stssync://sts/?ver=1.1&type=tasks&cmd=add-folder&base-url=” + Uri.EscapeDataString(web.Url) + “&list-url=” + Uri.EscapeDataString(taskList.RootFolder.ServerRelativeUrl) + “&guid=” + Uri.EscapeDataString(taskList.ID.ToString(“D”)));
messageHeaders.Add(“X-Sharing-Remote-Uid”, taskList.ID.ToString(“D”));
messageHeaders.Add(“X-Sharing-WssBaseUrl”, ConvertToBase64String(web.Url));
messageHeaders.Add(“X-Sharing-ItemId”, ConvertToBase64String(itemId));

SPUtility.SendEmail(web, messageHeaders, htmlBody);

return true;
}
catch (Exception ex)
{
Utilities.UpdateLogErr(ex, “Error while sending email. Please find details in audit logs”);
return false;
}
}

Hope this helps!

Thank you for your time.

Happy SharePointing 🙂 !!

SharePoint PowerShell: Upload multiple documents to sharepoint document library


Hi,

I was creating a script to replicate document library structure similar to Prod just in order to test the ShareGate Migration. Let me take a brief description about my scenario:

Description:

There is a document library present on Prod, which contains bulk document (~3000). Now I need to update metadata for all those documents using Excel sheet and ShareGate. I don’t have access to the Production library and not even replicate the Library to my Dev environment as it contains some very confidential documents.

Solution:

I have decided to create a script which will take one template document from file system and read name of document from one of columns of excel. The script will take some time(~hours in case of thousand documents) to upload the template with the new file name. The inputs to the script will be

  1. Path of the excel which contains name of documents in one column
  2. Path of the file where the template is placed on file system
  3. Url of the sharepoint web site
  4. Name of the document library

2

Code: 

# Add SharePoint Snapin to PowerShell            
if((Get-PSSnapin | Where {$_.Name -eq "Microsoft.SharePoint.PowerShell"}) -eq $null)             
{            
 Add-PSSnapin Microsoft.SharePoint.PowerShell            
}
$exlFile = "D:\Work\Book2 - Copy.xlsx"
$fileExt = ".pdf"
#$filePath =  "D:\Work\IAEA.docx"  
$filePath = "D:\Work\pdf.pdf"
$webUrl = "http://server/sites/site"            
$docLibName = "Library Name"      

try {    
    $xl = New-Object -COM "Excel.Application"
    #$xl.Visible = $true
    $wb = $xl.Workbooks.Open($exlFile)
    #$ws = $wb.Sheets.Item('Log')
    $ws = $wb.Sheets.Item('Sheet1')
    $lines = $ws.UsedRange.Rows.Count

    $spWeb = Get-SPWeb -Identity $webUrl             
    $spWeb.AllowUnsafeUpdates = $true;            
    $lib = $spWeb.Lists[$docLibName]            
    $folder = $lib.RootFolder            
    #$sourceFileName = $filePath.Substring($filePath.LastIndexOf("\")+1)             
    $file= Get-ChildItem $filePath  
    
    $docLibraryUrl = $lib.RootFolder.ServerRelativeUrl
    $uploadfolder = $spWeb.getfolder($docLibraryUrl + $folderPathWithinDocLibrary)
            
    $fileStream = ([System.IO.FileInfo] (Get-Item $file.FullName)).OpenRead()     

    for ($line = 2; $line -le $lines; $line ++) {       
        $fileName = $ws.Columns.Item(1).Rows.Item($line).Text
        
        if($fileName -ne "")
        {
            $fileName
            #Check if File exist
            $item = $uploadfolder.Files | where{$_.Name -eq $fileName}
            if(!$item)
            {                
                #Add file            
                write-host -NoNewLine -f yellow "Addin file " $fileName " to " $folder.ServerRelativeUrl "..."                    
                $newFilePath = $docLibraryUrl + $folderPathWithinDocLibrary + "/" + $fileName
                write-host "Creating document: $newFilePath ..."
                $spFile = $uploadfolder.Files.Add($newFilePath, [System.IO.Stream]$fileStream, $true)  
                
                write-host -f Green "...Success!" 
            }
        }
    }
     #Close file stream            
    $fileStream.Close()
    $spWeb.AllowUnsafeUpdates = $false;
    $spWeb.Dispose();
    $xl.Quit()
}
finally { 
    $wb.Close()
    $xl.Quit()
    [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
}

Output:

1

Hope that code help you finding solution.

Happy SharePointing 🙂

Mohit Vashishtha

Upload a file in SharePoint using REST and c# console application


Hi,

In my last post, I have explained how to create a sub site using REST from and Console application. In this blog  will explain how we can upload a file, which is located in file system, will be uploaded to sharepoint Document library. So if I brief about requirement here:

  • Need to upload a file to already created SharePoint site.
  • Use REST(not even CSOM) will be used in order to create.
  • API call will be send from some other machine(not SharePoint machine) which is in same domain and can access the SharePoint site.

Follow the given steps to achieve the same:

1) Create a simple console application with c# selected language.

1

2) Next is to install the Newtonsoft.Json. Navigate to Visual studio menu: “View” > “Other Windows” > “Package Manager Console” and Then type the following: “Install-Package Newtonsoft.Json”

2

3) Now install RestSharp using the package manager. Type the following: “Install-Package RestSharp”

3

4) Now open the Program.cs file of console application and paste the code below:

string siteurl = “http://sharepoitsite/sites/subsite&#8221;; //site on which file needs to be uploaded (don’t put / at end)
string documentlibrary = “Documents”; //Document library where file needs to be uploaded

string filePath = @”C:\Users\mohit.vashishtha\Desktop\test.html”;

byte[] binary = System.IO.File.ReadAllBytes(filePath);
string fname = System.IO.Path.GetFileName(filePath);
string result = string.Empty;
//Url to upload file
string resourceUrl = string.Format(“{0}/_api”,siteurl);

RestClient RC = new RestClient(resourceUrl);
NetworkCredential NCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
RC.Authenticator = new NtlmAuthenticator(NCredential);

Console.WriteLine(“Creating Rest Request”);
RestRequest Request = new RestRequest(“contextinfo?$select=FormDigestValue”, Method.POST);
Request.AddHeader(“Accept”, “application/json;odata=verbose”);
Request.AddHeader(“Body”, “”);

string ReturnedStr = RC.Execute(Request).Content;
int StartPos = ReturnedStr.IndexOf(“FormDigestValue”) + 18;
int length = ReturnedStr.IndexOf(@”””,”, StartPos) – StartPos;
string FormDigestValue = ReturnedStr.Substring(StartPos, length);

Console.WriteLine(“Uploading file Site……”);

resourceUrl = string.Format(“/web/GetFolderByServerRelativeUrl(‘{0}’)/Files/add(url='{1}’,overwrite=true)”, documentlibrary ,fname);
Request = new RestRequest(resourceUrl, Method.POST);
Request.RequestFormat = DataFormat.Json;
Request.AddHeader(“Accept”, “application/json;odata=verbose”);
Request.AddHeader(“X-RequestDigest”, FormDigestValue);
Console.WriteLine(“File is successfully uploaded to sharepoint site.”);
Console.ReadLine();

5) Now application is ready to run. Make sure that all the namespace issues are resolved.

6) It will take some time to create site but output window will display the details it got from the Request.

In case of already existing site:

54

Hope this information is helpful to you. Thanks for time.

Happy SharePointing 🙂

 

Get SharePoint search results using REST ajax call from Html


Hi,

We all aware the SharePoint exposed REST Api in order to perform various action at client side. There are some other ways also which a developer can adopt instead of REST(like CSOM) but that requires again client context. So it is recommenced that if we are using SharePoint Apps then use CSOM to get and update the data. Where as REST can be used in apps as well as some external applications.

This blog is intended to show how user can utilize the REST api and get the SharePoint Search results. There are few pre-requisites or conditions which must be fulfilled before proceeding further.

  • The machine where this code will be executed must have access to sharepoint site which means machine must be either in same domain or cross domain accessibility is there.
  • Search must be configured at SharePoint server.
  • Data must be properly crawled and you must get some results when searched for some keyword.

Steps:

1) Open the Explorer or any desired location and create a text file with ant desired name.

2) Now open this txt file in Notepad and click on “Save as..” option. Here select the “Save as type” as “All” and save the file in “.html” format as shown below:

1

3) Now open this file in any desired text editor(I love to use Notepad++ for same) and paste the following code:

<script src=”http://code.jquery.com/jquery-2.1.4.js&#8221; type=”text/javascript”></script>
<script type=”text/javascript”>
$(document).ready(function () {
$(“#SearchQuery”).click(function() {
$.ajax({
url: “http://<server URL>/_api/search/query?querytext='”+$(“#search-input”).val()+”‘&sourceid=%27b09a7990-05ea-4af9-81ef-edfab16c4e31%27″,
headers: { Accept: “application/json;odata=verbose” },
success: function (data) {

console.log(data.d);

},
error: function (jQxhr, errorCode, errorThrown) {
console.log(errorThrown);
}
});
});

});</script>
<input type=”text” id=”search-input”>
<input type=”button” id=”SearchQuery” value=”Search”>
<div id=”resultsDiv”></div>

Issues faced:

1) minFreeMemoryPercentageToActivateService memory issue:

2

Resolution: Open the web config of the web application and find out the entry with

<serviceHostingEnvironment aspNetCompatibilityEnabled=”true” />

to

<serviceHostingEnvironment aspNetCompatibilityEnabled=”true” minFreeMemoryPercentageToActivateService=”1″/>

Happy SharePointing 🙂