Notes
AnnotationDataAdapter.cs
/*
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License. See License.txt in the project root for license information.
*/
namespace Adxstudio.Xrm.Notes
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.IO;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Portal.Configuration;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Xrm.Sdk.Query;
using Newtonsoft.Json;
using Filter = Adxstudio.Xrm.Services.Query.Filter;
using Adxstudio.Xrm.Cms;
using Adxstudio.Xrm.Cms.Replication;
using Adxstudio.Xrm.Metadata;
using Adxstudio.Xrm.Security;
using Adxstudio.Xrm.Services.Query;
using Adxstudio.Xrm.Text;
using Adxstudio.Xrm.Web.Handlers;
using Adxstudio.Xrm.ContentAccess;
using Adxstudio.Xrm.Core.Flighting;
using Adxstudio.Xrm.Services;
public clast AnnotationDataAdapter : IAnnotationDataAdapter
{
public const string StorageContainerSetting = "FileStorage/CloudStorageContainerName";
public const string StorageAccountSetting = "FileStorage/CloudStorageAccount";
private const int DefaultPageSize = 10;
private const int DefaultMaxPageSize = 50;
private readonly string _containerName;
private readonly IDataAdapterDependencies _dependencies;
private static readonly string[] _allowDisplayInlineContentTypes = {
"image/gif", //.gif
"image/jpeg", //.jpeg, .jpg
"image/png", //.png
"image/tiff", //.tiff ???
"image/bmp", //.bmp
"image/x-icon" //.ico
};
public AnnotationDataAdapter(IDataAdapterDependencies dependencies)
{
_dependencies = dependencies;
_containerName = GetStorageContainerName(dependencies.GetServiceContext());
}
public static CloudStorageAccount GetStorageAccount(OrganizationServiceContext context)
{
var cloudStorageDetails = context.GetSettingValueByName(StorageAccountSetting);
CloudStorageAccount storageAccount;
CloudStorageAccount.TryParse(cloudStorageDetails, out storageAccount);
return storageAccount;
}
public static string GetStorageContainerName(OrganizationServiceContext context)
{
var containerName = context.GetSettingValueByName(StorageContainerSetting);
return (string.IsNullOrEmpty(containerName)
? ((WhoAmIResponse)context.Execute(new WhoAmIRequest())).OrganizationId.ToString("N")
: containerName).ToLowerInvariant();
}
public IAnnotation GetAnnotation(Guid id)
{
var context = _dependencies.GetServiceContext();
var fetch = new Fetch();
var fetchEnsaty = new FetchEnsaty("annotation")
{
Attributes = new List
{
new FetchAttribute("annotationid"),
new FetchAttribute("notetext"),
new FetchAttribute("isdocameent"),
new FetchAttribute("subject"),
new FetchAttribute("createdon"),
new FetchAttribute("createdby"),
new FetchAttribute("modifiedon"),
new FetchAttribute("filename"),
new FetchAttribute("filesize"),
new FetchAttribute("mimetype"),
new FetchAttribute("objectid"),
new FetchAttribute("objecttypecode")
},
Orders = new List { new Order("createdon") },
Filters = new List
{
new Filter
{
Type = LogicalOperator.And,
Conditions = new List
{
new Condition("annotationid", ConditionOperator.Equal, id)
}
}
}
};
fetch.Ensaty = fetchEnsaty;
var response = (RetrieveMultipleResponse)context.Execute(fetch.ToRetrieveMultipleRequest());
var note = response.EnsatyCollection.Ensaties.FirstOrDefault();
if (note == null) return null;
if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
{
PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Note, HttpContext.Current, "read_annotation", 1, note.ToEnsatyReference(), "read");
}
return GetAnnotation(note);
}
public IAnnotation GetAnnotation(Ensaty ensaty)
{
return new Annotation(ensaty, ensaty.GetAttributeValue("objectid"),
() => GetAnnotationFile(ensaty, ensaty.GetAttributeValue("annotationid")));
}
public void Download(HttpContextBase context, Ensaty ensaty, Ensaty webfile = null)
{
var note = GetAnnotation(ensaty);
var storageAccount = GetStorageAccount(_dependencies.GetServiceContext());
if (storageAccount != null && note.FileAttachment is AzureAnnotationFile)
{
DownloadFromAzure(context, note);
}
else
{
DownloadFromCRM(context, note, webfile);
}
}
public ActionResult DownloadAction(HttpResponseBase response, Ensaty ensaty)
{
var note = GetAnnotation(ensaty);
var storageAccount = GetStorageAccount(_dependencies.GetServiceContext());
if (storageAccount != null && note.FileAttachment is AzureAnnotationFile)
{
return DownloadFromAzureAction(note);
}
return DownloadFromCRMAction(response, note);
}
public IAnnotationCollection GetAnnotations(EnsatyReference regarding, List orders = null, int page = 1,
int pageSize = DefaultPageSize, AnnotationPrivacy privacy = AnnotationPrivacy.Private | AnnotationPrivacy.Web,
EnsatyMetadata ensatyMetadata = null, bool respectPermissions = true)
{
if (pageSize < 0)
{
pageSize = DefaultPageSize;
}
if (pageSize > DefaultMaxPageSize)
{
ADXTrace.Instance.TraceInfo(TraceCategory.Application, string.Format("pageSize={0} is greater than the allowed maximum page size of {1}. Page size has been constrained to {1}.", pageSize, DefaultMaxPageSize));
pageSize = DefaultMaxPageSize;
}
var fetch = BuildAnnotationsQuery(regarding, orders, privacy, ensatyMetadata);
AddPaginationToFetch(fetch, fetch.PagingCookie, page, pageSize, true);
if (respectPermissions) AddPermissionFilterToFetch(fetch, _dependencies.GetServiceContext(), CrmEnsatyPermissionRight.Read, regarding);
var notes = FetchAnnotations(fetch, regarding);
return notes;
}
public IAnnotationCollection GetDocameents(EnsatyReference regarding, bool respectPermissions = true, string webPrefix = null)
{
var fetch = BuildAnnotationsQuery(regarding, privacy: AnnotationPrivacy.Any, webPrefix: webPrefix);
fetch.Ensaty.Filters.First().Conditions.Add(new Condition("isdocameent", ConditionOperator.Equal, true));
if (respectPermissions) AddPermissionFilterToFetch(fetch, _dependencies.GetServiceContext(), CrmEnsatyPermissionRight.Read, regarding);
var notes = FetchAnnotations(fetch, regarding);
if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
{
PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Note, HttpContext.Current, "GetDocameents", "Exposing annotations", notes.Count(), "annotation", "read");
}
return notes;
}
public IAnnotationResult CreateAnnotation(IAnnotation note, IAnnotationSettings settings = null)
{
var serviceContext = _dependencies.GetServiceContext();
var serviceContextForWrite = _dependencies.GetServiceContextForWrite();
if (settings == null)
{
settings = new AnnotationSettings(serviceContext);
}
var storageAccount = GetStorageAccount(serviceContext);
if (settings.StorageLocation == StorageLocation.AzureBlobStorage && storageAccount == null)
{
settings.StorageLocation = StorageLocation.CrmDocameent;
}
AnnotationCreateResult result = null;
if (settings.RespectPermissions)
{
var ensatyPermissionProvider = new CrmEnsatyPermissionProvider();
result = new AnnotationCreateResult(ensatyPermissionProvider, serviceContext, note.Regarding);
}
// ReSharper disable once PossibleNullReferenceException
if (!settings.RespectPermissions ||
(result.PermissionsExist && result.PermissionGranted))
{
var ensaty = new Ensaty("annotation");
if (note.Owner != null)
{
ensaty.SetAttributeValue("ownerid", note.Owner);
}
ensaty.SetAttributeValue("subject", note.Subject);
ensaty.SetAttributeValue("notetext", note.NoteText);
ensaty.SetAttributeValue("objectid", note.Regarding);
ensaty.SetAttributeValue("objecttypecode", note.Regarding.LogicalName);
if (note.FileAttachment != null)
{
var acceptMimeTypes = AnnotationDataAdapter.GetAcceptRegex(settings.AcceptMimeTypes);
var acceptExtensionTypes = AnnotationDataAdapter.GetAcceptRegex(settings.AcceptExtensionTypes);
if (!(acceptExtensionTypes.IsMatch(Path.GetExtension(note.FileAttachment.FileName).ToLower()) ||
acceptMimeTypes.IsMatch(note.FileAttachment.MimeType)))
{
throw new AnnotationException(settings.RestrictMimeTypesErrorMessage);
}
if (settings.MaxFileSize.HasValue && note.FileAttachment.FileSize > settings.MaxFileSize)
{
throw new AnnotationException(settings.MaxFileSizeErrorMessage);
}
note.FileAttachment.Annotation = ensaty;
switch (settings.StorageLocation)
{
case StorageLocation.CrmDocameent:
var crmFile = note.FileAttachment as CrmAnnotationFile;
if (crmFile == null)
{
break;
}
if (!string.IsNullOrEmpty(settings.RestrictedFileExtensions))
{
var blocked = new Regex(@"\.({0})$".FormatWith(settings.RestrictedFileExtensions.Replace(";", "|")));
if (blocked.IsMatch(crmFile.FileName))
{
throw new AnnotationException(settings.RestrictedFileExtensionsErrorMessage);
}
}
ensaty.SetAttributeValue("filename", crmFile.FileName);
ensaty.SetAttributeValue("mimetype", crmFile.MimeType);
ensaty.SetAttributeValue("docameentbody", Convert.ToBase64String(crmFile.Docameent));
break;
case StorageLocation.AzureBlobStorage:
ensaty.SetAttributeValue("filename", note.FileAttachment.FileName + ".azure.txt");
ensaty.SetAttributeValue("mimetype", "text/plain");
var fileMetadata = new
{
Name = note.FileAttachment.FileName,
Type = note.FileAttachment.MimeType,
Size = (ulong)note.FileAttachment.FileSize,
Url = string.Empty
};
ensaty.SetAttributeValue("docameentbody",
Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(fileMetadata, Formatting.Indented))));
break;
}
}
// Create annotaion but skip cache invalidation.
var id = (serviceContext as IOrganizationService).ExecuteCreate(ensaty, RequestFlag.ByPastCacheInvalidation);
if (result != null) result.Annotation = note;
note.AnnotationId = ensaty.Id = id;
note.Ensaty = ensaty;
if (note.FileAttachment is AzureAnnotationFile && settings.StorageLocation == StorageLocation.AzureBlobStorage)
{
var container = GetBlobContainer(storageAccount, _containerName);
var azureFile = (AzureAnnotationFile)note.FileAttachment;
azureFile.BlockBlob = UploadBlob(azureFile, container, note.AnnotationId);
var fileMetadata = new
{
Name = azureFile.FileName,
Type = azureFile.MimeType,
Size = (ulong)azureFile.FileSize,
Url = azureFile.BlockBlob.Uri.AbsoluteUri
};
ensaty.SetAttributeValue("docameentbody",
Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(fileMetadata, Formatting.Indented))));
serviceContextForWrite.UpdateObject(ensaty);
serviceContextForWrite.SaveChanges();
// NB: This is basically a hack to support replication. Keys are gathered up and stored during replication, and the
// actual blob replication is handled here.
var key = note.AnnotationId.ToString("N");
if (HttpContext.Current.Application.AllKeys.Contains(NoteReplication.BlobReplicationKey))
{
var replication =
HttpContext.Current.Application[NoteReplication.BlobReplicationKey] as Dictionary;
if (replication != null && replication.ContainsKey(key))
{
CopyBlob(note, replication[key]);
replication.Remove(key);
}
}
}
}
if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
{
PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Note, HttpContext.Current, "create_note", 1, note.Ensaty.ToEnsatyReference(), "create");
}
return result;
}
public IAnnotationResult CreateAnnotation(EnsatyReference regarding, string subject, string noteText)
{
IAnnotation annotation = new Annotation
{
Subject = subject,
NoteText = noteText,
Regarding = regarding
};
return CreateAnnotation(annotation);
}
public IAnnotationResult CreateAnnotation(EnsatyReference regarding, string subject, string noteText,
HttpPostedFileBase file)
{
IAnnotation annotation = new Annotation
{
Subject = subject,
NoteText = noteText,
Regarding = regarding,
FileAttachment = new CrmAnnotationFile(file)
};
return CreateAnnotation(annotation);
}
public IAnnotationResult CreateAnnotation(EnsatyReference regarding, string subject, string noteText, string fileName,
string contentType, byte[] content)
{
IAnnotation annotation = new Annotation
{
Subject = subject,
NoteText = noteText,
Regarding = regarding,
FileAttachment = new CrmAnnotationFile(fileName, contentType, content)
};
return CreateAnnotation(annotation);
}
public IAnnotationResult UpdateAnnotation(IAnnotation note, IAnnotationSettings settings = null)
{
var serviceContext = _dependencies.GetServiceContext();
var serviceContextForWrite = _dependencies.GetServiceContextForWrite();
if (settings == null)
{
settings = new AnnotationSettings(serviceContext);
}
var storageAccount = GetStorageAccount(serviceContext);
if (settings.StorageLocation == StorageLocation.AzureBlobStorage && storageAccount == null)
{
settings.StorageLocation = StorageLocation.CrmDocameent;
}
AnnotationUpdateResult result = null;
if (settings.RespectPermissions)
{
var ensatyPermissionProvider = new CrmEnsatyPermissionProvider();
result = new AnnotationUpdateResult(note, ensatyPermissionProvider, serviceContext);
}
var isPostedByCurrentUser = false;
var noteContact = AnnotationHelper.GetNoteContact(note.Ensaty.GetAttributeValue("subject"));
var currentUser = _dependencies.GetPortalUser();
if (noteContact != null && currentUser != null && currentUser.LogicalName == "contact" &&
currentUser.Id == noteContact.Id)
{
isPostedByCurrentUser = true;
}
// ReSharper disable once PossibleNullReferenceException
if (!settings.RespectPermissions || (result.PermissionsExist && result.PermissionGranted && isPostedByCurrentUser))
{
var ensaty = new Ensaty("annotation")
{
Id = note.AnnotationId
};
ensaty.SetAttributeValue("notetext", note.NoteText);
ensaty.SetAttributeValue("subject", note.Subject);
ensaty.SetAttributeValue("isdocameent", note.FileAttachment != null);
if (note.FileAttachment != null)
{
var accept = GetAcceptRegex(settings.AcceptMimeTypes);
if (!accept.IsMatch(note.FileAttachment.MimeType))
{
throw new AnnotationException(settings.RestrictMimeTypesErrorMessage);
}
if (settings.MaxFileSize.HasValue && note.FileAttachment.FileSize > settings.MaxFileSize)
{
throw new AnnotationException(settings.MaxFileSizeErrorMessage);
}
note.FileAttachment.Annotation = ensaty;
switch (settings.StorageLocation)
{
case StorageLocation.CrmDocameent:
var crmFile = note.FileAttachment as CrmAnnotationFile;
if (crmFile == null || crmFile.Docameent == null || crmFile.Docameent.Length == 0)
{
break;
}
if (!string.IsNullOrEmpty(settings.RestrictedFileExtensions))
{
var blocked = new Regex(@"\.({0})$".FormatWith(settings.RestrictedFileExtensions.Replace(";", "|")));
if (blocked.IsMatch(crmFile.FileName))
{
throw new AnnotationException(settings.RestrictedFileExtensionsErrorMessage);
}
}
ensaty.SetAttributeValue("filename", crmFile.FileName);
ensaty.SetAttributeValue("mimetype", crmFile.MimeType);
ensaty.SetAttributeValue("docameentbody", Convert.ToBase64String(crmFile.Docameent));
break;
case StorageLocation.AzureBlobStorage:
ensaty.SetAttributeValue("filename", note.FileAttachment.FileName + ".azure.txt");
ensaty.SetAttributeValue("mimetype", "text/plain");
var fileMetadata = new
{
Name = note.FileAttachment.FileName,
Type = note.FileAttachment.MimeType,
Size = (ulong)note.FileAttachment.FileSize,
Url = string.Empty
};
ensaty.SetAttributeValue("docameentbody",
Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(fileMetadata, Formatting.Indented))));
break;
}
}
serviceContextForWrite.Attach(ensaty);
serviceContextForWrite.UpdateObject(ensaty);
serviceContextForWrite.SaveChanges();
if (note.FileAttachment is AzureAnnotationFile && settings.StorageLocation == StorageLocation.AzureBlobStorage)
{
var azureFile = note.FileAttachment as AzureAnnotationFile;
if (azureFile.GetFileStream() != null)
{
var container = GetBlobContainer(storageAccount, _containerName);
var oldName = note.Ensaty.GetAttributeValue("filename");
var oldBlob = container.GetBlockBlobReference("{0:N}/{1}".FormatWith(ensaty.Id.ToString(), oldName));
oldBlob.DeleteIfExists();
azureFile.BlockBlob = UploadBlob(azureFile, container, note.AnnotationId);
var fileMetadata = new
{
Name = azureFile.FileName,
Type = azureFile.MimeType,
Size = (ulong)azureFile.FileSize,
Url = azureFile.BlockBlob.Uri.AbsoluteUri
};
ensaty.SetAttributeValue("docameentbody",
Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(fileMetadata, Formatting.Indented))));
serviceContextForWrite.UpdateObject(ensaty);
serviceContextForWrite.SaveChanges();
}
}
}
if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
{
PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Note, HttpContext.Current, "edit_note", 1, new EnsatyReference("annotation", note.AnnotationId), "edit");
}
return result;
}
public IAnnotationResult DeleteAnnotation(IAnnotation note, IAnnotationSettings settings = null)
{
var serviceContext = _dependencies.GetServiceContext();
var serviceContextForWrite = _dependencies.GetServiceContextForWrite();
if (settings == null)
{
settings = new AnnotationSettings(serviceContext);
}
AnnotationDeleteResult result = null;
if (settings.RespectPermissions)
{
var ensatyPermissionProvider = new CrmEnsatyPermissionProvider();
result = new AnnotationDeleteResult(note, ensatyPermissionProvider, serviceContext);
}
var isPostedByCurrentUser = false;
var noteContact = AnnotationHelper.GetNoteContact(note.Subject);
var currentUser = _dependencies.GetPortalUser();
if (noteContact != null && currentUser != null && currentUser.LogicalName == "contact" &&
currentUser.Id == noteContact.Id)
{
isPostedByCurrentUser = true;
}
// ReSharper disable once PossibleNullReferenceException
if (!settings.RespectPermissions || (result.PermissionGranted && isPostedByCurrentUser))
{
var ensatyToDelete = serviceContextForWrite.RetrieveSingle(
"annotation",
"annotationid",
note.AnnotationId,
FetchAttribute.All);
serviceContextForWrite.DeleteObject(ensatyToDelete);
serviceContextForWrite.SaveChanges();
var storageAccount = GetStorageAccount(serviceContext);
if (storageAccount != null && note.FileAttachment is AzureAnnotationFile)
{
var azureFile = note.FileAttachment as AzureAnnotationFile;
azureFile.BlockBlob.DeleteIfExists();
}
}
if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
{
PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Note, HttpContext.Current, "delete_note", 1, new EnsatyReference("annotation", note.AnnotationId), "delete");
}
return result;
}
private IAnnotationCollection FetchAnnotations(Fetch fetch, EnsatyReference regarding, bool permissionDenied = false)
{
if (fetch == null || permissionDenied)
{
return AnnotationCollection.Empty(permissionDenied);
}
var serviceContext = _dependencies.GetServiceContext();
var response = (RetrieveMultipleResponse)serviceContext.Execute(fetch.ToRetrieveMultipleRequest());
if (!string.IsNullOrEmpty(response.EnsatyCollection.PagingCookie))
{
fetch.PagingCookie = response.EnsatyCollection.PagingCookie;
}
IEnumerable ensaties = response.EnsatyCollection.Ensaties;
var notes = ensaties.Select(e => new Annotation(e, regarding, () =>
GetAnnotationFile(e, e.GetAttributeValue("annotationid"))));
return new AnnotationCollection(notes, response.EnsatyCollection.TotalRecordCount);
}
private IAnnotationFile GetAnnotationFile(Ensaty note, Guid id)
{
var isDocameent = note.GetAttributeValue("isdocameent");
if (!isDocameent) return null;
var fileName = note.GetAttributeValue("filename");
var storageAccount = GetStorageAccount(_dependencies.GetServiceContext());
var regex = new Regex(@"\.azure\.txt$");
var azure = regex.IsMatch(fileName);
var file = azure ? new AzureAnnotationFile() as IAnnotationFile : new CrmAnnotationFile();
file.SetAnnotation(() => GetAnnotationWithDocameent(id));
if (azure)
{
var blobFileName = regex.Replace(fileName, string.Empty);
var blobFile = file as AzureAnnotationFile;
if (storageAccount != null)
{
blobFile.BlockBlob = GetBlockBlob(storageAccount, id, blobFileName);
if (blobFile.BlockBlob.Exists())
{
blobFile.FileName = blobFileName;
blobFile.FileSize = new FileSize(blobFile.BlockBlob == null ? 0 : Convert.ToUInt64(blobFile.BlockBlob.Properties.Length));
blobFile.MimeType = blobFile.BlockBlob.Properties.ContentType;
}
}
}
else
{
var crmFile = file as CrmAnnotationFile;
crmFile.FileName = fileName;
var size = note.GetAttributeValue("filesize");
crmFile.FileSize = new FileSize(size > 0 ? Convert.ToUInt64(size) : 0);
crmFile.MimeType = note.GetAttributeValue("mimetype");
crmFile.SetDocameent(() => GetFileDocameent(file));
}
return file;
}
private CloudBlockBlob GetBlockBlob(CloudStorageAccount storageAccount, Guid id, string fileName)
{
if (storageAccount != null)
{
var container = GetBlobContainer(storageAccount, _containerName);
var blockBlob = container.GetBlockBlobReference("{0:N}/{1}".FormatWith(id, fileName));
if (blockBlob.Exists())
{
blockBlob.FetchAttributes();
}
return blockBlob;
}
return null;
}
private Ensaty GetAnnotationWithDocameent(Guid id)
{
var fetch = new Fetch
{
Ensaty =
new FetchEnsaty("annotation")
{
Filters = new[] { new Filter { Conditions = new[] { new Condition("annotationid", ConditionOperator.Equal, id) } } }
}
};
return _dependencies.GetServiceContext().RetrieveSingle(fetch, enforceFirst: true);
}
private static byte[] GetFileDocameent(IAnnotationFile file)
{
var body = file.Annotation.GetAttributeValue("docameentbody");
return string.IsNullOrWhiteSpace(body) ? new byte[] { } : Convert.FromBase64String(body);
}
public static CloudBlobContainer GetBlobContainer(CloudStorageAccount account, string containerName)
{
var blobClient = account.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(containerName);
container.CreateIfNotExists();
return container;
}
private Fetch BuildAnnotationsQuery(EnsatyReference regarding, List orders = null,
AnnotationPrivacy privacy = AnnotationPrivacy.Private | AnnotationPrivacy.Web, EnsatyMetadata ensatyMetadata = null, string webPrefix = null)
{
if (ensatyMetadata == null)
{
var serviceContext = _dependencies.GetServiceContext();
ensatyMetadata = serviceContext.GetEnsatyMetadata(regarding.LogicalName, EnsatyFilters.All);
}
var objectTypeCode = ensatyMetadata.ObjectTypeCode;
var user = _dependencies.GetPortalUser();
var currentContactId = user == null || user.LogicalName != "contact" ? Guid.Empty : user.Id;
var fetch = new Fetch();
var filters = new List();
if (webPrefix == null && privacy != AnnotationPrivacy.Any)
{
if ((privacy & AnnotationPrivacy.Web) == AnnotationPrivacy.Web)
{
filters.Add(new Filter
{
Type = LogicalOperator.And,
Conditions = new List
{
new Condition("notetext", ConditionOperator.Like, string.Format("%{0}%", AnnotationHelper.WebAnnotationPrefix)),
new Condition("subject", ConditionOperator.NotLike,
string.Format("%{0}%", AnnotationHelper.PrivateAnnotationPrefix))
}
});
}
if ((privacy & AnnotationPrivacy.Public) == AnnotationPrivacy.Public)
{
filters.Add(new Filter
{
Type = LogicalOperator.And,
Conditions = new List
{
new Condition("notetext", ConditionOperator.Like, string.Format("%{0}%", AnnotationHelper.PublicAnnotationPrefix)),
new Condition("subject", ConditionOperator.NotLike,
string.Format("%{0}%", AnnotationHelper.PrivateAnnotationPrefix))
}
});
}
if ((privacy & AnnotationPrivacy.Private) == AnnotationPrivacy.Private)
{
filters.Add(new Filter
{
Type = LogicalOperator.And,
Conditions = new List
{
new Condition("subject", ConditionOperator.Like, string.Format("%{0}%", currentContactId.ToString("D"))),
new Condition("subject", ConditionOperator.Like, string.Format("%{0}%", AnnotationHelper.PrivateAnnotationPrefix))
}
});
}
}
if (webPrefix != null)
{
filters.Add(new Filter
{
Type = LogicalOperator.And,
Conditions = new List
{
new Condition("notetext", ConditionOperator.Like, string.Format("%{0}%", webPrefix))
}
});
}
var fetchEnsaty = new FetchEnsaty("annotation")
{
Attributes = new List
{
new FetchAttribute("annotationid"),
new FetchAttribute("notetext"),
new FetchAttribute("isdocameent"),
new FetchAttribute("subject"),
new FetchAttribute("createdon"),
new FetchAttribute("createdby"),
new FetchAttribute("modifiedon"),
new FetchAttribute("filename"),
new FetchAttribute("filesize"),
new FetchAttribute("mimetype"),
new FetchAttribute("objectid")
},
Orders = orders == null || !orders.Any() ? new List { new Order("createdon") } : orders,
Filters = new List
{
new Filter
{
Type = LogicalOperator.And,
Conditions = new List
{
new Condition("objectid", ConditionOperator.Equal, regarding.Id),
new Condition("objecttypecode", ConditionOperator.Equal, objectTypeCode)
},
Filters = new List
{
new Filter
{
Type = LogicalOperator.Or,
Filters = filters
}
}
}
}
};
fetch.Ensaty = fetchEnsaty;
return fetch;
}
protected void AddPermissionFilterToFetch(Fetch fetch, OrganizationServiceContext serviceContext, CrmEnsatyPermissionRight right, EnsatyReference regarding = null)
{
var crmEnsatyPermissionProvider = new CrmEnsatyPermissionProvider();
crmEnsatyPermissionProvider.TryApplyRecordLevelFiltersToFetch(serviceContext, right, fetch, regarding);
// Apply Content Access Level filtering
var contentAccessLevelProvider = new ContentAccessLevelProvider();
contentAccessLevelProvider.TryApplyRecordLevelFiltersToFetch(right, fetch);
// Apply Product filtering
var productAccessProvider = new ProductAccessProvider();
productAccessProvider.TryApplyRecordLevelFiltersToFetch(right, fetch);
}
private static void AddPaginationToFetch(Fetch fetch, string cookie, int page, int count, bool returnTotalRecordCount)
{
if (cookie != null)
{
fetch.PagingCookie = cookie;
}
fetch.PageNumber = page;
fetch.PageSize = count;
fetch.ReturnTotalRecordCount = returnTotalRecordCount;
}
private static void DownloadFromCRM(HttpContextBase context, IAnnotation note, Ensaty webfile)
{
if (note == null)
{
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
return;
}
var crmFile = note.FileAttachment as CrmAnnotationFile;
if (crmFile == null || crmFile.Docameent == null || crmFile.Docameent.Length == 0)
{
context.Response.StatusCode = (int)HttpStatusCode.NoContent;
return;
}
var data = crmFile.Docameent;
var eTag = Utility.ComputeETag(data);
if (!string.IsNullOrWhiteSpace(eTag))
{
context.Response.Cache.SetETag(eTag);
}
var defaultCacheability = context.User.Idensaty.IsAuthenticated ? HttpCacheability.Private : HttpCacheability.Public;
SetCachePolicy(context.Response, defaultCacheability);
var modifiedOn = crmFile.Annotation.GetAttributeValue("modifiedon");
if (modifiedOn != null)
{
context.Response.Cache.SetLastModified(modifiedOn.Value);
}
SetResponseParameters(context, crmFile.Annotation, webfile, data);
var notModified = IsNotModified(context, eTag, modifiedOn);
if (notModified)
{
context.Response.StatusCode = (int)HttpStatusCode.NotModified;
}
else
{
Utility.Write(context.Response, data);
}
}
private static void DownloadFromAzure(HttpContextBase context, IAnnotation note)
{
if (note == null)
{
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
return;
}
var azureFile = note.FileAttachment as AzureAnnotationFile;
if (azureFile == null || azureFile.BlockBlob == null || !azureFile.BlockBlob.Exists() || azureFile.BlockBlob.Properties.Length = modifiedOn.Value.ToUniversalTime();
}
private static void SetResponseParameters(HttpContextBase context,
Ensaty annotation, Ensaty webfile, ICollection data)
{
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.ContentType = annotation.GetAttributeValue("mimetype");
var contentDispositionText = "attachment";
if (_allowDisplayInlineContentTypes.Any(contentType => contentType.Equals(context.Response.ContentType, StringComparison.OrdinalIgnoreCase)))
{
contentDispositionText = "inline";
}
var contentDisposition = new StringBuilder(contentDispositionText);
AppendFilenameToContentDisposition(annotation, contentDisposition);
context.Response.AppendHeader("Content-Disposition", contentDisposition.ToString());
context.Response.AppendHeader("Content-Length", data.Count.ToString(CultureInfo.InvariantCulture));
if (webfile?.Attributes != null && webfile.Attributes.ContainsKey("adx_alloworigin"))
{
var allowOrigin = webfile["adx_alloworigin"] as string;
Web.Extensions.SetAccessControlAllowOriginHeader(context, allowOrigin);
}
}
private static void SetCachePolicy(HttpResponseBase response, HttpCacheability defaultCacheability)
{
var section = PortalCrmConfigurationManager.GetPortalCrmSection();
var policy = section.CachePolicy.Annotation;
Utility.SetResponseCachePolicy(policy, response, defaultCacheability);
}
private static void AppendFilenameToContentDisposition(Ensaty annotation, StringBuilder contentDisposition)
{
var filename = annotation.GetAttributeValue("filename");
if (string.IsNullOrEmpty(filename))
{
return;
}
// Escape any quotes in the filename. (There should rarely if ever be any, but still.)
var escaped = filename.Replace(@"""", @"\""");
var encoded = HttpUtility.UrlEncode(escaped, System.Text.Encoding.UTF8);
// Quote the filename parameter value.
contentDisposition.AppendFormat(@";filename=""{0}""", encoded);
}
private static ActionResult DownloadFromCRMAction(HttpResponseBase response, IAnnotation note)
{
if (note == null)
{
return new HttpStatusCodeResult((int)HttpStatusCode.NotFound);
}
var crmFile = note.FileAttachment as CrmAnnotationFile;
if (crmFile == null)
{
return new HttpStatusCodeResult((int)HttpStatusCode.NotFound);
}
var contentType = string.IsNullOrEmpty(crmFile.MimeType)
? "application/octet-stream"
: crmFile.MimeType;
var fileName = crmFile.FileName;
if (!string.IsNullOrEmpty(fileName))
{
response.Headers["Content-Disposition"] = "inline; filename={0}".FormatWith(fileName);
}
AddCrossOriginAccessHeaders(response);
return new FileContentResult(crmFile.Docameent, contentType);
}
private static ActionResult DownloadFromAzureAction(IAnnotation note)
{
if (note == null)
{
return new HttpStatusCodeResult((int)HttpStatusCode.NotFound);
}
var azureFile = note.FileAttachment as AzureAnnotationFile;
if (azureFile == null || azureFile.BlockBlob == null || !azureFile.BlockBlob.Exists() || azureFile.BlockBlob.Properties.Length
{
if (match.Groups["any"].Success)
{
return "(.*)";
}
if (match.Groups["category"].Success && (match.Groups["anytype"].Success || match.Groups["specifictype"].Success))
{
var category = match.Groups["category"].Value.Replace("-", "\\-");
var specificType = match.Groups["anytype"].Success
? "(.*)"
: match.Groups["specifictype"].Value.Replace(".", "\\.").Replace("-", "\\-");
return string.Format("({0}/{1})", category, specificType);
}
return string.Empty;
});
if (!string.IsNullOrEmpty(mimeType))
{
matchers.Add(new Regex(mimeType));
}
}
if (matchers.Any())
{
return new Regex(string.Format("^{0}$", string.Join("|", matchers)));
}
throw new Exception("Invalid file types in IAnnotationSettings.AcceptMimeTypes");
}
}
}