public DataAdapterDependencies(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider,
                                       IEntityUrlProvider urlProvider, EntityReference website, EntityReference portalUser = null, RequestContext requestContext = null)
        {
            if (serviceContext == null)
            {
                throw new ArgumentNullException("serviceContext");
            }

            if (securityProvider == null)
            {
                throw new ArgumentNullException("securityProvider");
            }

            if (urlProvider == null)
            {
                throw new ArgumentNullException("urlProvider");
            }

            if (website == null)
            {
                throw new ArgumentNullException("website");
            }

            _serviceContext   = serviceContext;
            _securityProvider = securityProvider;
            _urlProvider      = urlProvider;
            _website          = website;
            _portalUser       = portalUser;
            _requestContext   = requestContext;
        }
 public DataAdapterDependencies(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider, IEntityUrlProvider urlProvider, IPortalContext portalContext, ILatestPostUrlProvider postUrlProvider = null, string portalName = null, RequestContext requestContext = null)
     : base(serviceContext, securityProvider, urlProvider, portalContext)
 {
     _postUrlProvider = postUrlProvider ?? new AnchorLatestPostUrlProvider();
     PortalName       = portalName;
     _requestContext  = requestContext;
 }
 public DataAdapterDependencies(
     OrganizationServiceContext serviceContext,
     ICrmEntitySecurityProvider securityProvider,
     IEntityUrlProvider urlProvider,
     IPortalContext portalContext,
     string portalName             = null,
     RequestContext requestContext = null)
     : base(serviceContext, securityProvider, urlProvider, portalContext, requestContext)
 {
     PortalName = portalName;
 }
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="serviceContext">An <see cref="OrganizationServiceContext"/>.</param>
 /// <param name="securityProvider">An <see cref="ICrmEntitySecurityProvider"/>.</param>
 /// <param name="httpContext">An <see cref="HttpContextBase"/>.</param>
 /// <param name="portalContext">An <see cref="IPortalContext"/> to get user and website <see cref="EntityReference"/>s from.</param>
 public DataAdapterDependencies(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider,
                                HttpContextBase httpContext, IPortalContext portalContext, RequestContext requestContext = null)
     : this(
         serviceContext,
         securityProvider,
         httpContext,
         portalContext.Website == null ? null : portalContext.Website.ToEntityReference(),
         portalContext.User != null ? portalContext.User.ToEntityReference() : null,
         requestContext : requestContext)
 {
     portalContext.ThrowOnNull("portalContext");
 }
 public DataAdapterDependencies(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider,
                                IEntityUrlProvider urlProvider, IPortalContext portalContext) : this(
         serviceContext,
         securityProvider,
         urlProvider,
         portalContext.Website == null ? null : portalContext.Website.ToEntityReference(),
         portalContext.User == null ? null : portalContext.User.ToEntityReference())
 {
     if (portalContext == null)
     {
         throw new ArgumentNullException("portalContext");
     }
 }
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="serviceContext">An <see cref="OrganizationServiceContext"/>.</param>
        /// <param name="securityProvider">An <see cref="ICrmEntitySecurityProvider"/>.</param>
        /// <param name="httpContext">An <see cref="HttpContextBase"/>.</param>
        /// <param name="website">An <see cref="EntityReference"/> to a website.</param>
        /// <param name="portalUser">An <see cref="EntityReference"/> to a portal user.</param>
        public DataAdapterDependencies(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider,
                                       HttpContextBase httpContext, EntityReference website, EntityReference portalUser = null, RequestContext requestContext = null)
        {
            serviceContext.ThrowOnNull("serviceContext");
            securityProvider.ThrowOnNull("securityProvider");
            httpContext.ThrowOnNull("httpContext");
            website.ThrowOnNull("website");

            _serviceContext   = serviceContext;
            _securityProvider = securityProvider;
            _httpContext      = httpContext;
            _website          = website;
            _portalUser       = portalUser;
            _requestContext   = requestContext;
        }
        public SingleWebsiteCmsDataServiceQueryInterceptor(string portalName)
        {
            _securityProvider = PortalCrmConfigurationManager.CreateCrmEntitySecurityProvider(portalName);
            var portal  = PortalCrmConfigurationManager.CreatePortalContext(portalName);
            var website = portal.Website;

            if (website == null)
            {
                throw new ArgumentException("The specified portal {0} doesn't have a configured website.".FormatWith(portalName), "portalName");
            }

            website.AssertEntityName("adx_website");

            _website = website.ToEntityReference();
        }
        public SingleWebsiteCmsDataServiceQueryInterceptor(string portalName)
        {
            _securityProvider = PortalCrmConfigurationManager.CreateCrmEntitySecurityProvider(portalName);
            var portal  = PortalCrmConfigurationManager.CreatePortalContext(portalName);
            var website = portal.Website;

            if (website == null)
            {
                throw new ArgumentException("The specified portal '{0}' does not have a configured website.".FormatWith(portalName), "portalName");
            }

            website.AssertEntityName("adx_website");

            var id = website.GetAttributeValue <Guid?>("adx_websiteid");

            _websiteID = id.HasValue ? id.Value : website.Id;
        }
 public DataAdapterDependencies(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider,
                                IEntityUrlProvider urlProvider, EntityReference website, EntityReference portalUser = null) : this
     (serviceContext, securityProvider, urlProvider, website, portalUser, null)
 {
 }
