Friday, November 15, 2019

Checking if a User is in an SPGroup

Many know an example "How to check if user exists in a particular sharepoint group or not programatically":
using System;
using System.Linq;
using Microsoft.SharePoint;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            string userName = "DOMAIN\\user";
            string groupName = "Home Members";
            using (SPSite Site = new SPSite("http://sp"))
            {
                using (SPWeb Web = Site.OpenWeb())
                {
                    SPUser user = Web.EnsureUser(userName);
                    if (user.Groups.Cast().Any(g => g.Name.Equals(groupName)))
                    {
                        Console.WriteLine("User " + userName + " is a member of group " + groupName);
                    }
                    else
                    {
                        Console.WriteLine("User " + userName + " is NOT a member of group " + groupName);
                    }
                }
            }
        }
    }
}
The example is excellent, in the end we will write "bool" using "ToUpper()", which at the machine level works much faster, because Microsoft optimized it:
bool checkuser = user.Groups.Cast().Any(g => g.Name.ToUpper() == "Home Members".ToUpper());
//or GetCurrentUser
bool checkgcuser = SPContext.Current.Web.CurrentUser.Groups.Cast().Any(g => g.Name.ToUpper() == "Home Members".ToUpper());
Happy Coding!

Monday, March 4, 2019

Search text in Document (Word, Excel, Pdf, Txt)

In the previous article, I described how to create a document and attach it to a list item when creating it, this time I will focus on finding words within a document, since At the moment I am working on the implementation of my own project for searching the library of keywords within documents.
To work with documents Word and Excel I use DocumentFormat.OpenXml and to work with pdf I use TallComponents.PDFKit.

Why? Because MS SharePoint server keeps source files (documents) on the server, but in the client part we work with a copy of the document. I will give 4 code examples for MS Word (doc, docx), Excel (xls, xlsx), Pdf and Txt. I hope these examples will help you in the future in your projects.

