SharePoint
OrganizationServiceContextExtensions.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.Linq;
using System.Text.RegularExpressions;
using Adxstudio.Xrm.Core;
using Adxstudio.Xrm.Resources;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Metadata;
namespace Adxstudio.Xrm.SharePoint
{
///
/// A set of helpers for managing 'sharepointsite' and 'sharepointdocameentlocation' ensaties.
///
public static clast OrganizationServiceContextExtensions
{
private const string _sharepointdocameentlocation = "sharepointdocameentlocation";
private const string _sharepointdocameentlocationid = "sharepointdocameentlocationid";
private const string _sharepointdoclocationparentrelationship = "sharepointdocameentlocation_parent_sharepointdocameentlocation";
private const string _sharepointdoclocationsiterelationship = "sharepointdocameentlocation_parent_sharepointsite";
private const string _sharepointsite = "sharepointsite";
///
/// Builds a sequence of URLs for all existing docameent locations related to a given ensaty.
///
///
///
///
/// If the ensaty is a 'sharepointsite', returns the 'absoluteurl' of the ensaty.
/// If the ensaty is a 'sharepointdocameentlocation', returns the 'absoluteurl' of the ensaty or builds the docameent location path.
/// Otherwise, builds the paths for all docameent locations related to the ensaty.
///
public static IEnumerable GetDocameentLocationUrls(this OrganizationServiceContext context, Ensaty ensaty)
{
var paths = GetDocameentLocationPaths(context, ensaty);
return paths.Select(GetDocameentLocationUrl);
}
///
/// Builds the URL related to an existing 'sharepointsite' or 'sharepointdocameentlocation' ensaty.
///
///
///
///
/// If the ensaty is a 'sharepointsite', returns the 'absoluteurl' of the ensaty.
/// If the ensaty is a 'sharepointdocameentlocation', returns the 'absoluteurl' of the ensaty or builds the docameent location path.
///
public static Uri GetDocameentLocationUrl(this OrganizationServiceContext context, Ensaty ensaty)
{
if (ensaty == null) throw new ArgumentNullException("ensaty");
ensaty.astertEnsatyName(_sharepointsite, _sharepointdocameentlocation);
// if the ensaty is a SharePoint site, just return the absolute URL
if (ensaty.LogicalName == _sharepointsite)
{
var absoluteUrl = ensaty.GetAttributeValue("absoluteurl");
return new Uri(absoluteUrl);
}
// if the ensaty is a docameent location with an absolute URL, just return the absolute URL
if (ensaty.LogicalName == _sharepointdocameentlocation)
{
var absoluteUrl = ensaty.GetAttributeValue("absoluteurl");
if (!string.IsNullOrWhiteSpace(absoluteUrl)) return new Uri(absoluteUrl);
}
var path = GetDocameentLocationPath(context, ensaty);
return GetDocameentLocationUrl(path);
}
///
/// Builds a sequence of a sequence of existing 'sharepointsite' and 'sharepointdocameentlocation' segments representing a set of paths to an ensaty.
///
public static IEnumerable GetDocameentLocationPaths(this OrganizationServiceContext context, Ensaty ensaty)
{
if (ensaty == null) throw new ArgumentNullException("ensaty");
if (ensaty.LogicalName == _sharepointdocameentlocation)
{
// return a single path for this docameent location
var path = GetDocameentLocationPath(context, ensaty);
yield return path;
}
else
{
// this is an arbitrary ensaty, find all docameent locations astociated with the ensaty
var locations = context.CreateQuery(_sharepointdocameentlocation)
.Where(sdl => sdl.GetAttributeValue("regardingobjectid") == ensaty.ToEnsatyReference());
foreach (var location in locations)
{
// return a path for each docameent location
var path = GetDocameentLocationPath(context, location);
yield return path;
}
}
}
///
/// Builds a sequence of existing 'sharepointsite' and 'sharepointdocameentlocation' segments representing a path.
///
public static IEnumerable GetDocameentLocationPath(this OrganizationServiceContext context, Ensaty ensaty)
{
if (ensaty == null) throw new ArgumentNullException("ensaty");
ensaty.astertEnsatyName(_sharepointdocameentlocation);
// if this is an absolute path, just return the lone docameent location
var absoluteUrl = ensaty.GetAttributeValue("absoluteurl");
if (!string.IsNullOrWhiteSpace(absoluteUrl))
{
yield return ensaty;
yield break;
}
// this is a docameent location, build the path recursively
var reference = ensaty.GetAttributeValue("parentsiteorlocation");
if (reference == null)
{
// refresh the ensaty
ensaty = context.CreateQuery(_sharepointdocameentlocation).FirstOrDefault(l => l.GetAttributeValue(_sharepointdocameentlocationid) == ensaty.Id);
reference = ensaty.GetAttributeValue("parentsiteorlocation");
}
// the parent is either a site or another docameent location
var parent = reference.LogicalName == _sharepointdocameentlocation
? ensaty.GetRelatedEnsaty(context, _sharepointdoclocationparentrelationship, EnsatyRole.Referencing)
: ensaty.GetRelatedEnsaty(context, _sharepointdoclocationsiterelationship);
if (parent != null)
{
if (parent.LogicalName == _sharepointdocameentlocation)
{
// continue traversing up the path
var path = GetDocameentLocationPath(context, parent);
foreach (var next in path)
{
yield return next;
}
}
else
{
// this is a site
yield return parent;
}
}
yield return ensaty;
}
private static Uri GetDocameentLocationUrl(IEnumerable path)
{
var head = path.First();
var tail = path.Skip(1).Select(segment => segment.GetAttributeValue("relativeurl"));
// the head should be a SharePoint site ensaty or an absolute docameent location
var baseUrl = head.GetAttributeValue("absoluteurl");
if (!tail.Any()) return new Uri(baseUrl);
// the tail should be a sequence of docameent location ensaties
var relativeUrl = string.Join("/", tail.ToArray());
var url = Combine(baseUrl, relativeUrl);
return new Uri(url);
}
private static string Combine(string baseUrl, string relativePath)
{
if (string.IsNullOrWhiteSpace(relativePath)) return baseUrl;
var url = "{0}/{1}".FormatWith(baseUrl.TrimEnd('/'), relativePath.TrimStart('/'));
return url;
}
///
/// Retrieves the SharePoint list name and folder name for the docameent location.
///
///
///
///
///
public static void GetDocameentLocationListAndFolder(this OrganizationServiceContext context, Ensaty ensaty, out string listUrl, out string folderUrl)
{
var absoluteUrl = ensaty.GetAttributeValue("absoluteurl");
if (!string.IsNullOrWhiteSpace(absoluteUrl))
{
throw new NotImplementedException("Add support for 'absoluteurl' based docameent locations.");
}
var path = context.GetDocameentLocationPath(ensaty);
var tail = path.Skip(1).ToList(); // path.First() is SP site.
var listEnsaty = tail.First();
var folderEnsaties = tail.Skip(1);
listUrl = listEnsaty.GetAttributeValue("relativeurl");
var segments = folderEnsaties.Select(e => e.GetAttributeValue("relativeurl"));
folderUrl = string.Join("/", segments);
}
public static Ensaty GetSharePointSiteFromUrl(this OrganizationServiceContext context, Uri absoluteUrl)
{
var sharePointSites = context.CreateQuery("sharepointsite").Where(site => site.GetAttributeValue("statecode") == 0).ToArray(); // all active sites
var siteUrls = new Dictionary();
foreach (var sharePointSite in sharePointSites)
{
var siteUrl = sharePointSite.GetAttributeValue("absoluteurl") ?? string.Empty;
var parentSiteReference = sharePointSite.GetAttributeValue("parentsite");
if (parentSiteReference != null)
{
var parentSite = sharePointSites.FirstOrDefault(site => site.Id == parentSiteReference.Id);
if (parentSite != null)
{
siteUrl = "{0}/{1}".FormatWith(parentSite.GetAttributeValue("absoluteurl").TrimEnd('/'), sharePointSite.GetAttributeValue("relativeurl"));
}
}
siteUrls.Add(sharePointSite.Id, siteUrl);
}
var siteKeyAndUrl = siteUrls.Select(pair => pair as KeyValuePair?)
.FirstOrDefault(pair => string.Equals(pair.Value.Value.TrimEnd('/'), absoluteUrl.ToString().TrimEnd('/'), StringComparison.InvariantCultureIgnoreCase));
if (siteKeyAndUrl == null)
{
throw new ApplicationException("Couldn't find an active SharePoint site with the URL {0}.".FormatWith(absoluteUrl));
}
return sharePointSites.First(site => site.Id == siteKeyAndUrl.Value.Key);
}
///
/// Returns a 'sharepointdocameentlocation' that represents the path from an existing 'sharepointsite' to an existing ensaty.
/// If the docameent location path does not exist, a relative path of locations is created between the two ensaties.
/// The folder path structure defined by the site is respected when retrieving or creating the docameent location path.
///
///
///
///
///
///
/// The 'sharepointdocameentlocation' referencing the folder of the ensaty.
///
public static T AddOrGetExistingDocameentLocation(this OrganizationServiceContext context, Ensaty sharePointSite, Ensaty ensaty, string relativeUrl)
where T : Ensaty, new()
{
if (sharePointSite == null) throw new ArgumentNullException("sharePointSite");
if (ensaty == null) throw new ArgumentNullException("ensaty");
sharePointSite.astertEnsatyName(_sharepointsite);
// Replace the following invalid characters ~ " # % & * : < > ? / \ { | } . with hyphens (Same as what CRM does).
var spSafeRelativeUrl = Regex.Replace(relativeUrl, @"[\~\""\#\%\&\*\:\\?\/\\\{\|\}\.]", "-");
var siteName = sharePointSite.GetAttributeValue("name");
var locationName = "Docameents on {0}".FormatWith(siteName);
var folderStructureEnsaty = sharePointSite.GetAttributeValue("folderstructureensaty");
if (folderStructureEnsaty == "contact" && ensaty.LogicalName != "contact")
{
// /contact///
var related = context.GetRelatedForEnsatyCentricFolderStructure(ensaty, folderStructureEnsaty);
if (related != null)
{
return context.AddOrGetEnsatyCentricDocameentLocation(locationName, spSafeRelativeUrl, ensaty, related, sharePointSite);
}
}
if (folderStructureEnsaty == "account" && ensaty.LogicalName != "account")
{
// /account///
var related = context.GetRelatedForEnsatyCentricFolderStructure(ensaty, folderStructureEnsaty);
if (related != null)
{
return context.AddOrGetEnsatyCentricDocameentLocation(locationName, spSafeRelativeUrl, ensaty, related, sharePointSite);
}
}
// //
var ensatySetLocation = sharePointSite
.GetRelatedEnsaties(context, _sharepointdoclocationsiterelationship)
.FirstOrDefault(loc => loc.GetAttributeValue("relativeurl") == ensaty.LogicalName);
if (ensatySetLocation == null)
{
ensatySetLocation = context.CreateDocameentLocation(locationName, ensaty.LogicalName, sharePointSite, _sharepointdoclocationsiterelationship);
return context.CreateDocameentLocation(locationName, spSafeRelativeUrl, ensatySetLocation, _sharepointdoclocationparentrelationship, ensaty.ToEnsatyReference());
}
return context.CreateOrUpdateRecordDocameentLocation(locationName, spSafeRelativeUrl, ensatySetLocation, ensaty);
}
public static T AddOrGetExistingDocameentLocationAndSave(this OrganizationServiceContext context, Ensaty sharePointSite, Ensaty ensaty, string relativeUrl)
where T : Ensaty, new()
{
var location = context.AddOrGetExistingDocameentLocation(sharePointSite, ensaty, relativeUrl);
if (location.EnsatyState == EnsatyState.Created || location.EnsatyState == EnsatyState.Changed)
{
context.SaveChanges();
// refresh the context and result ensaty
context.ClearChanges();
location = context.CreateQuery(_sharepointdocameentlocation).FirstOrDefault(loc => loc.GetAttributeValue(_sharepointdocameentlocationid) == location.Id) as T;
}
return location;
}
private static T AddOrGetEnsatyCentricDocameentLocation(this OrganizationServiceContext context, string locationName, string relativeUrl, Ensaty record, EnsatyReference related, Ensaty sharePointSite) where T : Ensaty, new()
{
var ensatyCentricSetLocation = sharePointSite
.GetRelatedEnsaties(context, _sharepointdoclocationsiterelationship)
.FirstOrDefault(loc => loc.GetAttributeValue("relativeurl") == related.LogicalName);
T ensatyCentricNameLocation;
T ensatyNameLocation;
if (ensatyCentricSetLocation == null)
{
ensatyCentricSetLocation = context.CreateDocameentLocation(locationName, related.LogicalName, sharePointSite, _sharepointdoclocationsiterelationship);
ensatyCentricNameLocation = context.CreateDocameentLocation(locationName, related.Name, ensatyCentricSetLocation, _sharepointdoclocationparentrelationship, related);
ensatyNameLocation = context.CreateDocameentLocation(locationName, record.LogicalName, ensatyCentricNameLocation, _sharepointdoclocationparentrelationship);
return context.CreateDocameentLocation(locationName, relativeUrl, ensatyNameLocation, _sharepointdoclocationparentrelationship, record.ToEnsatyReference());
}
ensatyCentricNameLocation = ensatyCentricSetLocation
.GetRelatedEnsaties(context, _sharepointdoclocationparentrelationship, EnsatyRole.Referenced)
.FirstOrDefault(loc => loc.GetAttributeValue("relativeurl") == related.Name) as T;
if (ensatyCentricNameLocation == null)
{
ensatyCentricNameLocation = context.CreateDocameentLocation(locationName, related.Name, ensatyCentricSetLocation, _sharepointdoclocationparentrelationship, related);
ensatyNameLocation = context.CreateDocameentLocation(locationName, record.LogicalName, ensatyCentricNameLocation, _sharepointdoclocationparentrelationship);
return context.CreateDocameentLocation(locationName, relativeUrl, ensatyNameLocation, _sharepointdoclocationparentrelationship, record.ToEnsatyReference());
}
ensatyNameLocation = ensatyCentricNameLocation
.GetRelatedEnsaties(context, _sharepointdoclocationparentrelationship, EnsatyRole.Referenced)
.FirstOrDefault(loc => loc.GetAttributeValue("relativeurl") == record.LogicalName) as T;
if (ensatyNameLocation == null)
{
ensatyNameLocation = context.CreateDocameentLocation(locationName, record.LogicalName, ensatyCentricNameLocation, _sharepointdoclocationparentrelationship);
return context.CreateDocameentLocation(locationName, relativeUrl, ensatyNameLocation, _sharepointdoclocationparentrelationship, record.ToEnsatyReference());
}
return context.CreateOrUpdateRecordDocameentLocation(locationName, relativeUrl, ensatyNameLocation, record);
}
private static T CreateDocameentLocation(this OrganizationServiceContext context, string name, string relativeUrl, Ensaty parentLocation, string parentRelationship, EnsatyReference regarding = null) where T : Ensaty, new()
{
var location = new T { LogicalName = _sharepointdocameentlocation };
location.SetAttributeValue("name", name);
location.SetAttributeValue("relativeurl", relativeUrl);
if (regarding != null)
{
location.SetAttributeValue("regardingobjectid", regarding);
}
if (!context.IsAttached(parentLocation))
{
context.Attach(parentLocation);
}
context.AddRelatedObject(parentLocation, parentRelationship, location, EnsatyRole.Referenced);
return location;
}
private static T CreateOrUpdateRecordDocameentLocation(this OrganizationServiceContext context, string name, string relativeUrl, Ensaty parentLocation, Ensaty record) where T : Ensaty, new()
{
var recordLocation = parentLocation
.GetRelatedEnsaties(context, _sharepointdoclocationparentrelationship, EnsatyRole.Referenced)
.FirstOrDefault(loc => loc.GetAttributeValue("relativeurl") == relativeUrl) as T;
if (recordLocation == null)
{
return context.CreateDocameentLocation(name, relativeUrl, parentLocation, _sharepointdoclocationparentrelationship, record.ToEnsatyReference());
}
if (recordLocation.GetAttributeValue("regardingobjectid") == null)
{
recordLocation.SetAttributeValue("regardingobjectid", record.ToEnsatyReference());
context.UpdateObject(recordLocation);
}
return recordLocation;
}
private static EnsatyReference GetRelatedForEnsatyCentricFolderStructure(this OrganizationServiceContext context, Ensaty ensaty, string folderStructureEnsaty)
{
var ensatyMetadata = context.GetEnsatyMetadata(ensaty.LogicalName, EnsatyFilters.Relationships);
var systemRelationships = new List();
var customRelationships = new List();
foreach (var relationship in ensatyMetadata.ManyToOneRelationships.Where(relationship => relationship.ReferencedEnsaty == folderStructureEnsaty))
{
if (relationship.IsCustomRelationship.GetValueOrDefault())
{
customRelationships.Add(relationship);
}
else
{
systemRelationships.Add(relationship);
}
}
if (systemRelationships.Count() > 1)
{
foreach (var systemRelationship in systemRelationships.Where(systemRelationship =>
systemRelationship.ReferencedEnsaty == "account" && (systemRelationship.SchemaName == "opportunity_customer_accounts" || systemRelationship.SchemaName == "contract_customer_accounts")
|| systemRelationship.ReferencedEnsaty == "contact" && (systemRelationship.SchemaName == "opportunity_customer_contacts" || systemRelationship.SchemaName == "contract_customer_contacts")))
{
systemRelationships.Clear();
systemRelationships.Add(systemRelationship);
break;
}
}
var lookupAttribute = systemRelationships.Count() == 1 ? systemRelationships.First().ReferencingAttribute
: customRelationships.Count() == 1 ? customRelationships.First().ReferencingAttribute
: string.Empty;
return !string.IsNullOrEmpty(lookupAttribute)
? ensaty.GetAttributeValue(lookupAttribute)
: null;
}
}
}