Exemple #10
0
 protected virtual void AssertRequestEntitySecurity(IPortalContext portal, OrganizationServiceContext serviceContext, Entity entity, ICrmEntitySecurityProvider security)
 {
     if (!security.TryAssert(serviceContext, entity, CrmEntityRight.Change))
     {
         throw new CmsEntityServiceException(HttpStatusCode.Forbidden, "Entity access denied.");
     }
 }
Exemple #11
0
        protected virtual void ProcessRequest(HttpContext context, ICmsEntityServiceProvider serviceProvider, Guid portalScopeId, IPortalContext portal, OrganizationServiceContext serviceContext, Entity entity, CmsEntityMetadata entityMetadata, ICrmEntitySecurityProvider security)
        {
            if (IsRequestMethod(context.Request, "GET"))
            {
                WriteResponse(context.Response, new JObject
                {
                    { "d", GetEntityJson(context, serviceProvider, portalScopeId, portal, serviceContext, entity, entityMetadata) }
                });

                return;
            }

            if (IsRequestMethod(context.Request, "POST"))
            {
                var preImage = entity.Clone(false);

                var extensions = UpdateEntityFromJsonRequestBody(context.Request, serviceContext, entity, entityMetadata);

                serviceProvider.InterceptChange(context, portal, serviceContext, entity, entityMetadata, CmsEntityOperation.Update, preImage);

                serviceContext.UpdateObject(entity);

                serviceProvider.InterceptExtensionChange(context, portal, serviceContext, entity, entityMetadata, extensions, CmsEntityOperation.Update);

                serviceContext.SaveChanges();

                WriteNoContentResponse(context.Response);

                return;
            }

            throw new CmsEntityServiceException(HttpStatusCode.MethodNotAllowed, "Request method {0} not allowed for this resource.".FormatWith(context.Request.HttpMethod));
        }
Exemple #12
0
 private static bool TryAssertEditable(OrganizationServiceContext serviceContext, Entity entity, ICrmEntitySecurityProvider securityProvider)
 {
     return(securityProvider.TryAssert(serviceContext, entity, CrmEntityRight.Change));
 }
Exemple #13
0
 public DataAdapterDependencies(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider, IEntityUrlProvider urlProvider, IPortalContext portalContext) : base(serviceContext, securityProvider, urlProvider, portalContext)
 {
 }
 private static IEnumerable <IWebLink> CreateWebLinkSubTree(OrganizationServiceContext serviceContext, EntityReference entity, ICrmEntitySecurityProvider securityProvider, IEntityUrlProvider urlProvider, ILookup <Guid, Entity> childWebLinkLookup)
 {
     return(childWebLinkLookup[entity.Id]
            .Select(e => CreateWebLink(serviceContext, e, securityProvider, urlProvider, childWebLinkLookup)));
 }
 public DataAdapterDependencies(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider,
                                HttpContextBase httpContext, EntityReference website, EntityReference portalUser = null)
     : this(serviceContext, securityProvider, httpContext, website, portalUser : portalUser, requestContext : null)
 {
 }
        public SecurityCrmSiteMapNodeValidator(ICrmEntitySecurityProvider securityProvider)
        {
            securityProvider.ThrowOnNull("securityProvider");

            _securityProvider = securityProvider;
        }
        protected override void AssertRequestEntitySecurity(IPortalContext portal, OrganizationServiceContext serviceContext, Entity entity, ICrmEntitySecurityProvider security)
        {
            // If the current request entity is the current website, leave security handling for later, once we have info about
            // the relationship being requested.
            if (entity.ToEntityReference().Equals(portal.Website.ToEntityReference()))
            {
                return;
            }

            base.AssertRequestEntitySecurity(portal, serviceContext, entity, security);
        }