1. Word (DocumentFormat.OpenXml):
//get file library
 SPFile file = item.File;
 string value = file.ToString();
 int index = (value.LastIndexOf('/') + 1);
 string fileName = value.Substring(index);
 string FileExtension = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower();
  //condition
   if (FileExtension == "doc" || FileExtension == "docx")
    {
     if (file.Exists)
      {
       //use file Stream
        byte[] byteArray = file.OpenBinary();
         using (MemoryStream memStr = new MemoryStream())
          {
           memStr.Write(byteArray, 0, (int)byteArray.Length);
            using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(memStr, false))
             {
              Document document = wordDoc.MainDocumentPart.Document;
               var body = document.MainDocumentPart.Document.Body;
                //search in body
                 foreach (var text in body.Descendants<Text>())
                  {
                   //use case sensetive
                     if (text.Text.IndexOf("test", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
                      {
                       Console.WriteLine(file.ToString());
                      }
                  }
              }
           }
        }
     }
2. Excel (DocumentFormat.OpenXml):
//condition
 if (FileExtension == "xls" || FileExtension == "xlsx")
   {
    if (file.Exists)
     {
      //use file Stream
       byte[] byteArray = file.OpenBinary();
        using (MemoryStream memStr = new MemoryStream())
         {
          memStr.Write(byteArray, 0, (int)byteArray.Length);
           using (SpreadsheetDocument document = SpreadsheetDocument.Open(memStr, false))
            {
             SharedStringTable sharedStringTable = document.WorkbookPart.SharedStringTablePart.SharedStringTable;
              string cellValue = null;
               foreach (WorksheetPart worksheetPart in document.WorkbookPart.WorksheetParts)
                {
                 //get List excel document 
                 foreach (SheetData sheetData in worksheetPart.Worksheet.Elements<SheetData>())
                  {
                   if (sheetData.HasChildren)
                    {
                     //get Row excel document
                     foreach (Row row in sheetData.Elements<Row>())
                      {
                       //get Cell excel document
                       foreach (Cell cell in row.Elements<Cell>())
                        {
                         cellValue = cell.InnerText;
                          if (cell.DataType == CellValues.SharedString)
                           {
                            cellValue = document.WorkbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault().SharedStringTable.ElementAt(int.Parse(cell.CellValue.Text)).InnerText;
                             //use case sensetive
                              if (cellValue.IndexOf("test", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
                               {
                                Console.WriteLine(file.ToString());
                               }
                            }
                         }
                       }
                    }
                 }
              }
           }
        }
    }
}
3. Pdf (TallComponents.PDFKit):
//condition
 if (FileExtension == "pdf")
   {
    if (file.Exists)
     {
      //use file Stream
      byte[] byteArray = file.OpenBinary();
       using (MemoryStream memStr = new MemoryStream())
        {
         memStr.Write(byteArray, 0, (int)byteArray.Length);
          {
           TallComponents.PDF.Document document = new TallComponents.PDF.Document(memStr);
           TextFindCriteria criteria = new TextFindCriteria("test", false, false);
           TextMatchEnumerator enumerator = document.Find(criteria);
            foreach (TextMatch match in enumerator)
             {
              Console.WriteLine(file.ToString());
             }
          }
       }
    }
 }
4. Txt (System.IO namespace):
//condition
 if (FileExtension == "txt")
   {
     if (file.Exists)
      {
        byte[] byteArray = file.OpenBinary();
         using (StreamReader reader = new StreamReader(file.OpenBinaryStream()))
           {
            string content = String.Empty;
            content = reader.ReadToEnd();
             if (content.IndexOf("test", 0, StringComparison.CurrentCultureIgnoreCase) != -1)
               {
                 Console.WriteLine(file.ToString());
               }
           }
       }
   }
Happy Coding!

Friday, February 22, 2019

Create document and upload list item attachment (SharePoint 2010, 2013, 2016)

Hello everyone, this time I will talk about creating Event Reciever and actions that will occur with the element of the list, we are talking about reading the properties of the list item, creating the Word document, filling it with these properties of the current list element and attaching it to an attachment to this element of the list while creating. Such a task came to mind non-monotonously, it was set by user asked it on the forum, I thought that in future project it was possible, and I myself wanted to broaden my horizons in this topic.
In this project, to create a document and its content, I will use DocumentFormat.OpenXml and a description of this library I will use the blog Create a word document with OpenXml and C# (by Ludovic Perrichon).

So begin!!!

1. Create is a Custom list (name "ListProject") then modify list view and show column "Created", "Created by", "Modified", "Modified by".



2.List is ready, then open Visual studio and click "New project" choose project depending on your version SharePoint On-Premises "SharePoint -(2010, 2013, 2016) Empty Project" project name "ItemUploadAttachments".



3. Set URL and Select a Farm Solution.



4. Click right-click on the project name and click "Add" then "New item" and choose "Event Reciever" is name "UploadAttachments".



5. And will see Event Reciever Settings then choose event source "Custom List" and click handle events only "An item was added". Click Finish.



6. Open is added in project Event Reciever "UploadAttachments" and you will see "Elements.xml" open and edit file, set to comment or remove row "<Receivers ListTemplateId="101">" and add "<Receivers ListUrl="Lists/ListProject">", then save file.



7. Open DocumentFormat.OpenXml and insert last version to nuget package "Install-Package DocumentFormat.OpenXml -Version 2.9.0".







8. We continue to work with Event Reciever open file "UploadAttachments.cs" and will see code "public override void ItemAdded(SPItemEventProperties properties) {}" this will be our event, which is activated when creating a list item. Add the code of this void "ItemAdded".
using (SPWeb web = properties.OpenWeb()) {
  try {
      //GetListCurrentItem
        SPListItem currentItem = properties.ListItem;
        string Title = currentItem["Title"].ToString();
        string Author = currentItem["Author"].ToString();
        DateTime Created = DateTime.Parse(currentItem["Created"].ToString());
        string Modified = currentItem["Editor"].ToString();
        DateTime EndTime = DateTime.Parse(currentItem["Modified"].ToString());
        string filepath = @"C:\Temp\" + Title + ".docx";
        //Create file
        CreateWordprocessingDocument(filepath, Title, Author, Created, Modified, EndTime);
        //Upload file
        FileStream stream = new FileStream(filepath, FileMode.Open);
        byte[] byteArray = new byte[stream.Length];
        stream.Read(byteArray, 0, Convert.ToInt32(stream.Length));
        stream.Close();
        currentItem.Attachments.Add(Title + ".docx", byteArray);
        currentItem.Update();
      }
       catch (Exception ex)
       {
        throw ex;
       }
}
9. Further, beyond the limits of this method, we create a public static void "CreateWordprocessingDocument"
public static void CreateWordprocessingDocument(string filepath, string Title, string Author, DateTime Created, string Modified, DateTime EndTime)
        {
        using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(filepath, WordprocessingDocumentType.Document))
            {
                MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();
                mainPart.Document = new Document();
                Body body = mainPart.Document.AppendChild(new Body());
                Paragraph para = body.AppendChild(new Paragraph());
                Run run = para.AppendChild(new Run());
                if (Author != "")
                    run.AppendChild(new Text("Author: " + Author));
                {
                    if (Created != null)
                    {
                        Paragraph p = new Paragraph();
                        Run r = new Run();
                        RunProperties rp2 = new RunProperties();
                        rp2.Italic = new Italic();
                        rp2.Bold = new Bold();
                        r.Append(rp2);
                        Text t = new Text("Date created: " + Created) { Space = SpaceProcessingModeValues.Preserve };
                        r.Append(t);
                        p.Append(r);
                        body.Append(p);
                    }
                    if (Modified != "")
                    {
                        Paragraph p = new Paragraph();
                        Run r = new Run();
                        Text t = new Text("Editor: " + Modified);
                        r.Append(t);
                        p.Append(r);
                        body.Append(p);
                    }
                    if (EndTime != null)
                    {
                        Paragraph p = new Paragraph();
                        Run r = new Run();
                        RunProperties rp2 = new RunProperties();
                        rp2.Bold = new Bold();
                        r.Append(rp2);
                        Text t = new Text("Date Modified: " + EndTime);
                        r.Append(t);
                        p.Append(r);
                        body.Append(p);
                    }
                }
            }
        }
10. Check our project is not error, Build solution and Deploy solution. Open our list "ListProject" then "New item" and check in attachment to this item.








Happy Coding!

Wednesday, February 13, 2019

Create folder in SharePoint list (SharePoint 2010, 2013, 2016)

So, we continue to work with basic operations, today is another piece of code in which we are using CSOM create a folder in the program list. And as usual by tradition I use Visual studio.

The main advantage of this code is the use of C#, which means such wonderful features are available as Custom Timer Job, Event Reciever and much more. In my console project I using following reference and code:

using Microsoft.SharePoint.Client;

using (var clientContext = new ClientContext("http://sp/sites/test"))
            {
                string folderName = "test";
                var list = clientContext.Web.Lists.GetByTitle("ListBase");
                list.EnableFolderCreation = true;

                clientContext.Load(list);
                clientContext.Load(list.RootFolder);
                clientContext.Load(list.RootFolder.Folders);
                clientContext.ExecuteQuery();

                var folderCollection = list.RootFolder.Folders;

                foreach (var folder in folderCollection)
                {
                    if (folder.Name == folderName)
                    {
                        clientContext.Load(folder.Files);
                        clientContext.ExecuteQuery();
                    }
                    else
                    {
                        var itemCreateInfo = new ListItemCreationInformation
                        {
                            UnderlyingObjectType = FileSystemObjectType.Folder,
                            LeafName = folderName
                        };
                        var newItem = list.AddItem(itemCreateInfo);
                        newItem["Title"] = folderName;
                        newItem.Update();
                        clientContext.ExecuteQuery();
                        break;
                    }
                }
            }
Happy Coding!

Copying folder library to another library (SharePoint 2010, 2013, 2016)

In this article, I continue to lay out the basic operations for working with .NET MS SharePoint server On-Premises one of which is copying a folder from an attachment inside from one library to another, as always I run the code from the Console application from Visual studio.

The main advantage of this code is the use of C#, which means such wonderful features are available as Custom Timer Job, Event Reciever and much more. In my console project I using following reference and code:

using Microsoft.SharePoint;

using (SPSite SPsite = new SPSite("http://sp/sites/test"))
            {
                using (SPWeb SPWeb = SPsite.OpenWeb())
                {
                    SPDocumentLibrary srcLib = (SPDocumentLibrary)SPWeb.Lists["Documents"];
                    SPDocumentLibrary destLib = (SPDocumentLibrary)SPWeb.Lists["OldDocuments"];
                    foreach (SPListItem sourceItem in srcLib.Folders)
                    {
                        SPFolder sourceFolder = sourceItem.Folder;
                        string targetPath = destLib.RootFolder.ServerRelativeUrl + "/" + sourceFolder.Name;
                        SPFolder targetFolder = SPWeb.GetFolder(targetPath);
                        SPListItem targetItem = targetFolder.Item;
                        sourceItem.Folder.CopyTo(targetPath);
                    }
               }
           }
Happy Coding!

Friday, January 25, 2019

Editing wsp-package third-party solution

In this article I will explain how to make a change to a third-party solution by changing the data in the wsp file. I have a wsp file, where the visual web part is displayed in English, since I have to work with Russian-speaking users, I need to add names in Russian and translate the web part from ANSI to UTF-8, how to do it all in order. , so, let's begin!

1. Unpacking the wsp file (.cab) It is suitable to use archivers such as 7-Zip or WinRAR. Name solution is "Exaction.ListSearch.wsp", The screenshot shows that its web part is in English.



Right-click on our wsp file and select Unpacking in "Exaction.ListSearch" open this folder and will see manifest, dll-file and another folder related to the project (Features, Layouts, CONTROLTEMPLATES).


2. To change a web part from English to Russian to open folder "CONTROLTEMPLATES" with extension ".ascx". Open this file via notepad editor and change text on "Russian names".



Save As and change Encoding on UTF-8.



3. Now is download makeddf 1.0.1 in the same folder (you can in another, but you will have to specify the full path to the file makeddf.exe).

4. Open is PowerShell ISE editor (or Command Promt) run as Administrator and insert this command:

#Get path
cd "C:\wsp\Exaction.ListSearch"
#Create ddf-file
C:\wsp\Exaction.ListSearch\makeddf.exe /p Exaction.ListSearch /d Exaction.ListSearch.ddf /c Exaction.ListSearch.cab
#Set cab-file
makecab /f Exaction.ListSearch.ddf

5. Run command to get path cd "C:\wsp\Exaction.ListSearch"

6. Run command to create ddf-file: C:\wsp\Exaction.ListSearch\makeddf.exe /p Exaction.ListSearch /d Exaction.ListSearch.ddf /c Exaction.ListSearch.cab


7. Run command to create cab-file: makecab /f Exaction.ListSearch.ddf.


8. Rename file "Exaction.ListSearch.cab" on "Exaction.ListSearch.wsp".

9. Copy file "Exaction.ListSearch.wsp" into SharePoint server and Open is PowerShell ISE editor run as Administrator then add and run 2 command:

#Add PSSnapin Microsoft SharePoint
Add-pssnapin Microsoft.sharepoint.powershell
#Update Solutions
Update-SPSolution –Identity Exaction.ListSearch.wsp –LiteralPath C:\Wsp\NewListSearch\Exaction.ListSearch.wsp –GACDeployment -FullTrustBinDeployment
We are waiting for IIS to restart and open our web part, congratulations, everything works!


Happy Coding!

Thursday, January 24, 2019

Highlighting list items with .NET and CSR (Employee Vacation Project) on SharePoint server 2013, 2016

Hello everyone, in this article I will talk about the project in which I needed to highlight the elements of the list that matched by dates and categories. All of us go on vacation from time to time and someone may substitute us for the time of our absence, however, we need to see whether the period of time for vacation for employees in one category (for example, SharePoint developers) or not, for this task, I need a list of Calendar, columns Title, Category (lookup another list column), Start Time, End Time and Flag (hidden). I create several elements of the list (employees) with a start and end date, some leave vacation days.
The main advantage of this code is the use of C#, which means such features are available as Visual Web Part and JSLink (CSR).




Lets get started!

1. Open the visual studio 2012 or 2015 as run as administrator on SharePoint server (my example on SharePoint server 2013 OnPremise). 
2. Create an SharePoint server 2013 - Visual Web Part (name Project: "CalendarDatePeriods").



3. Set URL and Select a Farm Solution.



4. Add reference in the Project Microsoft.CSharp.

5. Open file "VisualWebPart1UserControl.ascx.cs".



6. Remove code "protected void Page_Load(object sender, EventArgs e){ }".

7. Add this code (Do not forget that the URL of the server and the name of the list may differ from yours!):
public class Item
 {
   public Int32 ID { get; set; }
   public string Title { get; set; }
   public string Category { get; set; }
   public DateTime StartTime { get; set; }
   public DateTime EndTime { get; set; }
 }
    //Class declaration array
    public class RootObject
    {
        public RootObject()
         {
            items = new List<Item>();
         }
            public List<Item> items { get; set; }
     }
         //Load page
         protected void Page_Load(object sender, EventArgs e)
          {
            //create int array
            List<int> ID_array = new List<int>();
            //GetListAllItems
            using (SPSite site = new SPSite("http://sp-test/sites/eng"))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    web.AllowUnsafeUpdates = true;
                    string listUrl = web.ServerRelativeUrl + "/lists/Calendar";
                    SPList list = web.GetList(listUrl);
                    SPView view = list.Views["All Events"];
                    SPListItemCollection items = list.GetItems(view);
                    //Run class RootObject
                    RootObject objs = new RootObject();
                    foreach (SPListItem item in items)
                    {
                        //Add items to array
                        objs.items.Add(new Item
                        {
                            ID = Int32.Parse(item["ID"].ToString()),
                            Title = item["Title"].ToString(),
                            Category = item["Category"].ToString(),
                            StartTime = DateTime.Parse(item["Start Time"].ToString()),
                            EndTime = DateTime.Parse(item["End Time"].ToString()),
                        });
                    }
                    //Filter array DateTime periods
                    var array = objs.items;
                    for (int i = 0; i < array.Count - 1; i++)
                    {
                        for (int j = i + 1; j < array.Count; j++)
                        {
                            var p1 = array[i];
                            var p2 = array[j];
                            if (p1.Category != "1;#-" && p2.Category != "1;#-")
                            {
                                if (p1.Category != p2.Category)
                                    continue;
                                if (!(p1.StartTime > p2.EndTime || p2.StartTime > p1.EndTime))
                                {
                                    ID_array.Add(p1.ID);
                                    ID_array.Add(p2.ID);
                                    ID_array.Distinct().ToArray();
                                }
                            }
                        }
                    }
                    //Update List Item to DateTime period
                    for (int x = 0; x < ID_array.Count; x++)
                    {
                        using (SPSite osite = new SPSite("http://sp-test/sites/eng"))
                        {
                            using (SPWeb oweb = site.OpenWeb())
                            {
                                SPList olist = oweb.Lists["Calendar"];
                                SPListItemCollection oitems = list.GetItems(new SPQuery()
                                {
                                    Query = @"<Where><Eq><FieldRef Name='ID' /><Value Type='Int'>" + ID_array[x] + "</Value></Eq></Where>"
                                });

                                foreach (SPListItem item in oitems)
                                {
                                    item["Flag"] = "Yes";
                                    item.Update();
                                }
                            }
                        }
                    }
                }
            }
        }
