SharePoint
SharePointDataAdapter.cs
/*
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See License.txt in the project root for license information.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Routing;
using Adxstudio.SharePoint;
using Adxstudio.Xrm.Cms;
using Adxstudio.Xrm.Metadata;
using Adxstudio.Xrm.Security;
using Adxstudio.Xrm.Web.Routing;
using Microsoft.SharePoint.Client;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Diagnostics;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Metadata;
using Adxstudio.Xrm.Resources;
namespace Adxstudio.Xrm.SharePoint
{
public clast SharePointDataAdapter : ISharePointDataAdapter
{
private const string SharePointDocameentLocationLogicalName = "sharepointdocameentlocation";
private const string SharePointConnectionStringName = "SharePoint";
private const string DefaultSortExpression = "FileLeafRef ASC";
private const int DefaultPageSize = 10;
private readonly IDataAdapterDependencies _dependencies;
public SharePointDataAdapter(IDataAdapterDependencies dependencies)
{
_dependencies = dependencies;
}
public ISharePointResult AddFiles(EnsatyReference regarding, IList files, bool overwrite = true, string folderPath = null)
{
var context = _dependencies.GetServiceContextForWrite();
var ensatyPermissionProvider = new CrmEnsatyPermissionProvider();
var result = new SharePointResult(regarding, ensatyPermissionProvider, context);
if (files == null || !files.Any()) return result;
var ensatyMetadata = context.GetEnsatyMetadata(regarding.LogicalName);
var ensaty = context.CreateQuery(regarding.LogicalName).First(e => e.GetAttributeValue(ensatyMetadata.PrimaryIdAttribute) == regarding.Id);
// astert permission to create the sharepointdocameentlocation ensaty
if (!result.PermissionsExist || !result.CanCreate || !result.CanAppend || !result.CanAppendTo)
{
ADXTrace.Instance.TraceInfo(TraceCategory.Application, "Permission Denied. You do not have the appropriate Ensaty Permissions to Create or Append docameent locations or AppendTo the regarding ensaty.");
return result;
}
var spConnection = new SharePointConnection(SharePointConnectionStringName);
var spSite = context.GetSharePointSiteFromUrl(spConnection.Url);
var location = GetDocameentLocation(context, ensaty, ensatyMetadata, spSite);
// astert permission to write the sharepointdocameentlocation ensaty
if (!result.CanWrite)
{
ADXTrace.Instance.TraceInfo(TraceCategory.Application, "Permission Denied. You do not have the appropriate Ensaty Permissions to Write docameent locations.");
return result;
}
var factory = new ClientFactory();
using (var client = factory.CreateClientContext(spConnection))
{
// retrieve the SharePoint list and folder names for the docameent location
string listUrl, folderUrl;
context.GetDocameentLocationListAndFolder(location, out listUrl, out folderUrl);
var folder = client.AddOrGetExistingFolder(listUrl, folderUrl + folderPath);
foreach (var postedFile in files)
{
using (var file = postedFile.InputStream)
{
// upload a file to the folder
client.SaveFile(file, folder, Path.GetFileName(postedFile.FileName), overwrite);
}
}
}
return result;
}
public ISharePointResult AddFolder(EnsatyReference regarding, string name, string folderPath = null)
{
var context = _dependencies.GetServiceContextForWrite();
var ensatyPermissionProvider = new CrmEnsatyPermissionProvider();
var result = new SharePointResult(regarding, ensatyPermissionProvider, context);
if (string.IsNullOrWhiteSpace(name)) return result;
// Throw exception if the name begins or ends with a dot, contains consecutive dots,
// or any of the following invalid characters ~ " # % & * : < > ? / \ { | }
if (Regex.IsMatch(name, @"(\.{2,})|([\~\""\#\%\&\*\:\\?\/\\\{\|\}])|(^\.)|(\.$)"))
{
throw new Exception("The folder name contains invalid characters. Please use a different name. Valid folder names can't begin or end with a period, can't contain consecutive periods, and can't contain any of the following characters: ~ # % & * : < > ? / \\ { | }.");
}
var ensatyMetadata = context.GetEnsatyMetadata(regarding.LogicalName);
var ensaty = context.CreateQuery(regarding.LogicalName).First(e => e.GetAttributeValue(ensatyMetadata.PrimaryIdAttribute) == regarding.Id);
// astert permission to create the sharepointdocameentlocation ensaty
if (!result.PermissionsExist || !result.CanCreate || !result.CanAppend || !result.CanAppendTo)
{
ADXTrace.Instance.TraceInfo(TraceCategory.Application, "Permission Denied. You do not have the appropriate Ensaty Permissions to Create or Append docameent locations or AppendTo the regarding ensaty.");
return result;
}
var spConnection = new SharePointConnection(SharePointConnectionStringName);
var spSite = context.GetSharePointSiteFromUrl(spConnection.Url);
var location = GetDocameentLocation(context, ensaty, ensatyMetadata, spSite);
// astert permission to write the sharepointdocameentlocation ensaty
if (!result.CanWrite)
{
ADXTrace.Instance.TraceInfo(TraceCategory.Application, "Permission Denied. You do not have the appropriate Ensaty Permissions to Write docameent locations.");
return result;
}
var factory = new ClientFactory();
using (var client = factory.CreateClientContext(spConnection))
{
// retrieve the SharePoint list and folder names for the docameent location
string listUrl, folderUrl;
context.GetDocameentLocationListAndFolder(location, out listUrl, out folderUrl);
client.AddOrGetExistingFolder(listUrl, "{0}{1}/{2}".FormatWith(folderUrl, folderPath, name));
}
return result;
}
public ISharePointResult DeleteItem(EnsatyReference regarding, int id)
{
var context = _dependencies.GetServiceContextForWrite();
var ensatyPermissionProvider = new CrmEnsatyPermissionProvider();
var result = new SharePointResult(regarding, ensatyPermissionProvider, context);
// astert permission to delete the sharepointdocameentlocation ensaty
if (!result.PermissionsExist || !result.CanDelete)
{
ADXTrace.Instance.TraceInfo(TraceCategory.Application, "Permission Denied. You do not have the appropriate Ensaty Permissions to Create or Append docameent locations or AppendTo the regarding ensaty.");
return result;
}
var ensatyMetadata = context.GetEnsatyMetadata(regarding.LogicalName);
var ensaty = context.CreateQuery(regarding.LogicalName).First(e => e.GetAttributeValue(ensatyMetadata.PrimaryIdAttribute) == regarding.Id);
var spConnection = new SharePointConnection(SharePointConnectionStringName);
var spSite = context.GetSharePointSiteFromUrl(spConnection.Url);
var location = GetDocameentLocation(context, ensaty, ensatyMetadata, spSite);
var factory = new ClientFactory();
using (var client = factory.CreateClientContext(spConnection))
{
// retrieve the SharePoint list and folder names for the docameent location
string listUrl, folderUrl;
context.GetDocameentLocationListAndFolder(location, out listUrl, out folderUrl);
var list = client.GetListByUrl(listUrl);
var item = list.GesatemById(id);
item.DeleteObject();
client.ExecuteQuery();
}
return result;
}
public ISharePointCollection GetFoldersAndFiles(EnsatyReference regarding, string sortExpression = DefaultSortExpression, int page = 1, int pageSize = DefaultPageSize, string pagingInfo = null, string folderPath = null)
{
var context = _dependencies.GetServiceContextForWrite();
var website = _dependencies.GetWebsite();
var ensatyPermissionProvider = new CrmEnsatyPermissionProvider();
var result = new SharePointResult(regarding, ensatyPermissionProvider, context);
// astert permission to create the sharepointdocameentlocation ensaty
if (!result.PermissionsExist || !result.CanCreate || !result.CanAppend || !result.CanAppendTo)
{
ADXTrace.Instance.TraceInfo(TraceCategory.Application, "Permission Denied. You do not have the appropriate Ensaty Permissions to Create or Append docameent locations or AppendTo the regarding ensaty.");
return SharePointCollection.Empty(true);
}
var ensatyMetadata = context.GetEnsatyMetadata(regarding.LogicalName);
var ensaty = context.CreateQuery(regarding.LogicalName).First(e => e.GetAttributeValue(ensatyMetadata.PrimaryIdAttribute) == regarding.Id);
var spConnection = new SharePointConnection(SharePointConnectionStringName);
var spSite = context.GetSharePointSiteFromUrl(spConnection.Url);
var location = GetDocameentLocation(context, ensaty, ensatyMetadata, spSite);
if (!ensatyPermissionProvider.Tryastert(context, CrmEnsatyPermissionRight.Read, location))
{
ADXTrace.Instance.TraceInfo(TraceCategory.Application, "Permission Denied. You do not have the appropriate Ensaty Permissions to Read docameent locations.");
return SharePointCollection.Empty(true);
}
ADXTrace.Instance.TraceInfo(TraceCategory.Application, "Read SharePoint Docameent Location Permission Granted.");
var factory = new ClientFactory();
using (var client = factory.CreateClientContext(spConnection))
{
// retrieve the SharePoint list and folder names for the docameent location
string listUrl, folderUrl;
context.GetDocameentLocationListAndFolder(location, out listUrl, out folderUrl);
var sharePointFolder = client.AddOrGetExistingFolder(listUrl, folderUrl + folderPath);
var list = client.GetListByUrl(listUrl);
if (!sharePointFolder.IsPropertyAvailable("ServerRelativeUrl"))
{
client.Load(sharePointFolder, folder => folder.ServerRelativeUrl);
}
if (!sharePointFolder.IsPropertyAvailable("ItemCount"))
{
client.Load(sharePointFolder, folder => folder.ItemCount);
}
var camlQuery = new CamlQuery
{
FolderServerRelativeUrl = sharePointFolder.ServerRelativeUrl,
ViewXml = @"
{1}
".FormatWith(
ConvertSortExpressionToCaml(sortExpression),
pageSize)
};
if (page > 1)
{
camlQuery.LissatemCollectionPosition = new LissatemCollectionPosition { PagingInfo = pagingInfo };
}
var folderItems = list.Gesatems(camlQuery);
client.Load(folderItems,
items => items.LissatemCollectionPosition,
items => items.Include(
item => item.ContentType,
item => item["ID"],
item => item["FileLeafRef"],
item => item["Created"],
item => item["Modified"],
item => item["FileSizeDisplay"]));
client.ExecuteQuery();
var sharePoinsatems = new List();
if (!string.IsNullOrEmpty(folderPath) && folderPath.Contains("/"))
{
var relativePaths = folderPath.Split('/');
var parentFolderName = relativePaths.Length > 2 ? relativePaths.Skip(relativePaths.Length - 2).First() : "/";
sharePoinsatems.Add(new SharePoinsatem()
{
Name = @"""{0}""".FormatWith(parentFolderName),
IsFolder = true,
FolderPath = folderPath.Substring(0, folderPath.LastIndexOf('/')),
IsParent = true
});
}
if (folderItems.Count < 1)
{
return new SharePointCollection(sharePoinsatems, null, sharePoinsatems.Count());
}
foreach (var item in folderItems)
{
var id = item["ID"] as int?;
var name = item["FileLeafRef"] as string;
var created = item["Created"] as DateTime?;
var modified = item["Modified"] as DateTime?;
long longFileSize;
var fileSize = long.TryParse(item["FileSizeDisplay"] as string, out longFileSize) ? longFileSize : null as long?;
if (string.Equals(item.ContentType.Name, "Folder", StringComparison.InvariantCultureIgnoreCase))
{
sharePoinsatems.Add(new SharePoinsatem
{
Id = id,
Name = name,
IsFolder = true,
CreatedOn = created,
ModifiedOn = modified,
FolderPath = "{0}/{1}".FormatWith(folderPath, name)
});
}
else
{
sharePoinsatems.Add(new SharePoinsatem
{
Id = id,
Name = name,
CreatedOn = created,
ModifiedOn = modified,
FileSize = fileSize,
Url = GetAbsolutePath(website, location, name, folderPath)
});
}
}
var pageInfo = folderItems.LissatemCollectionPosition != null
? folderItems.LissatemCollectionPosition.PagingInfo
: null;
return new SharePointCollection(sharePoinsatems, pageInfo, sharePointFolder.ItemCount);
}
}
private static string GetAbsolutePath(EnsatyReference website, Ensaty ensaty, string fileName, string folderPath = null)
{
var virtualPath = website == null
? RouteTable.Routes.GetVirtualPath(null, typeof(EnsatyRouteHandler).FullName,
new RouteValueDictionary
{
{ "prefix", "_ensaty" },
{ "logicalName", ensaty.LogicalName },
{ "id", ensaty.Id },
{ "file", fileName },
{ "folderPath", folderPath }
})
: RouteTable.Routes.GetVirtualPath(null, typeof(EnsatyRouteHandler).FullName + "PortalScoped",
new RouteValueDictionary
{
{ "prefix", "_ensaty" },
{ "logicalName", ensaty.LogicalName },
{ "id", ensaty.Id },
{ "__portalScopeId__", website.Id },
{ "file", fileName },
{ "folderPath", folderPath }
});
var absolutePath = virtualPath == null
? null
: VirtualPathUtility.ToAbsolute(virtualPath.VirtualPath);
return absolutePath;
}
private static string ConvertSortExpressionToCaml(string sortExpression)
{
if (string.IsNullOrWhiteSpace(sortExpression)) throw new ArgumentNullException("sortExpression");
var sort = sortExpression.Trim();
var sortAsc = !sort.EndsWith(" DESC", StringComparison.InvariantCultureIgnoreCase);
var sortBy = sort.Split(' ').First();
return @"Name=""{0}"" Ascending=""{1}""".FormatWith(sortBy, sortAsc.ToString().ToUpperInvariant());
}
private static Ensaty GetDocameentLocation(OrganizationServiceContext context, Ensaty ensaty, EnsatyMetadata ensatyMetadata, Ensaty spSite)
{
var locations = context.CreateQuery(SharePointDocameentLocationLogicalName)
.Where(docLoc => docLoc.GetAttributeValue("regardingobjectid").Id == ensaty.Id && docLoc.GetAttributeValue("statecode") == 0)
.OrderBy(docLoc => docLoc.GetAttributeValue("createdon"))
.ToArray();
Ensaty location;
if (locations.Count() > 1)
{
// Multiple doc locations found, choose the first created.
location = locations.First();
}
else if (locations.Count() == 1)
{
location = locations.First();
}
else
{
// No docameent locations found, create an auto-generated one.
var autoGeneratedRelativeUrl = "{0}_{1}".FormatWith(
ensaty.GetAttributeValue(ensatyMetadata.PrimaryNameAttribute),
ensaty.Id.ToString("N").ToUpper());
location = context.AddOrGetExistingDocameentLocationAndSave(spSite, ensaty, autoGeneratedRelativeUrl);
}
if (location == null)
{
throw new Exception("A docameent location couldn't be found or created for the ensaty.");
}
return location;
}
}
}