Exemple #18
0
        protected virtual bool TryAssertReadPermission(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider, Entity forumThread, IDictionary <Guid, bool> forumPermissionCache)
        {
            if (forumThread == null)
            {
                throw new ArgumentNullException("forumThread");
            }

            if (forumThread.LogicalName != "adx_communityforumthread")
            {
                throw new ArgumentException(string.Format("Value must have logical name {0}.", forumThread.LogicalName), "forumThread");
            }

            var forumReference = forumThread.GetAttributeValue <EntityReference>("adx_forumid");

            if (forumReference == null)
            {
                throw new ArgumentException(string.Format("Value must have entity reference attribute {0}.", "adx_forumid"), "forumThread");
            }

            bool cachedResult;

            if (forumPermissionCache.TryGetValue(forumReference.Id, out cachedResult))
            {
                return(cachedResult);
            }

            var blog = forumThread.GetRelatedEntity(serviceContext, "adx_communityforum_communityforumthread");

            var result = securityProvider.TryAssert(serviceContext, blog, CrmEntityRight.Read);

            forumPermissionCache[blog.Id] = result;

            return(result);
        }
Exemple #19
0
        protected override void ProcessRequest(HttpContext context, ICmsEntityServiceProvider serviceProvider, Guid portalScopeId, IPortalContext portal, OrganizationServiceContext serviceContext, Entity entity, CmsEntityMetadata entityMetadata, ICrmEntitySecurityProvider security)
        {
            if (!(IsRequestMethod(context.Request, "POST") || IsRequestMethod(context.Request, "DELETE")))
            {
                throw new CmsEntityServiceException(HttpStatusCode.MethodNotAllowed, "Request method {0} not allowed for this resource.".FormatWith(context.Request.HttpMethod));
            }

            CrmEntityInactiveInfo inactiveInfo;

            if (CrmEntityInactiveInfo.TryGetInfo(entity.LogicalName, out inactiveInfo))
            {
                serviceContext.SetState(inactiveInfo.InactiveState, inactiveInfo.InactiveStatus, entity);

                WriteNoContentResponse(context.Response);

                return;
            }

            if (entity.LogicalName == "adx_communityforumthread")
            {
                var forum = entity.GetRelatedEntity(serviceContext, new Relationship("adx_communityforum_communityforumthread"));

                if (forum != null)
                {
                    var forumDataAdapter = new ForumDataAdapter(
                        forum.ToEntityReference(),
                        new PortalConfigurationDataAdapterDependencies(portalName: PortalName, requestContext: context.Request.RequestContext));

                    forumDataAdapter.DeleteThread(entity.ToEntityReference());

                    WriteNoContentResponse(context.Response);

                    if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
                    {
                        PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Forum, HttpContext.Current, "delete_forumthread", 1, entity.ToEntityReference(), "delete");
                    }

                    return;
                }
            }

            if (entity.LogicalName == "adx_communityforumpost")
            {
                var forumThread = entity.GetRelatedEntity(serviceContext, new Relationship("adx_communityforumthread_communityforumpost"));

                if (forumThread != null)
                {
                    var forumThreadDataAdapter = new ForumThreadDataAdapter(
                        forumThread.ToEntityReference(),
                        new PortalConfigurationDataAdapterDependencies(portalName: PortalName, requestContext: context.Request.RequestContext));

                    forumThreadDataAdapter.DeletePost(entity.ToEntityReference());

                    WriteNoContentResponse(context.Response);

                    if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
                    {
                        PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Forum, HttpContext.Current, "delete_forumpost", 1, entity.ToEntityReference(), "delete");
                    }

                    return;
                }
            }

            serviceContext.DeleteObject(entity);
            serviceContext.SaveChanges();

            WriteNoContentResponse(context.Response);

            if (FeatureCheckHelper.IsFeatureEnabled(FeatureNames.TelemetryFeatureUsage))
            {
                PortalFeatureTrace.TraceInstance.LogFeatureUsage(FeatureTraceCategory.Blog, HttpContext.Current, "delete_blogpost", 1, entity.ToEntityReference(), "delete");
            }
        }