8. Add reference in the lines where the code is highlighted in red, he will suggest.

using System;

using Microsoft.SharePoint;

using System.Collections.Generic;

using System.Linq;

using System.Web.UI;

9. If no errors are detected in the project, then do "Deploy Solution".
10. After the project is published on the server, IIS is restarted and you need to wait a couple of minutes if you need to make sure that the project has been published successfully, follow the link: http://your_sharepoint_server:port/_admin/Solutions.aspx and see your solution "calendardateperiods.wsp" status "Deployed". Then restart our list and click to "Property" -> "Edit Page":



"Add a Web Part" -> Categories "Custom" -> Add "CalendarDatePeriods - VisualWebPart1":



We added a web part and immediately saw that in the "Flag" column, for elements that match in categories and dates, the value is "Yes". This means our code is working successfully.



To highlight the color of elements whose values match, we use CSR (JSlink) and add it via the Content Editor Web Part. We need to add item in library "Site Assets" "jquery-2.1.3.min.js", then create JavaScript-file DateCSR.js in which you need to add the code allocated by our elements and "Flag" hiding column:

<script type="text/javascript" src="/sites/eng/SiteAssets/jquery-2.1.3.min.js"></script>
<script type="text/javascript">
(function () { 
    var priorityFiledContext = {}; 
    priorityFiledContext.Templates = {}; 
    priorityFiledContext.Templates.Fields = {  
        "EventDate": { 
            "View": EventDateFiledTemplate 
        },
        "EndDate": { 
            "View": EndDateFiledTemplate 
        }
    }; 
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(priorityFiledContext);
})();
(function () { 
    var linkFiledContext = {}; 
    linkFiledContext.Templates = {}; 
    linkFiledContext.OnPostRender = linkOnPostRender;
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(linkFiledContext);
})();
function linkOnPostRender(ctx) 
{ 
    var linkCloumnIsEmpty = 1;
    for (i = 0; i < ctx.ListData.Row.length; i++) { 
        if (ctx.ListData.Row[i]["Flag"]) 
        { 
            linkCloumnIsEmpty = 1; 
            break; 
        } 
    } 
    if (linkCloumnIsEmpty) {
        var cell = $("div [name='Flag']").closest('th'); 
        var cellIndex = cell[0].cellIndex + 1;
        $('td:nth-child(' + cellIndex + ')').hide(); 
        $('th:nth-child(' + cellIndex + ')').hide(); 
    }
}
function EventDateFiledTemplate(ctx) {
    var Flag = ctx.CurrentItem.Flag;
    var EventDate = ctx.CurrentItem.EventDate;
    if (Flag == "Yes"){
       return "<span style='color :red'>" + EventDate + "</span>";
    } else {
          return "<span style='color :green'>" + EventDate + "</span>";
    }        
}
  function EndDateFiledTemplate(ctx) {
    var Flag = ctx.CurrentItem.Flag;
    var EndDate = ctx.CurrentItem.EndDate; 
    if (Flag == "Yes"){
         return "<span style='color :red'>" + EndDate + "</span>";
    } else {
        return "<span style='color :green'>" + EndDate + "</span>";
    }
}
</script>
"Add a Web Part" -> Category "Media and content" -> Add "Content Editor":



