/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>True if deleted successfully and False otherwise.</returns> public bool Execute(DeletePageContentCommandRequest request) { UnitOfWork.BeginTransaction(); var pageContent = Repository.AsQueryable <PageContent>() .Where(f => f.Id == request.PageContentId) .Fetch(f => f.Content) .Fetch(f => f.Page) .FirstOne(); var htmlContent = pageContent.Content as HtmlContent; if (htmlContent != null) { // Check if user has confirmed the deletion of content if (!request.IsUserConfirmed && pageContent.Page.IsMasterPage) { var hasAnyChildren = contentService.CheckIfContentHasDeletingChildren(pageContent.Page.Id, pageContent.Content.Id); if (hasAnyChildren) { var message = PagesGlobalization.DeletePageContent_ContentHasChildrenContents_DeleteConfirmationMessage; var logMessage = string.Format("User is trying to delete content which has children contents. Confirmation is required. PageContentId: {0}, ContentId: {1}, PageId: {2}", request.PageContentId, pageContent.Page.Id, pageContent.Content.Id); throw new ConfirmationRequestException(() => message, logMessage); } } var draft = pageContent.Content.History != null?pageContent.Content.History.FirstOrDefault(c => c.Status == ContentStatus.Draft) : null; if (draft != null) { Repository.Delete <HtmlContent>(draft.Id, request.ContentVersion); Repository.Delete <HtmlContent>(pageContent.Content.Id, pageContent.Content.Version); } else { Repository.Delete <HtmlContent>(pageContent.Content.Id, request.ContentVersion); } } if (pageContent.Options != null) { foreach (var option in pageContent.Options) { Repository.Delete(option); } } Repository.Delete <PageContent>(pageContent.Id, request.PageContentVersion); UnitOfWork.Commit(); // Notify Events.PageEvents.Instance.OnPageContentDeleted(pageContent); if (htmlContent != null) { Events.PageEvents.Instance.OnHtmlContentDeleted(htmlContent); } return(true); }
protected virtual void GetBlogPostAndContentEntities(BlogPostViewModel request, IPrincipal principal, string[] roles, ref bool isNew, out BlogPostContent content, out PageContent pageContent, out BlogPost blogPost) { content = null; pageContent = null; // Loading blog post and it's content, or creating new, if such not exists if (!isNew) { var blogPostFuture = repository .AsQueryable <BlogPost>(b => b.Id == request.Id) .ToFuture(); content = repository .AsQueryable <BlogPostContent>(c => c.PageContents.Any(x => x.Page.Id == request.Id && !x.IsDeleted)) .ToFuture() .FirstOrDefault(); blogPost = blogPostFuture.FirstOne(); if (configuration.Security.AccessControlEnabled) { accessControlService.DemandAccess(blogPost, principal, AccessLevel.ReadWrite, roles); } if (content != null) { // Check if user has confirmed the deletion of content if (!request.IsUserConfirmed && blogPost.IsMasterPage) { var hasAnyChildren = contentService.CheckIfContentHasDeletingChildren(blogPost.Id, content.Id, request.Content); if (hasAnyChildren) { var message = PagesGlobalization.SaveContent_ContentHasChildrenContents_RegionDeleteConfirmationMessage; var logMessage = string.Format("User is trying to delete content regions which has children contents. Confirmation is required. ContentId: {0}, PageId: {1}", content.Id, blogPost.Id); throw new ConfirmationRequestException(() => message, logMessage); } } var bpRef = blogPost; var contentRef = content; pageContent = repository.FirstOrDefault <PageContent>(c => c.Page == bpRef && !c.IsDeleted && c.Content == contentRef); } } else { blogPost = new BlogPost(); } if (pageContent == null) { pageContent = new PageContent { Page = blogPost }; } }
/// <summary> /// Saves the blog post. /// </summary> /// <param name="request">The request.</param> /// <param name="principal">The principal.</param> /// <returns> /// Saved blog post entity /// </returns> public BlogPost SaveBlogPost(BlogPostViewModel request, IPrincipal principal) { string[] roles; if (request.DesirableStatus == ContentStatus.Published) { accessControlService.DemandAccess(principal, RootModuleConstants.UserRoles.PublishContent); roles = new[] { RootModuleConstants.UserRoles.PublishContent }; } else { accessControlService.DemandAccess(principal, RootModuleConstants.UserRoles.EditContent); roles = new[] { RootModuleConstants.UserRoles.EditContent }; } Layout layout; Page masterPage; LoadLayout(out layout, out masterPage); if (masterPage != null) { var level = accessControlService.GetAccessLevel(masterPage, principal); if (level < AccessLevel.Read) { var message = BlogGlobalization.SaveBlogPost_FailedToSave_InaccessibleMasterPage; const string logMessage = "Failed to save blog post. Selected master page for page layout is inaccessible."; throw new ValidationException(() => message, logMessage); } } var region = LoadRegion(layout, masterPage); var isNew = request.Id.HasDefaultValue(); var userCanEdit = securityService.IsAuthorized(RootModuleConstants.UserRoles.EditContent); // UnitOfWork.BeginTransaction(); // NOTE: this causes concurrent data exception. BlogPost blogPost; BlogPostContent content = null; PageContent pageContent = null; Pages.Models.Redirect redirectCreated = null; // Loading blog post and it's content, or creating new, if such not exists if (!isNew) { var blogPostFuture = repository .AsQueryable <BlogPost>(b => b.Id == request.Id) .ToFuture(); content = repository .AsQueryable <BlogPostContent>(c => c.PageContents.Any(x => x.Page.Id == request.Id && !x.IsDeleted)) .ToFuture() .FirstOrDefault(); blogPost = blogPostFuture.FirstOne(); if (cmsConfiguration.Security.AccessControlEnabled) { accessControlService.DemandAccess(blogPost, principal, AccessLevel.ReadWrite, roles); } if (content != null) { // Check if user has confirmed the deletion of content if (!request.IsUserConfirmed && blogPost.IsMasterPage) { var hasAnyChildren = contentService.CheckIfContentHasDeletingChildren(blogPost.Id, content.Id, request.Content); if (hasAnyChildren) { var message = PagesGlobalization.SaveContent_ContentHasChildrenContents_RegionDeleteConfirmationMessage; var logMessage = string.Format("User is trying to delete content regions which has children contents. Confirmation is required. ContentId: {0}, PageId: {1}", content.Id, blogPost.Id); throw new ConfirmationRequestException(() => message, logMessage); } } pageContent = repository.FirstOrDefault <PageContent>(c => c.Page == blogPost && !c.IsDeleted && c.Content == content); } if (userCanEdit && !string.Equals(blogPost.PageUrl, request.BlogUrl) && request.BlogUrl != null) { request.BlogUrl = urlService.FixUrl(request.BlogUrl); pageService.ValidatePageUrl(request.BlogUrl, request.Id); if (request.RedirectFromOldUrl) { var redirect = redirectService.CreateRedirectEntity(blogPost.PageUrl, request.BlogUrl); if (redirect != null) { repository.Save(redirect); redirectCreated = redirect; } } blogPost.PageUrl = urlService.FixUrl(request.BlogUrl); } } else { blogPost = new BlogPost(); } if (pageContent == null) { pageContent = new PageContent { Region = region, Page = blogPost }; } // Push to change modified data each time. blogPost.ModifiedOn = DateTime.Now; blogPost.Version = request.Version; if (userCanEdit) { blogPost.Title = request.Title; blogPost.Description = request.IntroText; blogPost.Author = request.AuthorId.HasValue ? repository.AsProxy <Author>(request.AuthorId.Value) : null; blogPost.Category = request.CategoryId.HasValue ? repository.AsProxy <Category>(request.CategoryId.Value) : null; blogPost.Image = (request.Image != null && request.Image.ImageId.HasValue) ? repository.AsProxy <MediaImage>(request.Image.ImageId.Value) : null; if (isNew || request.DesirableStatus == ContentStatus.Published) { blogPost.ActivationDate = request.LiveFromDate; blogPost.ExpirationDate = TimeHelper.FormatEndDate(request.LiveToDate); } } if (isNew) { if (!string.IsNullOrWhiteSpace(request.BlogUrl)) { blogPost.PageUrl = urlService.FixUrl(request.BlogUrl); pageService.ValidatePageUrl(blogPost.PageUrl); } else { blogPost.PageUrl = CreateBlogPermalink(request.Title); } blogPost.MetaTitle = request.MetaTitle ?? request.Title; if (masterPage != null) { blogPost.MasterPage = masterPage; masterPageService.SetPageMasterPages(blogPost, masterPage.Id); } else { blogPost.Layout = layout; } UpdateStatus(blogPost, request.DesirableStatus); AddDefaultAccessRules(blogPost, principal, masterPage); } else if (request.DesirableStatus == ContentStatus.Published || blogPost.Status == PageStatus.Preview) { // Update only if publishing or current status is preview. // Else do not change, because it may change from published to draft status UpdateStatus(blogPost, request.DesirableStatus); } // Create content. var newContent = new BlogPostContent { Id = content != null ? content.Id : Guid.Empty, Name = request.Title, Html = request.Content ?? string.Empty, EditInSourceMode = request.EditInSourceMode, ActivationDate = request.LiveFromDate, ExpirationDate = TimeHelper.FormatEndDate(request.LiveToDate) }; // Preserve content if user is not authorized to change it. if (!userCanEdit) { if (content == null) { throw new SecurityException("Forbidden: Access is denied."); // User has no rights to create new content. } var contentToPublish = (BlogPostContent)(content.History != null ? content.History.FirstOrDefault(c => c.Status == ContentStatus.Draft) ?? content : content); newContent.Name = contentToPublish.Name; newContent.Html = contentToPublish.Html; } content = (BlogPostContent)contentService.SaveContentWithStatusUpdate(newContent, request.DesirableStatus); pageContent.Content = content; blogPost.PageUrlHash = blogPost.PageUrl.UrlHash(); blogPost.UseCanonicalUrl = request.UseCanonicalUrl; repository.Save(blogPost); repository.Save(content); repository.Save(pageContent); pageContent.Content = content; blogPost.PageContents = new [] { pageContent }; IList <Tag> newTags = null; if (userCanEdit) { tagService.SavePageTags(blogPost, request.Tags, out newTags); } // Commit unitOfWork.Commit(); // Notify about new or updated blog post. if (isNew) { Events.BlogEvents.Instance.OnBlogCreated(blogPost); } else { Events.BlogEvents.Instance.OnBlogUpdated(blogPost); } // Notify about new created tags. Events.RootEvents.Instance.OnTagCreated(newTags); // Notify about redirect creation. if (redirectCreated != null) { Events.PageEvents.Instance.OnRedirectCreated(redirectCreated); } return(blogPost); }
public SavePageHtmlContentResponse Execute(SavePageHtmlContentCommandRequest request) { var model = request.Content; if (model.DesirableStatus == ContentStatus.Published) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.PublishContent); } if (model.Id == default(Guid) || model.DesirableStatus != ContentStatus.Published) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } PageContent pageContent; var isNew = model.Id.HasDefaultValue(); if (!isNew) { var query = Repository .AsQueryable <PageContent>() .Where(f => f.Id == model.Id && !f.IsDeleted) .AsQueryable(); if (!model.IsUserConfirmed) { query = query.Fetch(f => f.Page); } if (configuration.Security.AccessControlEnabled) { query = query.Fetch(f => f.Page).ThenFetchMany(f => f.AccessRules); } pageContent = query.ToList().FirstOne(); // Check if user has confirmed the deletion of content if (!model.IsUserConfirmed && pageContent.Page.IsMasterPage) { var hasAnyChildren = contentService.CheckIfContentHasDeletingChildren(model.PageId, model.ContentId, model.PageContent); if (hasAnyChildren) { var message = PagesGlobalization.SaveContent_ContentHasChildrenContents_RegionDeleteConfirmationMessage; var logMessage = string.Format("User is trying to delete content regions which has children contents. Confirmation is required. PageContentId: {0}, ContentId: {1}, PageId: {2}", model.Id, model.ContentId, model.PageId); throw new ConfirmationRequestException(() => message, logMessage); } } } else { pageContent = new PageContent(); pageContent.Order = contentService.GetPageContentNextOrderNumber(model.PageId); if (configuration.Security.AccessControlEnabled) { pageContent.Page = Repository .AsQueryable <Root.Models.Page>(p => p.Id == model.PageId) .FetchMany(p => p.AccessRules) .ToList() .FirstOne(); } } // Demand access if (configuration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(pageContent.Page, Context.Principal, AccessLevel.ReadWrite); } // Get page as proxy, if page is not retrieved yet if (!configuration.Security.AccessControlEnabled) { pageContent.Page = Repository.AsProxy <Root.Models.Page>(model.PageId); } pageContent.Region = Repository.AsProxy <Region>(model.RegionId); var contentToSave = new HtmlContent { Id = model.ContentId, ActivationDate = model.LiveFrom, ExpirationDate = TimeHelper.FormatEndDate(model.LiveTo), Name = model.ContentName, Html = model.PageContent ?? string.Empty, UseCustomCss = model.EnabledCustomCss, CustomCss = model.CustomCss, UseCustomJs = model.EanbledCustomJs, CustomJs = model.CustomJs, EditInSourceMode = model.EditInSourceMode }; // Preserve content if user is not authorized to change it. if (!SecurityService.IsAuthorized(RootModuleConstants.UserRoles.EditContent) && model.Id != default(Guid)) { var originalContent = Repository.First <HtmlContent>(model.ContentId); var contentToPublish = (HtmlContent)(originalContent.History != null ? originalContent.History.FirstOrDefault(c => c.Status == ContentStatus.Draft) ?? originalContent : originalContent); contentToSave.Name = contentToPublish.Name; contentToSave.Html = contentToPublish.Html; contentToSave.UseCustomCss = contentToPublish.UseCustomCss; contentToSave.CustomCss = contentToPublish.CustomCss; contentToSave.UseCustomJs = contentToPublish.UseCustomJs; contentToSave.CustomJs = contentToPublish.CustomJs; contentToSave.EditInSourceMode = contentToPublish.EditInSourceMode; } UnitOfWork.BeginTransaction(); pageContent.Content = contentService.SaveContentWithStatusUpdate( contentToSave, model.DesirableStatus); optionsService.SaveChildContentOptions(pageContent.Content, request.ChildContentOptionValues, model.DesirableStatus); if (pageContent.Content.ContentRegions != null && pageContent.Content.ContentRegions.Count > 0) { if (!pageContent.Page.IsMasterPage) { var logMessage = string.Format("Dynamic regions are not allowed. Page: {0}, Content: {1}", pageContent.Page, pageContent.Id); throw new ValidationException(() => PagesGlobalization.SaveContent_DynamicRegionsAreNotAllowed_Message, logMessage); } } Repository.Save(pageContent); UnitOfWork.Commit(); // Notify. if (model.DesirableStatus != ContentStatus.Preview) { if (isNew) { Events.PageEvents.Instance.OnHtmlContentCreated((HtmlContent)pageContent.Content); Events.PageEvents.Instance.OnPageContentInserted(pageContent); } else { Events.PageEvents.Instance.OnHtmlContentUpdated((HtmlContent)pageContent.Content); } } return(new SavePageHtmlContentResponse { PageContentId = pageContent.Id, ContentId = pageContent.Content.Id, RegionId = pageContent.Region.Id, PageId = pageContent.Page.Id }); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>True if deleted successfully and False otherwise.</returns> public bool Execute(DeletePageContentCommandRequest request) { var deletingPageContent = Repository .AsQueryable <PageContent>() .Where(f => f.Id == request.PageContentId) .Fetch(f => f.Content) .Fetch(f => f.Page) .ThenFetchMany(f => f.PageContents) .ThenFetch(f => f.Content) .ToList() .FirstOne(); if (request.ContentVersion != deletingPageContent.Content.Version) { throw new ConcurrentDataException(deletingPageContent.Content); } if (request.PageContentVersion != deletingPageContent.Version) { throw new ConcurrentDataException(deletingPageContent); } var htmlContainer = deletingPageContent.Content as IDynamicContentContainer; if (htmlContainer != null) { // Check if user has confirmed the deletion of content if (!request.IsUserConfirmed) { var hasAnyChildren = contentService.CheckIfContentHasDeletingChildren(deletingPageContent.Page.Id, deletingPageContent.Content.Id); if (hasAnyChildren) { var message = PagesGlobalization.DeletePageContent_ContentHasChildrenContents_DeleteConfirmationMessage; var logMessage = string.Format("User is trying to delete content which has children contents. Confirmation is required. PageContentId: {0}, ContentId: {1}, PageId: {2}", request.PageContentId, deletingPageContent.Page.Id, deletingPageContent.Content.Id); throw new ConfirmationRequestException(() => message, logMessage); } } } var pageContentsToDelete = new List <PageContent> { deletingPageContent }; pageContentsToDelete = RetrieveAllChildrenToDelete(deletingPageContent.Page.PageContents.ToList(), pageContentsToDelete, new[] { deletingPageContent.Id }); UnitOfWork.BeginTransaction(); var htmlContentsToDelete = new List <HtmlContent>(); pageContentsToDelete.ForEach(pageContent => { // If content is HTML content, delete HTML content var htmlContent = pageContent.Content as HtmlContent; if (htmlContent != null) { var draft = pageContent.Content.History != null ? pageContent.Content.History.FirstOrDefault(c => c.Status == ContentStatus.Draft) : null; if (draft != null) { Repository.Delete(draft); } Repository.Delete(pageContent.Content); htmlContentsToDelete.Insert(0, htmlContent); } if (pageContent.Options != null) { foreach (var option in pageContent.Options) { Repository.Delete(option); } } Repository.Delete(pageContent); }); UnitOfWork.Commit(); // Notify pageContentsToDelete.Reverse(); pageContentsToDelete.ForEach(pageContent => Events.PageEvents.Instance.OnPageContentDeleted(pageContent)); htmlContentsToDelete.ForEach(htmlContent => Events.PageEvents.Instance.OnHtmlContentDeleted(htmlContent)); return(true); }