Exemple #20
0
        private IEnumerable <IForumThread> CreateForumThreads(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider,
                                                              EntityReference website, IEnumerable <Entity> query)
        {
            var entities = query.ToArray();

            var counterStrategy       = Dependencies.GetCounterStrategy();
            var postCounts            = counterStrategy.GetForumThreadPostCounts(serviceContext, entities);
            var infos                 = serviceContext.FetchForumThreadInfos(entities.Select(e => e.Id), website.Id);
            var urlProvider           = Dependencies.GetUrlProvider();
            var latestPostUrlProvider = Dependencies.GetLatestPostUrlProvider();

            return(entities.Select(entity =>
            {
                IForumThreadInfo info;
                info = infos.TryGetValue(entity.Id, out info) ? info : new UnknownForumThreadInfo();

                int postCount;
                postCount = postCounts.TryGetValue(entity.Id, out postCount) ? postCount : 0;

                var viewEntity = new PortalViewEntity(serviceContext, entity, securityProvider, urlProvider);

                var forumThread = new ForumThread(entity, viewEntity, info, postCount, ThreadUrlProvider.GetUrl(serviceContext, entity));

                forumThread.LatestPostUrl = latestPostUrlProvider.GetLatestPostUrl(forumThread, postCount);

                return forumThread;
            }).ToArray());
        }
Exemple #21
0
 public MultipleWebsiteCmsDataServiceQueryInterceptor(string portalName)
 {
     _securityProvider = PortalCrmConfigurationManager.CreateCrmEntitySecurityProvider(portalName);
 }