Add script "Content link" url, your JavaScript-file('/sites/eng/SiteAssets/DateCSR.js') and "Apply"



And we see our result, the most important thing is that this solution allows you to work with a large number of list items (I used more than 1000), without delays and timeouts. Additionally, you can modify this solution to suit your requirements; you can add an Event Reciever to create, modify, or delete list items with similar logic.


Happy Coding!

Tuesday, December 18, 2018

Create Custom Action "Copy URL document" to ECB menu

In this article, I created a solution for the ECB menu, where the short URL of the document is copied and inserted for example into a letter to the recipient send to email. Create JavaScript file and save in library "SiteAssets", using JQuery (version jquery-2.1.3.min.js). Add code your file:
<script type="text/javascript" src="/sites/test/SiteAssets/jquery-2.1.3.min.js"></script>
<script type="text/javascript">
function Custom_AddDocLibMenuItems(m, ctx)
    {
	      $("#where_to_insert").hide();
	      var strDisplayText = "Copy URL document";
	      var url = '';
	      var spans = $('#where_to_insert');
		  spans.text('');
		  function getlist() {
			var requestUri = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getByTitle('Documents')/items?$select=EncodedAbsUrl,FileLeafRef&$filter=Id eq " + currentItemID;
			var requestHeaders = {
			    "accept": "application/json;odata=verbose"
			}
			$.ajax({
			    url: requestUri,
			    type: 'GET',
			    dataType: 'json',
			    headers: requestHeaders,
			    success: function (data) 
			    {        
			       $.each(data.d.results, function(i,result) {
		            var EncodedAbsUrl = result.EncodedAbsUrl;
		            var link = document.createElement('a');
		            if (EncodedAbsUrl != null) {
		                link.href = EncodedAbsUrl;
		              } 
		            var FileLeafRef = result.FileLeafRef;
		            link.textContent = FileLeafRef;
		            var url = document.getElementById('where_to_insert').appendChild(link);
			    copy();
			    });
			       	function copy() {
				      var target = document.getElementById('where_to_insert');
				      var range, select;
				      if (document.createRange) {
				        range = document.createRange();
				        range.selectNode(target)
				        select = window.getSelection();
				        select.removeAllRanges();
				        select.addRange(range);
				        document.execCommand('copy');
				        select.removeAllRanges();
				      } else {
				        range = document.body.createTextRange();
				        range.moveToElementText(target);
				        range.select();
				        document.execCommand('copy');
				      }
				    }
			    },
			    error: function ajaxError(response) {
			        alert(response.status + ' ' + response.statusText);
			    }
			 });
		}
      	CAMOpt(m, strDisplayText, getlist(), strDisplayText.link);
      	CAMSep(m);
      }
</script>
<span id="where_to_insert"></span>
and save it.

"Edit Page to library -> Add a Web Part" -> Category "Media and content" -> Add "Content Editor":



Content Editor "Edit Web Part" add to your JavaScript file:



Check our solution after reloading the page, click to "Open Menu" and again "Open Menu" click item menu "Copy URL document":



Insert your copy into to Outlook messages:



If you hover the mouse over the link, it will see the URL of the document, and if you click, you will go to it by the link.
Happy Coding!

Thursday, October 11, 2018

Copying list items with metadata (history) to another list (SharePoint 2010, 2013, 2016)

In this article, I continue to sort out the tasks associated with transferring data from one source to another while preserving all the information. This time I published a sample code where I copy the list items with the whole story (metadata) into another list.

The main advantage of this code is the use of C#, which means such wonderful features are available as Custom Timer Job, Event Reciever and much more. In my console project I using following reference and code:

using System;

using Microsoft.SharePoint;

using Microsoft.SharePoint.Utilities;

1. Current site:
using (SPSite oSPsite = new SPSite("http://sp/sites/test"))
            {
                using (SPWeb oSPWeb = oSPsite.OpenWeb())
                {
                    //List source
                    SPList srcList = oSPWeb.Lists["Users1"];
                    //List destination
                    SPList destList = oSPWeb.Lists["Users2"];
                    foreach (SPListItem sourceItem in srcList.Items)
                    {
                        SPListItem targetItem = destList.AddItem();
                        for (int i = sourceItem.Versions.Count - 1; i >= 0; i--)
                        {
                            SPListItemVersion sourceField = sourceItem.Versions[i];
                            targetItem["Author"] = sourceField["Author"];
                            targetItem["Title"] = sourceField["Title"];
                            targetItem["Editor"] = sourceField["Editor"];
                            targetItem[SPBuiltInFieldId.Modified] = GetFieldValueAsDate(sourceField["Modified"]);
                            targetItem[SPBuiltInFieldId.Created] = GetFieldValueAsDate(sourceField["Created"]);
                            targetItem.Update();
                        }
                    }
                }
  private static String GetFieldValueAsDate(object sourceField)
        {
            string result = string.Empty;
            if (sourceField != null)
            {
                DateTime date = Convert.ToDateTime(sourceField);
                if (date.Year > 1900)
                    result = SPUtility.CreateISO8601DateTimeFromSystemDateTime(date);
            }
            return result;
        }
    }
}
2. Another site:
//Site source
using (SPSite oSPsite = new SPSite("http://sp/sites/test"))
 {
   using (SPWeb oSPWeb = oSPsite.OpenWeb())
    {
      //List source
      SPList srcList = oSPWeb.Lists["Test1"];
       //Site destination
       using (SPSite SPsite = new SPSite("http://sp/sites/RU_test"))
         {
           using (SPWeb SPWeb = SPsite.OpenWeb())
            {
              //List destination 
              SPList destList = SPWeb.Lists["Test2"];
                foreach (SPListItem sourceItem in srcList.Items)
                  {
                    SPListItem targetItem = destList.AddItem();
                      for (int i = sourceItem.Versions.Count - 1; i >= 0; i--)
                        {
                           SPListItemVersion sourceField = sourceItem.Versions[i];
                            targetItem["Author"] = sourceField["Author"];
                            targetItem["Title"] = sourceField["Title"];
                            targetItem["Editor"] = sourceField["Editor"];
                            targetItem[SPBuiltInFieldId.Modified] = GetFieldValueAsDate(sourceField["Modified"]);
                            targetItem[SPBuiltInFieldId.Created] = GetFieldValueAsDate(sourceField["Created"]);
                            targetItem.Update();
                        }
                    }
                }
            }
        }
     }
  }
private static String GetFieldValueAsDate(object sourceField)
        {
            string result = string.Empty;
            if (sourceField != null)
            {
                DateTime date = Convert.ToDateTime(sourceField);
                if (date.Year > 1900)
                    result = SPUtility.CreateISO8601DateTimeFromSystemDateTime(date);
            }
            return result;
        }
    }
}
Happy Coding!

Friday, October 5, 2018

Moving/copying file with version history to another library (SharePoint 2010, 2013, 2016)

Recently, I had to copy an archive of documents from one collection of sites to another, I didn’t have any problems with PowerShell, thanks to Import\Export, but the task changed when the question arose about transferring several large documents with a long history of versioning from one library to another. I tried to find a solution without a code, but did not find anything, and suddenly in one forum I saw a small piece of code that solved my problems, in this article I will share it and tell you a little.

The main advantage of this code is the use of C#, which means such wonderful features are available as Custom Timer Job, Event Reciever and much more. In my console project I using following reference and code:

using System;

using Microsoft.SharePoint;

using System.IO;

using System.Collections;