Exemple #22
0
        public PortalViewEntity(OrganizationServiceContext serviceContext, Entity entity, ICrmEntitySecurityProvider securityProvider, IEntityUrlProvider urlProvider)
        {
            if (serviceContext == null)
            {
                throw new ArgumentNullException("serviceContext");
            }

            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            if (securityProvider == null)
            {
                throw new ArgumentNullException("securityProvider");
            }

            if (urlProvider == null)
            {
                throw new ArgumentNullException("urlProvider");
            }

            Entity          = entity;
            EntityReference = entity.ToEntityReference();

            _description    = new Lazy <string>(GetDescription, LazyThreadSafetyMode.None);
            _editable       = new Lazy <bool>(() => TryAssertEditable(serviceContext, entity, securityProvider), LazyThreadSafetyMode.None);
            _serviceContext = serviceContext;
            _url            = new Lazy <string>(() => urlProvider.GetUrl(serviceContext, entity));
        }
        protected virtual bool TryAssertBlogPostRight(OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider, Entity blogPost, CrmEntityRight right, IDictionary <Guid, bool> blogPermissionCache)
        {
            if (blogPost == null)
            {
                throw new ArgumentNullException("blogPost");
            }

            if (blogPost.LogicalName != "adx_blogpost")
            {
                throw new ArgumentException(string.Format("Value must have logical name {0}.", blogPost.LogicalName), "blogPost");
            }

            var blogReference = blogPost.GetAttributeValue <EntityReference>("adx_blogid");

            if (blogReference == null)
            {
                throw new ArgumentException(string.Format("Value must have entity reference attribute {0}.", "adx_blogid"), "blogPost");
            }

            bool cachedResult;

            if (blogPermissionCache.TryGetValue(blogReference.Id, out cachedResult))
            {
                return(cachedResult);
            }

            var fetch = new Fetch
            {
                Entity = new FetchEntity("adx_blog")
                {
                    Filters = new[]
                    {
                        new Filter
                        {
                            Conditions = new[]
                            {
                                new Condition("adx_blogid", ConditionOperator.Equal, blogReference.Id),
                                new Condition("statecode", ConditionOperator.Equal, 0)
                            }
                        }
                    }
                }
            };

            var blog   = serviceContext.RetrieveSingle(fetch);
            var result = securityProvider.TryAssert(serviceContext, blog, right);

            blogPermissionCache[blogReference.Id] = result;

            return(result);
        }
        protected virtual void AssertRequestEntitySecurity(IPortalContext portal, OrganizationServiceContext serviceContext, Entity entity, ICrmEntitySecurityProvider security, IWebsiteAccessPermissionProvider websiteAccess, CmsEntityRelationshipInfo relationshipInfo)
        {
            if (!entity.ToEntityReference().Equals(portal.Website.ToEntityReference()))
            {
                return;
            }

            var otherEntity = relationshipInfo.IsCollection
                                ? relationshipInfo.ReferencingEntity
                                : relationshipInfo.ReferencedEntity;

            if (string.Equals(otherEntity, "adx_contentsnippet", StringComparison.OrdinalIgnoreCase))
            {
                if (!websiteAccess.TryAssert(serviceContext, WebsiteRight.ManageContentSnippets))
                {
                    throw new CmsEntityServiceException(HttpStatusCode.Forbidden, "Manage Content Snippets permission denied.");
                }

                return;
            }

            if (string.Equals(otherEntity, "adx_sitemarker", StringComparison.OrdinalIgnoreCase))
            {
                if (!websiteAccess.TryAssert(serviceContext, WebsiteRight.ManageSiteMarkers))
                {
                    throw new CmsEntityServiceException(HttpStatusCode.Forbidden, "Manage Site Markers permission denied.");
                }

                return;
            }

            if (string.Equals(otherEntity, "adx_weblinkset", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(otherEntity, "adx_weblink", StringComparison.OrdinalIgnoreCase))
            {
                if (!websiteAccess.TryAssert(serviceContext, WebsiteRight.ManageWebLinkSets))
                {
                    throw new CmsEntityServiceException(HttpStatusCode.Forbidden, "Manage Web Link Sets permission denied.");
                }

                return;
            }

            base.AssertRequestEntitySecurity(portal, serviceContext, entity, security);
        }
 private static IWebLink CreateWebLink(OrganizationServiceContext serviceContext, Entity entity, ICrmEntitySecurityProvider securityProvider, IEntityUrlProvider urlProvider, ILookup <Guid, Entity> childWebLinkLookup)
 {
     return(new WebLink(
                entity,
                new PortalViewEntity(serviceContext, entity, securityProvider, urlProvider),
                urlProvider.GetApplicationPath(serviceContext, entity),
                CreateWebLinkSubTree(serviceContext, entity.ToEntityReference(), securityProvider, urlProvider, childWebLinkLookup)));
 }
        protected override void ProcessRequest(HttpContext context, ICmsEntityServiceProvider serviceProvider, Guid portalScopeId, IPortalContext portal, OrganizationServiceContext serviceContext, Entity entity, CmsEntityMetadata entityMetadata, ICrmEntitySecurityProvider security)
        {
            if (!IsRequestMethod(context.Request, "POST"))
            {
                throw new CmsEntityServiceException(HttpStatusCode.MethodNotAllowed, "Request method {0} not allowed for this resource.".FormatWith(context.Request.HttpMethod));
            }

            var dataAdapterDependencies =
                new PortalConfigurationDataAdapterDependencies(requestContext: context.Request.RequestContext,
                                                               portalName: PortalName);
            var annotationDataAdapter = new AnnotationDataAdapter(dataAdapterDependencies);
            var website = context.GetWebsite();

            var             location = website.Settings.Get <string>("WebFiles/StorageLocation");
            StorageLocation storageLocation;

            if (!Enum.TryParse(location, true, out storageLocation))
            {
                storageLocation = StorageLocation.CrmDocument;
            }

            var maxFileSizeErrorMessage = website.Settings.Get <string>("WebFiles/MaxFileSizeErrorMessage");

            var annotationSettings = new AnnotationSettings(dataAdapterDependencies.GetServiceContext(),
                                                            storageLocation: storageLocation, maxFileSizeErrorMessage: maxFileSizeErrorMessage);

            var files       = context.Request.Files;
            var postedFiles = new List <HttpPostedFile>();

            for (var i = 0; i < files.Count; i++)
            {
                postedFiles.Add(files[i]);
            }

            foreach (var file in postedFiles)
            {
                annotationDataAdapter.CreateAnnotation(new Annotation
                {
                    Regarding      = entity.ToEntityReference(),
                    FileAttachment = AnnotationDataAdapter.CreateFileAttachment(new HttpPostedFileWrapper(file), annotationSettings.StorageLocation)
                }, annotationSettings);
            }

            context.Response.ContentType = "text/plain";
            context.Response.Write("OK");
        }
        public ActionResult GetIndexView(string number, OrganizationServiceContext serviceContext, ICrmEntitySecurityProvider securityProvider, IEntityUrlProvider urlProvider)
        {
            var category = serviceContext.RetrieveSingle("category",
                                                         FetchAttribute.All,
                                                         new Condition("categorynumber", ConditionOperator.Equal, number));

            if (category == null)
            {
                return(RedirectToPageNotFound());
            }

            if (!securityProvider.TryAssert(serviceContext, category, CrmEntityRight.Read))
            {
                return(RedirectToAccessDeniedPage());
            }
            var categoryDataAdapter = new CategoryDataAdapter(category);

            // Retrieve related articles from knowledgearticlescategories
            var relatedArticles = categoryDataAdapter.SelectRelatedArticles();

            // Retrieve Child Categories
            var childCategories   = categoryDataAdapter.SelectChildCategories();
            var categoryViewModel = new CategoryViewModel
            {
                RelatedArticles = relatedArticles,
                ChildCategories = childCategories,
                Number          = category.GetAttributeValue <string>("categorynumber"),
                Title           = category.GetAttributeValue <string>("title")
            };

            return(View(categoryViewModel));
        }
        protected override void ProcessRequest(HttpContext context, ICmsEntityServiceProvider serviceProvider, Guid portalScopeId, IPortalContext portal, OrganizationServiceContext serviceContext, Entity entity, CmsEntityMetadata entityMetadata, ICrmEntitySecurityProvider security)
        {
            if (!IsRequestMethod(context.Request, "GET"))
            {
                throw new CmsEntityServiceException(HttpStatusCode.MethodNotAllowed, "Request method {0} not allowed for this resource.".FormatWith(context.Request.HttpMethod));
            }

            var children = GetChildren(serviceContext, entity, entityMetadata)
                           .Where(child => security.TryAssert(serviceContext, child, CrmEntityRight.Read))
                           .ToList();

            children.Sort(new EntitySiteMapDisplayOrderComparer());

            var entityMetadataCache = new Dictionary <string, CmsEntityMetadata>();

            var childInfos = children.Select(e =>
            {
                var info = new ExtendedSiteMapChildInfo
                {
                    Title             = GetChildTitle(e),
                    EntityUri         = VirtualPathUtility.ToAbsolute(CmsEntityRouteHandler.GetAppRelativePath(portalScopeId, e.ToEntityReference())),
                    HasPermission     = security.TryAssert(serviceContext, e, CrmEntityRight.Change),
                    Id                = e.Id,
                    LogicalName       = e.LogicalName,
                    HiddenFromSiteMap = e.Attributes.Contains("adx_hiddenfromsitemap") && e.GetAttributeValue <bool?>("adx_hiddenfromsitemap").GetValueOrDefault(),
                    Url               = e.Contains("adx_partialurl") ? e.GetAttributeValue <string>("adx_partialurl") : null
                };

                CmsEntityMetadata childEntityMetadata;

                if (TryGetEntityMetadata(serviceContext, e.LogicalName, entityMetadataCache, out childEntityMetadata))
                {
                    if (childEntityMetadata.HasAttribute("adx_displayorder"))
                    {
                        info.DisplayOrder             = e.Attributes.Contains("adx_displayorder") ? e.GetAttributeValue <int?>("adx_displayorder") : null;
                        info.DisplayOrderPropertyName = "adx_displayorder";
                    }
                }

                return(info);
            }).ToArray();

            var childJson = SerializeChildInfos(childInfos);

            WriteResponse(context.Response, new JObject
            {
                { "d", new JRaw(childJson) }
            });
        }
        protected override void ProcessRequest(HttpContext context, ICmsEntityServiceProvider serviceProvider, Guid portalScopeId, IPortalContext portal, OrganizationServiceContext serviceContext, Entity entity, CmsEntityMetadata entityMetadata, ICrmEntitySecurityProvider security)
        {
            var relationshipSchemaName = string.IsNullOrWhiteSpace(RelationshipSchemaName) ? context.Request.Params["relationshipSchemaName"] : RelationshipSchemaName;

            if (string.IsNullOrWhiteSpace(relationshipSchemaName))
            {
                throw new CmsEntityServiceException(HttpStatusCode.BadRequest, "Unable to determine entity relationship schema name from request.");
            }

            var match = _relationshipSchemaNameRegex.Match(relationshipSchemaName);

            if (!match.Success)
            {
                throw new CmsEntityServiceException(HttpStatusCode.BadRequest, "Unable to determine entity relationship schema name from request.");
            }

            var schemaName = match.Groups["schemaName"].Value;

            if (string.IsNullOrWhiteSpace(schemaName))
            {
                throw new CmsEntityServiceException(HttpStatusCode.BadRequest, "Unable to determine entity relationship schema name from request.");
            }

            var entityRole = match.Groups["entityRole"].Value;

            EntityRole parsedRole;

            var relationship = new Relationship(schemaName)
            {
                PrimaryEntityRole = Enum.TryParse(entityRole, true, out parsedRole) ? new EntityRole?(parsedRole) : null
            };

            CmsEntityRelationshipInfo relationshipInfo;

            if (!entityMetadata.TryGetRelationshipInfo(relationship, out relationshipInfo))
            {
                throw new CmsEntityServiceException(HttpStatusCode.NotFound, "Entity relationship not found.");
            }

            // If the current request entity is the current website, do security handling here, since we skipped it earlier.
            if (entity.ToEntityReference().Equals(portal.Website.ToEntityReference()))
            {
                AssertRequestEntitySecurity(portal, serviceContext, entity, security, CreateWebsiteAccessPermissionProvider(portal), relationshipInfo);
            }

            if (IsRequestMethod(context.Request, "GET"))
            {
                if (relationshipInfo.IsCollection)
                {
                    var readableRelatedEntities = entity.GetRelatedEntities(serviceContext, relationship)
                                                  .Where(e => security.TryAssert(serviceContext, e, CrmEntityRight.Read));

                    var entityMetadataLookup = new Dictionary <string, CmsEntityMetadata>();

                    var entityJsonObjects = readableRelatedEntities.Select(e =>
                    {
                        CmsEntityMetadata relatedEntityMetadata;

                        if (!entityMetadataLookup.TryGetValue(e.LogicalName, out relatedEntityMetadata))
                        {
                            relatedEntityMetadata = new CmsEntityMetadata(serviceContext, e.LogicalName);

                            entityMetadataLookup[e.LogicalName] = relatedEntityMetadata;
                        }

                        return(GetEntityJson(context, serviceProvider, portalScopeId, portal, serviceContext, e, relatedEntityMetadata));
                    });

                    WriteResponse(context.Response, new JObject
                    {
                        { "d", new JArray(entityJsonObjects) }
                    });
                }
                else
                {
                    var relatedEntity = entity.GetRelatedEntity(serviceContext, relationship);

                    if (relatedEntity == null)
                    {
                        throw new CmsEntityServiceException(HttpStatusCode.NotFound, "Related entity not found.");
                    }

                    if (!security.TryAssert(serviceContext, relatedEntity, CrmEntityRight.Read))
                    {
                        throw new CmsEntityServiceException(HttpStatusCode.Forbidden, "Related entity access denied.");
                    }

                    WriteResponse(context.Response, new JObject
                    {
                        { "d", GetEntityJson(context, serviceProvider, portalScopeId, portal, serviceContext, relatedEntity, new CmsEntityMetadata(serviceContext, relatedEntity.LogicalName)) }
                    });
                }

                return;
            }

            if (IsRequestMethod(context.Request, "POST"))
            {
                if (relationshipInfo.IsCollection)
                {
                    OneToManyRelationshipMetadata relationshipMetadata;

                    if (!entityMetadata.TryGetOneToManyRelationshipMetadata(relationship, out relationshipMetadata))
                    {
                        throw new CmsEntityServiceException(HttpStatusCode.BadRequest, "Unable to retrieve the one-to-many relationship metadata for relationship {0} on entity type".FormatWith(relationship.ToSchemaName("."), entity.LogicalName));
                    }

                    var relatedEntity         = CreateEntityOfType(serviceContext, relationshipMetadata.ReferencingEntity);
                    var relatedEntityMetadata = new CmsEntityMetadata(serviceContext, relatedEntity.LogicalName);

                    var extensions = UpdateEntityFromJsonRequestBody(context.Request, serviceContext, relatedEntity, relatedEntityMetadata);

                    var preImage = relatedEntity.Clone(false);

                    // Ensure the reference to the target entity is set.
                    relatedEntity.SetAttributeValue(relationshipMetadata.ReferencingAttribute, new EntityReference(entity.LogicalName, entity.GetAttributeValue <Guid>(relationshipMetadata.ReferencedAttribute)));

                    serviceProvider.InterceptChange(context, portal, serviceContext, relatedEntity, relatedEntityMetadata, CmsEntityOperation.Create, preImage);

                    serviceContext.AddObject(relatedEntity);

                    serviceProvider.InterceptExtensionChange(context, portal, serviceContext, relatedEntity, relatedEntityMetadata, extensions, CmsEntityOperation.Create);

                    serviceContext.SaveChanges();

                    var refetchedEntity = serviceContext.CreateQuery(relatedEntity.LogicalName)
                                          .FirstOrDefault(e => e.GetAttributeValue <Guid>(relatedEntityMetadata.PrimaryIdAttribute) == relatedEntity.Id);

                    if (refetchedEntity == null)
                    {
                        throw new CmsEntityServiceException(HttpStatusCode.InternalServerError, "Unable to retrieve the created entity.");
                    }

                    WriteResponse(context.Response, new JObject
                    {
                        { "d", GetEntityJson(context, serviceProvider, portalScopeId, portal, serviceContext, refetchedEntity, relatedEntityMetadata) }
                    }, HttpStatusCode.Created);
                }
                else
                {
                    OneToManyRelationshipMetadata relationshipMetadata;

                    if (!entityMetadata.TryGetManyToOneRelationshipMetadata(relationship, out relationshipMetadata))
                    {
                        throw new CmsEntityServiceException(HttpStatusCode.BadRequest, "Unable to retrieve the many-to-one relationship metadata for relationship {0} on entity type".FormatWith(relationship.ToSchemaName("."), entity.LogicalName));
                    }

                    var relatedEntity         = CreateEntityOfType(serviceContext, relationshipMetadata.ReferencedEntity);
                    var relatedEntityMetadata = new CmsEntityMetadata(serviceContext, relatedEntity.LogicalName);

                    var extensions = UpdateEntityFromJsonRequestBody(context.Request, serviceContext, relatedEntity, relatedEntityMetadata);

                    serviceProvider.InterceptChange(context, portal, serviceContext, relatedEntity, relatedEntityMetadata, CmsEntityOperation.Create);

                    serviceContext.AddObject(relatedEntity);
                    serviceContext.AddLink(relatedEntity, relationship, entity);

                    serviceProvider.InterceptExtensionChange(context, portal, serviceContext, relatedEntity, relatedEntityMetadata, extensions, CmsEntityOperation.Create);

                    serviceContext.SaveChanges();

                    var refetchedEntity = serviceContext.CreateQuery(relatedEntity.LogicalName)
                                          .FirstOrDefault(e => e.GetAttributeValue <Guid>(relatedEntityMetadata.PrimaryIdAttribute) == relatedEntity.Id);

                    if (refetchedEntity == null)
                    {
                        throw new CmsEntityServiceException(HttpStatusCode.InternalServerError, "Unable to retrieve the created entity.");
                    }

                    WriteResponse(context.Response, new JObject
                    {
                        { "d", GetEntityJson(context, serviceProvider, portalScopeId, portal, serviceContext, refetchedEntity, relatedEntityMetadata) }
                    }, HttpStatusCode.Created);
                }

                return;
            }

            throw new CmsEntityServiceException(HttpStatusCode.MethodNotAllowed, "Request method {0} not allowed for this resource.".FormatWith(context.Request.HttpMethod));
        }
        protected override void ProcessRequest(HttpContext context, ICmsEntityServiceProvider serviceProvider, Guid portalScopeId, IPortalContext portal, OrganizationServiceContext serviceContext, Entity entity, CmsEntityMetadata entityMetadata, ICrmEntitySecurityProvider security)
        {
            var attributeLogicalName = string.IsNullOrWhiteSpace(AttributeLogicalName) ? context.Request.Params["attributeLogicalName"] : AttributeLogicalName;

            if (string.IsNullOrWhiteSpace(attributeLogicalName))
            {
                throw new CmsEntityServiceException(HttpStatusCode.BadRequest, "Unable to determine entity attribute logical name from request.");
            }

            if (entityMetadata.HasAttribute(AttributeLogicalName))
            {
                if (!IsRequestMethod(context.Request, "GET"))
                {
                    throw new CmsEntityServiceException(HttpStatusCode.MethodNotAllowed, "Request method {0} not allowed for this resource.".FormatWith(context.Request.HttpMethod));
                }

                var value = entity.Attributes.Contains(attributeLogicalName) ? entity.Attributes[attributeLogicalName] : null;

                var json = new JObject
                {
                    {
                        "d", new JObject
                        {
                            { attributeLogicalName, GetValueJson(value) }
                        }
                    },
                };

                WriteResponse(context.Response, json);

                return;
            }

            throw new CmsEntityServiceException(HttpStatusCode.NotFound, "Entity attribute not found.");
        }