//Get SPSite or Site Collection
using (SPSite oSPsite = new SPSite("http://sp/sites/test")){
 using (SPWeb oSPWeb = oSPsite.OpenWeb())
  {
   //Get Library source
   SPList lib_source = oSPWeb.Lists["Library1"];
   //Get Library destination
   SPList lib_destination = (SPDocumentLibrary)oSPWeb.Lists["Library2"];
   //Get item (file) using SPQuery
   SPListItemCollection items = lib_source.GetItems(new SPQuery()
    {
     Query = @"<Where><Eq><FieldRef Name='FileLeafRef'/><Value Type='Text'>Document.docx</Value></Eq></Where>"
      });
         foreach (SPListItem item in items) {
           SPFile fileSource = item.File;
           //Get the created by and created
           SPUser userCreatedBy = fileSource.Author;
           //Convert the "TimeCreated" property to local time
           DateTime dateCreatedOn = fileSource.TimeCreated.ToLocalTime();
           //Get the versions history
           int countVersions = item.File.Versions.Count;
              for (int i = 0; i <= countVersions; i++)
                {
                  Hashtable hashSourceProp;
                  Stream streamFile;
                  SPUser userModifiedBy;
                  DateTime dateModifiedOn;
                  string strVerComment = "";
                  bool bolMajorVer = false;
                    if (i < countVersions)
                     {
                      //Get all versions file, history, properties, createdBy, checkInComment
                      SPFileVersion fileSourceVer = item.File.Versions[i];
                      hashSourceProp = fileSourceVer.Properties;
                      userModifiedBy = (i == 0) ? userCreatedBy : fileSourceVer.CreatedBy;
                      dateModifiedOn = fileSourceVer.Created.ToLocalTime();
                      strVerComment = fileSourceVer.CheckInComment;
                      bolMajorVer = fileSourceVer.VersionLabel.EndsWith("0") ? true : false;
                      streamFile = fileSourceVer.OpenBinaryStream();
                     } else {
                       //Get current versions file, history, properties, createdBy, checkInComment
                       userModifiedBy = fileSource.ModifiedBy;
                       dateModifiedOn = fileSource.TimeLastModified;
                       hashSourceProp = fileSource.Properties;
                       strVerComment = fileSource.CheckInComment;
                       bolMajorVer = fileSource.MinorVersion == 0 ? true : false;
                       streamFile = fileSource.OpenBinaryStream();
                     }
                       //URL library destination
                       string urlDestFile = lib_destination.RootFolder.Url + "/Folder/" + fileSource.Name;
                       //Copy all properties
                       SPFile fileDest = lib_destination.RootFolder.Files.Add(
                         urlDestFile,
                         streamFile,
                         hashSourceProp,
                         userCreatedBy,
                         userModifiedBy,
                         dateCreatedOn,
                         dateModifiedOn,
                         strVerComment,
                         true);
                          if (bolMajorVer)
                             fileDest.Publish(strVerComment);
                          else
                            {
                             SPListItem itmNewVersion = fileDest.Item;
                             itmNewVersion["Created"] = dateCreatedOn;
                             itmNewVersion["Modified"] = dateModifiedOn;
                             itmNewVersion.UpdateOverwriteVersion();
                            }                  
                        }
                    }
                }
            }
Happy Coding!

Wednesday, August 8, 2018

Using CSR in List Items (SharePoint server 2013, 2016)

All of us have become very advanced users and of course we use various messengers for calls, such as Skype and many others, so users need to make a call. In my case, the contact information was in the SharePoint list, i.e. there was all the information including the email and of course the phones. In the list view, I see all users and their phones, but how do I call the phone number with a simple click, the more Skype is active? To help me came "CSR".

How is create of this solution, lets get started!

In my list 2 columns "Title" and "CellPhone", I was add 5 items (Users):


We need to add 2 items in library "Site Assets" "jquery-2.1.3.min.js" and picture size 16*16 (Metro-Phone-Blue-16.png), then create JavaScript-file CellPhone.js, open it and add code, where we using "Clien-Side rendering" and save it
<script type="text/javascript" src="/sites/test/SiteAssets/jquery-2.1.3.min.js"></script>
<script type="text/javascript">
(function () { 
    var linkFilenameFiledContext = {}; 
    linkFilenameFiledContext.Templates = {}; 
    linkFilenameFiledContext.Templates.Fields = { 
        "CellPhone": { "View": linkFilenameFiledTemplate } 
    };
    SPClientTemplates.TemplateManager.RegisterTemplateOverrides(linkFilenameFiledContext); 
})(); 

function linkFilenameFiledTemplate(ctx) {
    var title = ctx.CurrentItem["CellPhone"];
    var phone = ctx.CurrentItem["CellPhone"];
    title = title.replace(/\.[^/.]+$/, "") 
    if (phone != '') {
        return title + " <a href=" + "'callto: +7 " + phone + "'><img src='/sites/test/SiteAssets/Metro-Phone-Blue-16.png'/ title='Call number'></a>"; 
    } 
}
</script>
and save it:


"Add a Web Part" -> Category "Media and content" -> Add "Content Editor":



Content Editor "Edit Web Part"



Add script "Content link" url, your JavaScript-file('/sites/test/SiteAssets/CellPhone.js') and "Apply"



Refresh Page your list and we will see:



Click the button phone, call to Skype:



Happy Coding!

Tuesday, August 7, 2018

SharePoint migration (2010, 2013, 2016) errors correction

Many of us have faced migration to the new version SharePoint server and, of course, not without exception, experienced difficulties with errors, today I will describe the mistakes I personally encountered and try to show one or more solutions.

We have already attached the database to MS SQL Server and open Windows PowerShell ISE (run as Administrator). Make sure that the account under which we work has system account rights on the current farm SharePoint server and db_owner for a migrated database.
Now add script "Add-PSSnappin":

Add-pssnapin Microsoft.sharepoint.powershell

Now add script "Test-SPContentDatabase", if you need comfortable view use "Out-GridView"

Test-SPContentDatabase -Name WSS_ContentSPS -WebApplication http://sp-test | Out-GridView
OR export data to file "Export-Csv"
Test-SPContentDatabase -Name WSS_ContentSPS -WebApplication http://sp-test | Export-Csv -path 'C:\TestMigration_WSSContentSPS_07.08.2018.csv' -Encoding unicode -Delimiter "`t"
Run script and will see error:

Category : MissingAssembly
Error : True
UpgradeBlocking : False
Message : Assembly
[Microsoft.ReportingServices.SharePoint.UI.ServerPages,
Version=14.0.0.0, Culture=neutral,
PublicKeyToken=89845dcd8080cc91] is referenced in the
database [WSS_ContentSPS], but is not installed on the
current farm. Please install any feature/solution which
contains this assembly.
Remedy : One or more assemblies are referenced in the database
[WSS_ContentSPS], but are not installed on the current
farm. Please install any feature or solution which contains
these assemblies.


How is the fix? You can install the solution or if you are sure that you do not need this solution on the current farm, then you can delete it via T-SQL, first open MS SQL Management studio, click create query and select the database you need, then add script (you need table "EventReceivers" -> column "Assembly")
Select * from EventReceivers where Assembly like '%Microsoft.ReportingServices.SharePoint.UI.ServerPages,Version=14.0.0.0,Culture=neutral,PublicKeyToken=89845dcd8080cc91%'
We are convinced that this solution is really present and then delete:
Delete from EventReceivers where Assembly like '%Microsoft.ReportingServices.SharePoint.UI.ServerPages,Version=14.0.0.0,Culture=neutral,PublicKeyToken=89845dcd8080cc91%'


Category : MissingFeature
Error : True
UpgradeBlocking : False
Message : Database
[WSS_Content] has reference(s) to a missing feature: Id = [bf8b58f5-ebae-4a70-9848-622beaaf2043],
Name = [Power View Integration Feature], Description = [Enables interactive data exploration and visual presentation against PowerPivot workbooks and Analysis Services tabular databases.],
Install Location = [PowerView]."
","The feature with Id bf8b58f5-ebae-4a70-9848-622beaaf2043 is referenced in the database [WSS_Content]
but is not installed on the current farm.
The missing feature may cause upgrade to fail. Please install any solution which contains the feature and restart upgrade if necessary."


Is the addin for "SSRS installed" in your new farm.

Category : MissingWebPart
Error : True
UpgradeBlocking : False
Message : WebPart class
[6a1f4b36-329d-317b-802a-96130a9ae5e7] (class [Microsoft.SharePoint.Portal.WebControls.BusinessDataFilterWebPart] from assembly
[Microsoft.SharePoint.Portal, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c]) is referenced [1] times in the database [WSS_Content], but
is not installed on the current farm. Please install any feature/solution which contains this web
part.","One or more web parts are referenced in the database [WSS_Content], but are not installed
on the current farm. Please install any feature or solution which contains these web parts."


Category : MissingWebPart
Error : True
UpgradeBlocking : False
Message : WebPart class
MissingWebPart,"True","False","WebPart class [69a2a58c-9b8d-d5c5-a7f6-a0feeeaf3867] (class
[Microsoft.SharePoint.Portal.WebControls.SpListFilterWebPart] from assembly
[Microsoft.SharePoint.Portal, Version=15.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c]) is referenced [10] times in the database [WSS_Content],
but is not installed on the current farm. Please install any feature/solution which contains this web part."


After you migrate the sites on Microsoft SharePoint Server 2013 to SharePoint Server 2016, the following web part controls no longer work on the migrated sites:

SpListFilterWebPart;
ExcelWebRenderer;
ReportViewerWebpart;

"Web part controls don't work after sites are migrated to SharePoint 2016."

Solutions: add your file web.config 2 row:
<SafeControl Assembly="Microsoft.SharePoint.Portal, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" Namespace="Microsoft.SharePoint.Portal.WebControls" TypeName="SpListFilterWebPart" Safe="True" />
<SafeControl Assembly="Microsoft.SharePoint.Portal, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" Namespace="Microsoft.SharePoint.Portal.WebControls" TypeName="BusinessDataFilterWebPart" Safe="True" />

To be continued,
Happy Coding!

Monday, August 6, 2018

Ribbons Customization in SharePoint 2013 (List Items Approved or Rejected)

In my first article I'll demonstrate how to create a project in Visual Studio for MS SharePoint server 2013 and make the buttons for authorization (Approve and Reject) in Ribbon for updating of list/library items.

In one of the projects I was asked to make it possible to authorize the list/library items when selecting these elements with the mouse in the list itself without opening one of the forms. Such a decision seemed to me interesting and I studied the CSOM with the possibility of a method SP.ListOperation.Selection.getSelectedItems().
var context = SP.ClientContext.get_current();
var selectedItemIds = SP.ListOperation.Selection.getSelectedItems(context);
It allows you to work directly with the list items when you select a click.



Further in the screenshots you can see that when you select multiple items and when you click button "Approved Items" or "Rejected Items", depending on the authorization logic the selected list items are updated.

Select "Title2" (Rejected) and "Title3" (Approved), click button "Approved Items, then will see: "Title3 is Approved"" and "Title2 successfully Approved".





How is create of this solution, lets get started:

1. Open the visual studio 2012 or 2015 as run as administrator. 
2. Create an Empty SharePoint Project 2013.



3. Let the name be "RibbonCustomActionExample".
4. Select a Farm Solution.



5. Add New Item to the solution (Module).



6. Add 2 Module. Name it as ApprovedCA



and RejectedCA



7. Then Add New Item to the solution (SharePoint "Layouts" Mapped Folder).



8. Rename folder "Layouts" in "Scripts".



9. Add New Item to folder "Scripts".



10. JavaScript-file name "script.js".



11. Open JavaScript-file "script.js" and add to code:
function getSelectedItems(OnSuccess, OnError) {
    var context = SP.ClientContext.get_current();
    var listId = SP.ListOperation.Selection.getSelectedList();
    var selectedItemIds = SP.ListOperation.Selection.getSelectedItems(context);
    var list = context.get_web().get_lists().getById(listId);
    var listItems = [];
    for (idx in selectedItemIds) {
        var item = list.getItemById(parseInt(selectedItemIds[idx].id));
        listItems.push(item);
        context.load(item);
    }
    context.executeQueryAsync(
       function () {
           OnSuccess(listItems);
       },
       OnError
    );
}
function RejectedItems() {
    var context = SP.ClientContext.get_current();
    var selectedItems = SP.ListOperation.Selection.getSelectedItems(context);
    var ListGUID = SP.ListOperation.Selection.getSelectedList();
    var clientContext = new SP.ClientContext.get_current();
    var targetList = clientContext.get_web().get_lists().getById(ListGUID);
    var itemArray = [];
    var itemAllertNo = [];
    var itemAllertYes = [];
    getSelectedItems(function (items) {
        for (var i = 0 ; i < items.length; i++) {
            if ((items[i].get_item('Test') == "Rejected")) {
                itemAllertNo.push(items[i].get_item('Title'));
            } else {
                var oListItem = targetList.getItemById(selectedItems[i].id);
                oListItem.set_item('Test', 'Rejected');
                oListItem.update();
                itemArray[i] = oListItem;
                clientContext.load(itemArray[i]);
                itemAllertYes.push(items[i].get_item('Title'));
                clientContext.executeQueryAsync(onQueryFailed);
            }
        }
        if (itemAllertNo != '') {
            alert("List items " + itemAllertNo + " is rejected!");
        }
        if (itemAllertYes != '') {
            alert("List items " + itemAllertYes + " successfully rejected!");
            window.location.reload();
        }
    },
        function (sender, args) {
            alert('An error occured: ' + args.get_message());
        });
}
function ApprovedItems() {
    var context = SP.ClientContext.get_current();
    var selectedItems = SP.ListOperation.Selection.getSelectedItems(context);
    var ListGUID = SP.ListOperation.Selection.getSelectedList();
    var clientContext = new SP.ClientContext.get_current();
    var targetList = clientContext.get_web().get_lists().getById(ListGUID);
    var itemArray = [];
    var itemAllertNo = [];
    var itemAllertYes = [];
    getSelectedItems(function (items) {
        for (var i = 0 ; i < items.length; i++) {
            if ((items[i].get_item('Test') == "Aproved")) {
                itemAllertNo.push(items[i].get_item('Title'));
            } else {
                var oListItem = targetList.getItemById(selectedItems[i].id);
                oListItem.set_item('Test', 'Aproved');
                oListItem.update();
                itemArray[i] = oListItem;
                clientContext.load(itemArray[i]);
                itemAllertYes.push(items[i].get_item('Title'));
                clientContext.executeQueryAsync(onQueryFailed);
            }
        }
        if (itemAllertNo != '') {
            alert("List items " + itemAllertNo + " is approved!");
        }
        if (itemAllertYes != '') {
            alert("List items " + itemAllertYes + " successfully approved!");
            window.location.reload();
        }
    },
        function (sender, args) {
            alert('An error occured: ' + args.get_message());
        });
}
function onQueryFailed(sender, args) {
    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}
12. Open the Elements.xml in module ApprovedCA and remove default code



13. Add to code in this Elements.xml (ApprovedCA):
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="f110dac1-9797-4959-8596-2161fb5a3cb1.RibbonCustomAction"
RegistrationType="List"
RegistrationId="100"
Location="CommandUI.Ribbon"
Sequence="10001"
Title="New Action Command">
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition Location="Ribbon.ListItem.Actions.Controls._children">
<Button Id="Approved Items"
Alt="Request RibbonCustomAction"
Sequence="100"
Command="New Action Command"
LabelText="Approved Items"
TemplateAlias="o1"
Image32by32="/_layouts/15/1033/images/formatmap32x32.png?rev=23" Image32by32Left="-375" Image32by32Top="-511"
Image16by16="/_layouts/15/1033/images/formatmap32x32.png?rev=23" Image16by16Left="-375" Image16by16Top="-511" />
</CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler Command="New Action Command"
CommandAction="javascript: ApprovedItems();"
EnabledScript="var EnableDisableItem = function()
{
this.clientContext = SP.ClientContext.get_current();  
                              this.selectedItems = SP.ListOperation.Selection.getSelectedItems(this.clientContext);
if (selectedItems.length==1)  {
if (selectedItems[0].fsObjType == 0)
{return true;}
else
{return false;}
}
if (selectedItems.length!=1)
{return false;}
};
EnableDisableItem();"/>
</CommandUIHandlers>
</CommandUIExtension >
</CustomAction>
<CustomAction
ScriptSrc="Scripts/script.js"
Location="ScriptLink"
Sequence="100">
</CustomAction>
</Elements>

14. Open the Elements.xml in module RejectedCA, remove default code and add to code in Elements.xml:
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="f110dac1-9797-4959-8596-2161fb5a3cb2.RibbonCustomAction"
RegistrationType="List"
RegistrationId="100"
Location="CommandUI.Ribbon"
Sequence="10001"
Title="Invoke 'RibbonCustomAction' action">
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition Location="Ribbon.ListItem.Actions.Controls._children">
<Button Id="New Action Command"
Alt="Request RibbonCustomAction"
Sequence="100"
Command="Invoke_RibbonCustomActionButtonRequest"
LabelText="Rejected Items"
TemplateAlias="o1"
Image32by32="/_layouts/15/1033/images/formatmap32x32.png?rev=23" Image32by32Left="-375" Image32by32Top="-511"
Image16by16="/_layouts/15/1033/images/formatmap32x32.png?rev=23" Image16by16Left="-375" Image16by16Top="-511" />
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler Command="Invoke_RibbonCustomActionButtonRequest"
CommandAction="javascript: RejectedItems();"
EnabledScript="var EnableDisableItem = function()
{
this.clientContext = SP.ClientContext.get_current();
this.selectedItems = SP.ListOperation.Selection.getSelectedItems(this.clientContext);
if (selectedItems.length==1)  {
if (selectedItems[0].fsObjType == 0)
{return true;}
else
{return false;}
}
if (selectedItems.length!=1)
{return false;}
};
EnableDisableItem();  "/>
</CommandUIHandlers>
</CommandUIExtension>
</CustomAction>
<CustomAction
ScriptSrc="Scripts/script.js"
Location="ScriptLink"
Sequence="100">
</CustomAction>
</Elements>
15. Then Build -> "Deploy Solution" and check current solution.

Happy Coding!