/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The page view model.</param> /// <returns>Created page</returns> public virtual SavePageResponse Execute(AddNewPageViewModel request) { // Create / fix page url var pageUrl = request.PageUrl; var createPageUrl = (pageUrl == null); if (createPageUrl && !string.IsNullOrWhiteSpace(request.PageTitle)) { pageUrl = pageService.CreatePagePermalink(request.PageTitle, request.ParentPageUrl); } else { pageUrl = urlService.FixUrl(pageUrl); // Validate Url pageService.ValidatePageUrl(pageUrl); } var page = new PageProperties { PageUrl = pageUrl, Title = request.PageTitle, Layout = Repository.First <Root.Models.Layout>(request.TemplateId), IsPublic = true, Status = PageStatus.Unpublished }; Repository.Save(page); UnitOfWork.Commit(); // Notifying, that page is created PagesApiContext.Events.OnPageCreated(page); return(new SavePageResponse(page)); }
private string TryValidateOldUrl(string url) { if (string.IsNullOrWhiteSpace(url)) { return(null); } url = urlService.FixUrl(url); if (!urlService.ValidateInternalUrl(url)) { var serverPath = httpContextAccessor.MapPublicPath("/").TrimEnd('/'); if (url.StartsWith(serverPath) && serverPath != url) { url = url.Substring(serverPath.Length, url.Length - serverPath.Length); if (!urlService.ValidateInternalUrl(url)) { return(null); } } else { return(null); } } return(url); }
/// <summary> /// Saves SEO information. /// </summary> /// <param name="model">The SEO information model.</param> /// <returns> /// true if SEO information saved successfully; false otherwise. /// </returns> public virtual EditSeoViewModel Execute(EditSeoViewModel model) { var page = Repository.First <PageProperties>(model.PageId); bool initialHasSeo = page.HasSEO; Models.Redirect newRedirect = null; page.Version = model.Version; page.Title = model.PageTitle; model.ChangedUrlPath = urlService.FixUrl(model.ChangedUrlPath); if (!string.Equals(model.PageUrlPath, model.ChangedUrlPath)) { pageService.ValidatePageUrl(model.ChangedUrlPath, model.PageId); if (model.CreatePermanentRedirect) { var redirect = redirectService.CreateRedirectEntity(model.PageUrlPath, model.ChangedUrlPath); if (redirect != null) { Repository.Save(redirect); newRedirect = redirect; } } page.NodeCountInSitemap = model.UpdateSitemap ? sitemapService.ChangeUrl(page.PageUrl, model.ChangedUrlPath) : sitemapService.NodesWithUrl(model.ChangedUrlPath); page.PageUrl = model.ChangedUrlPath; } page.PageUrlHash = page.PageUrl.UrlHash(); page.MetaTitle = model.MetaTitle; page.MetaKeywords = model.MetaKeywords; page.MetaDescription = model.MetaDescription; page.UseCanonicalUrl = model.UseCanonicalUrl; Repository.Save(page); UnitOfWork.Commit(); // Notify about SEO change. if (page.HasSEO != initialHasSeo) { Events.PageEvents.Instance.OnPageSeoStatusChanged(page); } // Notify about new redirect creation. if (newRedirect != null) { Events.PageEvents.Instance.OnRedirectCreated(newRedirect); } return(new EditSeoViewModel { PageUrlPath = page.PageUrl }); }
/// <summary> /// Gets the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns><c>GetPageResponse</c> with page properties.</returns> public GetPageResponse Get(GetPageRequest request) { var query = repository.AsQueryable <PageProperties>(); if (request.PageId.HasValue) { query = query.Where(page => page.Id == request.PageId.Value); } else { var url = urlService.FixUrl(request.PageUrl); query = query.Where(page => page.PageUrlHash == url.UrlHash()); } var model = query .Select(page => new PageModel { Id = page.Id, Version = page.Version, CreatedBy = page.CreatedByUser, CreatedOn = page.CreatedOn, LastModifiedBy = page.ModifiedByUser, LastModifiedOn = page.ModifiedOn, PageUrl = page.PageUrl, Title = page.Title, Description = page.Description, IsPublished = page.Status == PageStatus.Published, PublishedOn = page.PublishedOn, LayoutId = page.Layout != null && !page.Layout.IsDeleted ? page.Layout.Id : (Guid?)null, MasterPageId = page.MasterPage != null && !page.MasterPage.IsDeleted ? page.MasterPage.Id : (Guid?)null, CategoryId = page.Category != null && !page.Category.IsDeleted ? page.Category.Id : (Guid?)null, CategoryName = page.Category != null && !page.Category.IsDeleted ? page.Category.Name : null, MainImageId = page.Image != null && !page.Image.IsDeleted ? page.Image.Id : (Guid?)null, MainImageUrl = page.Image != null && !page.Image.IsDeleted ? page.Image.PublicUrl : null, MainImageThumbnauilUrl = page.Image != null && !page.Image.IsDeleted ? page.Image.PublicThumbnailUrl : null, MainImageThumbnailUrl = page.Image != null && !page.Image.IsDeleted ? page.Image.PublicThumbnailUrl : null, MainImageCaption = page.Image != null && !page.Image.IsDeleted ? page.Image.Caption : null, IsArchived = page.IsArchived, IsMasterPage = page.IsMasterPage, LanguageId = page.Language != null ? page.Language.Id : (Guid?)null, LanguageCode = page.Language != null ? page.Language.Code : null, LanguageGroupIdentifier = page.LanguageGroupIdentifier }) .FirstOne(); model.MainImageUrl = fileUrlResolver.EnsureFullPathUrl(model.MainImageUrl); model.MainImageThumbnauilUrl = fileUrlResolver.EnsureFullPathUrl(model.MainImageThumbnauilUrl); model.MainImageThumbnailUrl = fileUrlResolver.EnsureFullPathUrl(model.MainImageThumbnailUrl); return(new GetPageResponse { Data = model }); }
private string FixUrl(string url) { foreach (var ending in new[] { ".asp", ".aspx", ".php", ".htm", ".html" }) { if (url.EndsWith(ending)) { url = url.Substring(0, url.LastIndexOf(ending, StringComparison.InvariantCulture)); } } url = urlService.FixUrl(url); return(url); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The page view model.</param> /// <returns>Created page</returns> public virtual SavePageResponse Execute(AddNewPageViewModel request) { // Create / fix page url var pageUrl = request.PageUrl; var createPageUrl = (pageUrl == null); if (createPageUrl && !string.IsNullOrWhiteSpace(request.PageTitle)) { pageUrl = pageService.CreatePagePermalink(request.PageTitle, request.ParentPageUrl); } else { pageUrl = urlService.FixUrl(pageUrl); // Validate Url pageService.ValidatePageUrl(pageUrl); } var page = new PageProperties { PageUrl = pageUrl, PageUrlLowerTrimmed = pageUrl.LowerTrimmedUrl(), Title = request.PageTitle, MetaTitle = request.PageTitle, Layout = Repository.First <Root.Models.Layout>(request.TemplateId), Status = PageStatus.Unpublished }; var parentOptions = Repository .AsQueryable <LayoutOption>(o => o.Layout.Id == request.TemplateId) .ToList(); optionService.SaveOptionValues(request.OptionValues, null, parentOptions, () => new PageOption { Page = page }); Repository.Save(page); // Update access control if enabled: if (cmsConfiguration.AccessControlEnabled) { accessControlService.UpdateAccessControl(request.UserAccessList, page.Id); } UnitOfWork.Commit(); // Notifying, that page is created Events.PageEvents.Instance.OnPageCreated(page); return(new SavePageResponse(page)); }
private System.Guid?GetPageLanguageGroupIdentifier(GetPageTranslationsRequest request) { // Get page language group identifier var query = repository.AsQueryable <Module.Pages.Models.PageProperties>(); if (request.PageId.HasValue) { query = query.Where(p => p.Id == request.PageId.Value); } else { var url = urlService.FixUrl(request.PageUrl); query = query.Where(p => p.PageUrl == url); } return(query.Select(p => p.LanguageGroupIdentifier).FirstOrDefault()); }
public PageExistsResponse Get(PageExistsRequest request) { var url = urlService.FixUrl(request.PageUrl); var id = repository .AsQueryable <Module.Root.Models.Page>(p => p.PageUrlHash == url.UrlHash()) .Select(p => p.Id) .FirstOrDefault(); return(new PageExistsResponse { Data = new PageModel { Exists = !id.HasDefaultValue(), PageId = !id.HasDefaultValue() ? id : (System.Guid?)null } }); }
public GetPageResponse Get(GetPageRequest request) { var query = repository.AsQueryable <Module.Pages.Models.PageProperties>(); if (request.PageId.HasValue) { query = query.Where(page => page.Id == request.PageId.Value); } else { var url = urlService.FixUrl(request.PageUrl); query = query.Where(page => page.PageUrl == url); } var model = query .Select(page => new PageModel { Id = page.Id, Version = page.Version, CreatedBy = page.CreatedByUser, CreatedOn = page.CreatedOn, LastModifiedBy = page.ModifiedByUser, LastModifiedOn = page.ModifiedOn, PageUrl = page.PageUrl, Title = page.Title, Description = page.Description, IsPublished = page.Status == PageStatus.Published, PublishedOn = page.PublishedOn, LayoutId = page.Layout.Id, CategoryId = page.Category.Id, CategoryName = page.Category.Name, MainImageId = page.Image.Id, MainImageUrl = page.Image.PublicUrl, MainImageThumbnauilUrl = page.Image.PublicThumbnailUrl, MainImageCaption = page.Image.Caption, IsArchived = page.IsArchived }) .FirstOne(); return(new GetPageResponse { Data = model }); }
/// <summary> /// Finds the redirect. /// </summary> /// <param name="source">The source url.</param> /// <returns> /// Destination url /// </returns> public string FindRedirect(string source) { string redirectDestinationUrl = null; var useCache = cmsConfiguration.Cache.Enabled; if (urlService.ValidateInternalUrl(source)) { source = urlService.FixUrl(source); } if (useCache) { var redirects = cacheService.Get(cacheKey, cmsConfiguration.Cache.Timeout, () => redirectService.GetAllRedirects()); redirectDestinationUrl = redirects.Where(x => x.PageUrl.Equals(source, StringComparison.InvariantCultureIgnoreCase)).Select(x => x.RedirectUrl).FirstOrDefault(); } else { return(redirectService.GetRedirect(source)); } return(redirectDestinationUrl); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>Save response.</returns> /// <exception cref="CmsException">Failed to save page properties.</exception> public SavePageResponse Execute(EditPagePropertiesViewModel request) { var isMultilanguageEnabled = cmsConfiguration.EnableMultilanguage; ValidateRequest(request, isMultilanguageEnabled); var pageQuery = Repository.AsQueryable <PageProperties>(p => p.Id == request.Id) .FetchMany(p => p.Options) .Fetch(p => p.Layout) .ThenFetchMany(l => l.LayoutOptions) .FetchMany(p => p.MasterPages) .AsQueryable(); if (cmsConfiguration.Security.AccessControlEnabled) { pageQuery = pageQuery.FetchMany(f => f.AccessRules); } var page = pageQuery.ToList().FirstOne(); var beforeChange = new UpdatingPagePropertiesModel(page); var roles = page.IsMasterPage ? new[] { RootModuleConstants.UserRoles.EditContent, RootModuleConstants.UserRoles.PublishContent, RootModuleConstants.UserRoles.Administration } : new[] { RootModuleConstants.UserRoles.EditContent, RootModuleConstants.UserRoles.PublishContent }; if (cmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(page, Context.Principal, AccessLevel.ReadWrite, roles); } else { AccessControlService.DemandAccess(Context.Principal, roles); } var canEdit = page.IsMasterPage ? SecurityService.IsAuthorized( Context.Principal, RootModuleConstants.UserRoles.MultipleRoles(RootModuleConstants.UserRoles.EditContent, RootModuleConstants.UserRoles.Administration)) : SecurityService.IsAuthorized(Context.Principal, RootModuleConstants.UserRoles.EditContent); IList <PageProperties> translations = null; if (canEdit && isMultilanguageEnabled && !page.IsMasterPage) { translations = LoadAndValidateTranslations(page, request); } // Load master pages for updating page's master path and page's children master path IList <Guid> newMasterIds; IList <Guid> oldMasterIds; IList <Guid> childrenPageIds; IList <MasterPage> existingChildrenMasterPages; masterPageService.PrepareForUpdateChildrenMasterPages(page, request.MasterPageId, out newMasterIds, out oldMasterIds, out childrenPageIds, out existingChildrenMasterPages); IList <SitemapNode> updatedNodes = null; // Start transaction, only when everything is already loaded UnitOfWork.BeginTransaction(); Models.Redirect redirectCreated = null; var initialSeoStatus = page.HasSEO; request.PageUrl = urlService.FixUrl(request.PageUrl); if (canEdit && !string.Equals(page.PageUrl, request.PageUrl)) { pageService.ValidatePageUrl(request.PageUrl, request.Id); if (request.RedirectFromOldUrl) { var redirect = redirectService.CreateRedirectEntity(page.PageUrl, request.PageUrl); if (redirect != null) { Repository.Save(redirect); redirectCreated = redirect; } } if (request.UpdateSitemap) { updatedNodes = sitemapService.ChangeUrlsInAllSitemapsNodes(page.PageUrl, request.PageUrl); } page.PageUrl = request.PageUrl; } List <PageProperties> updatePageTranslations = null; if (canEdit) { page.PageUrlHash = page.PageUrl.UrlHash(); page.ForceAccessProtocol = request.ForceAccessProtocol; categoryService.CombineEntityCategories <PageProperties, PageCategory>(page, request.Categories); page.Title = request.PageName; page.CustomCss = request.PageCSS; page.CustomJS = request.PageJavascript; masterPageService.SetMasterOrLayout(page, request.MasterPageId, request.TemplateId); if (isMultilanguageEnabled && !page.IsMasterPage) { updatePageTranslations = UpdatePageTranslations(page, translations, request); } } var publishDraftContent = false; if (request.CanPublishPage && !page.IsMasterPage) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.PublishContent); if (request.IsPagePublished) { if (page.Status != PageStatus.Published) { page.Status = PageStatus.Published; page.PublishedOn = DateTime.Now; publishDraftContent = true; } } else { page.Status = PageStatus.Unpublished; } } IList <PageOption> pageOptions = page.Options.Distinct().ToList(); if (canEdit) { if (!page.IsMasterPage) { page.UseNoFollow = request.UseNoFollow; page.UseNoIndex = request.UseNoIndex; page.IsArchived = request.IsArchived; } page.UseCanonicalUrl = request.UseCanonicalUrl; page.Version = request.Version; page.Image = request.Image != null && request.Image.ImageId.HasValue ? Repository.AsProxy <MediaImage>(request.Image.ImageId.Value) : null; page.SecondaryImage = request.SecondaryImage != null && request.SecondaryImage.ImageId.HasValue ? Repository.AsProxy <MediaImage>(request.SecondaryImage.ImageId.Value) : null; page.FeaturedImage = request.FeaturedImage != null && request.FeaturedImage.ImageId.HasValue ? Repository.AsProxy <MediaImage>(request.FeaturedImage.ImageId.Value) : null; pageOptions = optionService.SaveOptionValues(request.OptionValues, pageOptions, () => new PageOption { Page = page }); if (cmsConfiguration.Security.AccessControlEnabled) { page.AccessRules.RemoveDuplicateEntities(); var accessRules = request.UserAccessList != null?request.UserAccessList.Cast <IAccessRule>().ToList() : null; accessControlService.UpdateAccessControl(page, accessRules); } } // Notify about page properties changing. var cancelEventArgs = Events.PageEvents.Instance.OnPagePropertiesChanging(beforeChange, new UpdatingPagePropertiesModel(page)); if (cancelEventArgs.Cancel) { Context.Messages.AddError(cancelEventArgs.CancellationErrorMessages.ToArray()); return(null); } Repository.Save(page); IList <Tag> newTags = null; if (canEdit) { masterPageService.UpdateChildrenMasterPages(existingChildrenMasterPages, oldMasterIds, newMasterIds, childrenPageIds); tagService.SavePageTags(page, request.Tags, out newTags); } if (publishDraftContent) { contentService.PublishDraftContent(page.Id); } UnitOfWork.Commit(); // Notify about page properties change. page.Options = pageOptions; Events.PageEvents.Instance.OnPagePropertiesChanged(page); // Notify about translation properties changed if (updatePageTranslations != null) { updatePageTranslations.ForEach(Events.PageEvents.Instance.OnPagePropertiesChanged); } // Notify about redirect creation. if (redirectCreated != null) { Events.PageEvents.Instance.OnRedirectCreated(redirectCreated); } // Notify about SEO status change. if (initialSeoStatus != page.HasSEO) { Events.PageEvents.Instance.OnPageSeoStatusChanged(page); } // Notify about new tags. Events.RootEvents.Instance.OnTagCreated(newTags); // Notify about updated sitemap nodes. if (updatedNodes != null) { var updatedSitemaps = new List <Models.Sitemap>(); foreach (var node in updatedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeUpdated(node); if (!updatedSitemaps.Contains(node.Sitemap)) { updatedSitemaps.Add(node.Sitemap); } } foreach (var updatedSitemap in updatedSitemaps) { Events.SitemapEvents.Instance.OnSitemapUpdated(updatedSitemap); } } return(new SavePageResponse(page)); }
/// <summary> /// Saves SEO information. /// </summary> /// <param name="model">The SEO information model.</param> /// <returns> /// true if SEO information saved successfully; false otherwise. /// </returns> public virtual EditSeoViewModel Execute(EditSeoViewModel model) { var page = Repository.First <PageProperties>(model.PageId); bool initialHasSeo = page.HasSEO; Models.Redirect newRedirect = null; page.Version = model.Version; page.Title = model.PageTitle; model.ChangedUrlPath = urlService.FixUrl(model.ChangedUrlPath); IList <SitemapNode> updatedNodes = null; if (!string.Equals(model.PageUrlPath, model.ChangedUrlPath)) { pageService.ValidatePageUrl(model.ChangedUrlPath, model.PageId); if (model.CreatePermanentRedirect) { var redirect = redirectService.CreateRedirectEntity(model.PageUrlPath, model.ChangedUrlPath); if (redirect != null) { Repository.Save(redirect); newRedirect = redirect; } } if (model.UpdateSitemap) { updatedNodes = sitemapService.ChangeUrlsInAllSitemapsNodes(page.PageUrl, model.ChangedUrlPath); } page.PageUrl = model.ChangedUrlPath; } page.PageUrlHash = page.PageUrl.UrlHash(); page.MetaTitle = model.MetaTitle; page.MetaKeywords = model.MetaKeywords; page.MetaDescription = model.MetaDescription; page.UseCanonicalUrl = model.UseCanonicalUrl; Repository.Save(page); UnitOfWork.Commit(); // Notify about SEO change. if (page.HasSEO != initialHasSeo) { Events.PageEvents.Instance.OnPageSeoStatusChanged(page); } // Notify about new redirect creation. if (newRedirect != null) { Events.PageEvents.Instance.OnRedirectCreated(newRedirect); } // Notify about updated sitemap nodes. if (updatedNodes != null) { var updatedSitemaps = new List <Models.Sitemap>(); foreach (var node in updatedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeUpdated(node); if (!updatedSitemaps.Contains(node.Sitemap)) { updatedSitemaps.Add(node.Sitemap); } } foreach (var updatedSitemap in updatedSitemaps) { Events.SitemapEvents.Instance.OnSitemapUpdated(updatedSitemap); } } return(new EditSeoViewModel { PageUrlPath = page.PageUrl }); }
/// <summary> /// Saves SEO information. /// </summary> /// <param name="model">The SEO information model.</param> /// <returns> /// true if SEO information saved successfully; false otherwise. /// </returns> public virtual EditSeoViewModel Execute(EditSeoViewModel model) { var pageQuery = Repository.AsQueryable <PageProperties>(p => p.Id == model.PageId) .FetchMany(p => p.Options) .Fetch(p => p.Layout) .ThenFetchMany(l => l.LayoutOptions) .FetchMany(p => p.MasterPages) .AsQueryable(); if (cmsConfiguration.Security.AccessControlEnabled) { pageQuery = pageQuery.FetchMany(f => f.AccessRules); } var page = pageQuery.ToList().FirstOne(); var beforeChange = new UpdatingPagePropertiesModel(page); var roles = new[] { RootModuleConstants.UserRoles.EditContent }; if (cmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(page, Context.Principal, AccessLevel.ReadWrite, roles); } else { AccessControlService.DemandAccess(Context.Principal, roles); } bool initialHasSeo = page.HasSEO; Models.Redirect newRedirect = null; page.Version = model.Version; page.Title = model.PageTitle; model.ChangedUrlPath = urlService.FixUrl(model.ChangedUrlPath); IList <SitemapNode> updatedNodes = null; if (!string.Equals(model.PageUrlPath, model.ChangedUrlPath)) { pageService.ValidatePageUrl(model.ChangedUrlPath, model.PageId); if (model.CreatePermanentRedirect) { var redirect = redirectService.CreateRedirectEntity(model.PageUrlPath, model.ChangedUrlPath); if (redirect != null) { Repository.Save(redirect); newRedirect = redirect; } } if (model.UpdateSitemap) { updatedNodes = sitemapService.ChangeUrlsInAllSitemapsNodes(page.PageUrl, model.ChangedUrlPath); } page.PageUrl = model.ChangedUrlPath; } page.PageUrlHash = page.PageUrl.UrlHash(); page.MetaTitle = model.MetaTitle; page.MetaKeywords = model.MetaKeywords; page.MetaDescription = model.MetaDescription; page.UseCanonicalUrl = model.UseCanonicalUrl; // Notify about page properties changing. var cancelEventArgs = Events.PageEvents.Instance.OnPagePropertiesChanging(beforeChange, new UpdatingPagePropertiesModel(page)); if (cancelEventArgs.Cancel) { Context.Messages.AddError(cancelEventArgs.CancellationErrorMessages.ToArray()); return(null); } Repository.Save(page); UnitOfWork.Commit(); Events.PageEvents.Instance.OnPagePropertiesChanged(page); // Notify about SEO change. if (page.HasSEO != initialHasSeo) { Events.PageEvents.Instance.OnPageSeoStatusChanged(page); } // Notify about new redirect creation. if (newRedirect != null) { Events.PageEvents.Instance.OnRedirectCreated(newRedirect); } // Notify about updated sitemap nodes. if (updatedNodes != null) { var updatedSitemaps = new List <Models.Sitemap>(); foreach (var node in updatedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeUpdated(node); if (!updatedSitemaps.Contains(node.Sitemap)) { updatedSitemaps.Add(node.Sitemap); } } foreach (var updatedSitemap in updatedSitemaps) { Events.SitemapEvents.Instance.OnSitemapUpdated(updatedSitemap); } } return(new EditSeoViewModel { PageUrlPath = page.PageUrl }); }
/// <summary> /// Executes a command to save a redirect. /// </summary> /// <param name="request">The redirect view model.</param> /// <returns> /// Saved redirect view model. /// </returns> public SiteSettingRedirectViewModel Execute(SiteSettingRedirectViewModel request) { Models.Redirect redirect; request.PageUrl = urlService.FixUrl(request.PageUrl); request.RedirectUrl = urlService.FixUrl(request.RedirectUrl); // Validate request if (!urlService.ValidateUrl(request.PageUrl)) { var message = PagesGlobalization.SaveRedirect_InvalidPageUrl_Message; var logMessage = string.Format("Invalid page url {0}.", request.PageUrl); throw new ValidationException(() => message, logMessage); } if (!urlService.ValidateUrl(request.RedirectUrl)) { var message = PagesGlobalization.SaveRedirect_InvalidRedirectUrl_Message; var logMessage = string.Format("Invalid redirect url {0}.", request.RedirectUrl); throw new ValidationException(() => message, logMessage); } // Validate for url patterns string patternsValidationMessage; if (!urlService.ValidateUrlPatterns(request.PageUrl, out patternsValidationMessage)) { var logMessage = string.Format("{0}. URL: {1}.", patternsValidationMessage, request.PageUrl); throw new ValidationException(() => patternsValidationMessage, logMessage); } if (!urlService.ValidateUrlPatterns(request.RedirectUrl, out patternsValidationMessage, PagesGlobalization.SaveRedirect_RedirectUrl_Name)) { var logMessage = string.Format("{0}. URL: {1}.", patternsValidationMessage, request.PageUrl); throw new ValidationException(() => patternsValidationMessage, logMessage); } redirectService.ValidateRedirectExists(request.PageUrl, request.Id); redirectService.ValidateForCircularLoop(request.PageUrl, request.RedirectUrl, request.Id); if (request.Id.HasDefaultValue()) { redirect = new Models.Redirect(); } else { redirect = Repository.First <Models.Redirect>(request.Id); } redirect.Version = request.Version; redirect.PageUrl = request.PageUrl; redirect.RedirectUrl = request.RedirectUrl; Repository.Save(redirect); UnitOfWork.Commit(); // Notify. if (request.Id.HasDefaultValue()) { PagesApiContext.Events.OnRedirectCreated(redirect); } else { PagesApiContext.Events.OnRedirectUpdated(redirect); } return(new SiteSettingRedirectViewModel { Id = redirect.Id, Version = redirect.Version, PageUrl = redirect.PageUrl, RedirectUrl = redirect.RedirectUrl }); }
/// <summary> /// Deletes the page. /// </summary> /// <param name="model">The model.</param> /// <param name="principal">The principal.</param> /// <param name="messages">The messages.</param> /// <returns> /// Delete result /// </returns> /// <exception cref="ConcurrentDataException"></exception> /// <exception cref="System.ComponentModel.DataAnnotations.ValidationException"> /// </exception> public bool DeletePage(DeletePageViewModel model, IPrincipal principal, IMessagesIndicator messages = null) { var languagesFuture = repository.AsQueryable <Language>().ToFuture(); var page = repository .AsQueryable <PageProperties>(p => p.Id == model.PageId) .FetchMany(p => p.PageContents) .ThenFetch(pc => pc.Content) .ToFuture() .FirstOne(); if (model.Version > 0 && page.Version != model.Version) { throw new ConcurrentDataException(page); } if (page.IsMasterPage && repository.AsQueryable <MasterPage>(mp => mp.Master == page).Any()) { var message = PagesGlobalization.DeletePageCommand_MasterPageHasChildren_Message; var logMessage = string.Format("Failed to delete page. Page is selected as master page. Id: {0} Url: {1}", page.Id, page.PageUrl); throw new ValidationException(() => message, logMessage); } var isRedirectInternal = false; if (!string.IsNullOrWhiteSpace(model.RedirectUrl)) { isRedirectInternal = urlService.ValidateInternalUrl(model.RedirectUrl); if (!isRedirectInternal && urlService.ValidateInternalUrl(urlService.FixUrl(model.RedirectUrl))) { isRedirectInternal = true; } if (isRedirectInternal) { model.RedirectUrl = urlService.FixUrl(model.RedirectUrl); } } if (model.UpdateSitemap) { accessControlService.DemandAccess(principal, RootModuleConstants.UserRoles.EditContent); } var sitemaps = new Dictionary <Sitemap, bool>(); var sitemapNodes = sitemapService.GetNodesByPage(page); if (model.UpdateSitemap) { sitemapNodes.Select(node => node.Sitemap) .Distinct() .ToList() .ForEach( sitemap => sitemaps.Add( sitemap, !cmsConfiguration.Security.AccessControlEnabled || accessControlService.GetAccessLevel(sitemap, principal) == AccessLevel.ReadWrite)); foreach (var node in sitemapNodes) { if (sitemaps[node.Sitemap] && node.ChildNodes.Count > 0) { var logMessage = string.Format("In {0} sitemap node {1} has {2} child nodes.", node.Sitemap.Id, node.Id, node.ChildNodes.Count); throw new ValidationException(() => PagesGlobalization.DeletePageCommand_SitemapNodeHasChildNodes_Message, logMessage); } } } unitOfWork.BeginTransaction(); // Update sitemap nodes IList <SitemapNode> updatedNodes = new List <SitemapNode>(); IList <SitemapNode> deletedNodes = new List <SitemapNode>(); UpdateSitemapNodes(model, page, sitemapNodes, sitemaps, languagesFuture.ToList(), updatedNodes, deletedNodes); Redirect redirect; if (!string.IsNullOrWhiteSpace(model.RedirectUrl)) { if (string.Equals(page.PageUrl, model.RedirectUrl, StringComparison.OrdinalIgnoreCase)) { var logMessage = string.Format("Circular redirect loop from url {0} to url {0}.", model.RedirectUrl); throw new ValidationException(() => PagesGlobalization.ValidatePageUrlCommand_SameUrlPath_Message, logMessage); } // Validate url if (!urlService.ValidateExternalUrl(model.RedirectUrl)) { var logMessage = string.Format("Invalid redirect url {0}.", model.RedirectUrl); throw new ValidationException(() => PagesGlobalization.ValidatePageUrlCommand_InvalidUrlPath_Message, logMessage); } string patternsValidationMessage; if (isRedirectInternal && !urlService.ValidateUrlPatterns(model.RedirectUrl, out patternsValidationMessage, PagesGlobalization.DeletePage_RedirectUrl_Name)) { var logMessage = string.Format("{0}. URL: {1}.", patternsValidationMessage, model.RedirectUrl); throw new ValidationException(() => patternsValidationMessage, logMessage); } redirect = redirectService.GetPageRedirect(page.PageUrl); if (redirect != null) { redirect.RedirectUrl = model.RedirectUrl; } else { redirect = redirectService.CreateRedirectEntity(page.PageUrl, model.RedirectUrl); } if (redirect != null) { repository.Save(redirect); } } else { redirect = null; } // Delete child entities. if (page.PageTags != null) { foreach (var pageTag in page.PageTags) { repository.Delete(pageTag); } } var deletedPageContents = new List <PageContent>(); var htmlContentsToDelete = new List <HtmlContent>(); if (page.PageContents != null) { foreach (var pageContent in page.PageContents) { // 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(htmlContent); htmlContentsToDelete.Add(htmlContent); } repository.Delete(pageContent); deletedPageContents.Add(pageContent); } } if (page.Options != null) { foreach (var option in page.Options) { repository.Delete(option); } } if (page.AccessRules != null) { var rules = page.AccessRules.ToList(); rules.ForEach(page.RemoveRule); } if (page.MasterPages != null) { foreach (var master in page.MasterPages) { repository.Delete(master); } } // Delete page repository.Delete <Root.Models.Page>(page); // Commit unitOfWork.Commit(); var updatedSitemaps = new List <Sitemap>(); foreach (var node in updatedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeUpdated(node); if (!updatedSitemaps.Contains(node.Sitemap)) { updatedSitemaps.Add(node.Sitemap); } } foreach (var node in deletedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeDeleted(node); if (!updatedSitemaps.Contains(node.Sitemap)) { updatedSitemaps.Add(node.Sitemap); } } foreach (var updatedSitemap in updatedSitemaps) { Events.SitemapEvents.Instance.OnSitemapUpdated(updatedSitemap); } // Notifying about redirect created if (redirect != null) { Events.PageEvents.Instance.OnRedirectCreated(redirect); } // Notify about deleted page contents foreach (var deletedPageContent in deletedPageContents) { Events.PageEvents.Instance.OnPageContentDeleted(deletedPageContent); } // Notify about deleted html contents foreach (var htmlContent in htmlContentsToDelete) { Events.PageEvents.Instance.OnHtmlContentDeleted(htmlContent); } // Notifying, that page is deleted. Events.PageEvents.Instance.OnPageDeleted(page); if (sitemaps.Any(tuple => !tuple.Value) && messages != null) { // Some sitemaps where skipped, because user has no permission to edit. messages.AddSuccess(PagesGlobalization.DeletePage_SitemapSkipped_Message); } return(true); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns></returns> /// <exception cref="ConcurrentDataException"></exception> /// <exception cref="System.ComponentModel.DataAnnotations.ValidationException"> /// </exception> public virtual bool Execute(DeletePageViewModel request) { var page = Repository.First <PageProperties>(request.PageId); if (page.Version != request.Version) { throw new ConcurrentDataException(page); } if (page.IsMasterPage && Repository.AsQueryable <MasterPage>(mp => mp.Master == page).Any()) { var message = PagesGlobalization.DeletePageCommand_MasterPageHasChildren_Message; var logMessage = string.Format("Failed to delete page. Page is selected as master page. Id: {0} Url: {1}", page.Id, page.PageUrl); throw new ValidationException(() => message, logMessage); } request.RedirectUrl = urlService.FixUrl(request.RedirectUrl); if (request.UpdateSitemap) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } var sitemaps = new Dictionary <Models.Sitemap, bool>(); var sitemapNodes = sitemapService.GetNodesByPage(page); if (request.UpdateSitemap) { sitemapNodes.Select(node => node.Sitemap) .Distinct() .ToList() .ForEach( sitemap => sitemaps.Add( sitemap, !cmsConfiguration.Security.AccessControlEnabled || AccessControlService.GetAccessLevel(sitemap, Context.Principal) == AccessLevel.ReadWrite)); foreach (var node in sitemapNodes) { if (sitemaps[node.Sitemap] && node.ChildNodes.Count > 0) { var logMessage = string.Format("In {0} sitemap node {1} has {2} child nodes.", node.Sitemap.Id, node.Id, node.ChildNodes.Count); throw new ValidationException(() => PagesGlobalization.DeletePageCommand_SitemapNodeHasChildNodes_Message, logMessage); } } } UnitOfWork.BeginTransaction(); IList <SitemapNode> updatedNodes = new List <SitemapNode>(); IList <SitemapNode> deletedNodes = new List <SitemapNode>(); if (sitemapNodes != null) { // Archive sitemaps before update. sitemaps.Select(pair => pair.Key).ToList().ForEach(sitemap => sitemapService.ArchiveSitemap(sitemap.Id)); foreach (var node in sitemapNodes) { if (!node.IsDeleted) { if (request.UpdateSitemap && sitemaps[node.Sitemap]) { // Delete sitemap node. sitemapService.DeleteNode(node, ref deletedNodes); } else { // Unlink sitemap node. if (node.Page != null && node.Page.Id == page.Id) { node.Page = null; node.Url = page.PageUrl; node.UrlHash = page.PageUrlHash; Repository.Save(node); updatedNodes.Add(node); } } } } } if (!string.IsNullOrWhiteSpace(request.RedirectUrl)) { if (string.Equals(page.PageUrl, request.RedirectUrl, StringComparison.OrdinalIgnoreCase)) { var logMessage = string.Format("Circular redirect loop from url {0} to url {0}.", request.RedirectUrl); throw new ValidationException(() => PagesGlobalization.ValidatePageUrlCommand_SameUrlPath_Message, logMessage); } // Validate url if (!urlService.ValidateUrl(request.RedirectUrl)) { var logMessage = string.Format("Invalid redirect url {0}.", request.RedirectUrl); throw new ValidationException(() => PagesGlobalization.ValidatePageUrlCommand_InvalidUrlPath_Message, logMessage); } string patternsValidationMessage; if (!urlService.ValidateUrlPatterns(request.RedirectUrl, out patternsValidationMessage, PagesGlobalization.DeletePage_RedirectUrl_Name)) { var logMessage = string.Format("{0}. URL: {1}.", patternsValidationMessage, request.RedirectUrl); throw new ValidationException(() => patternsValidationMessage, logMessage); } var redirect = redirectService.GetPageRedirect(page.PageUrl); if (redirect != null) { redirect.RedirectUrl = request.RedirectUrl; } else { redirect = redirectService.CreateRedirectEntity(page.PageUrl, request.RedirectUrl); } if (redirect != null) { Repository.Save(redirect); } } // Delete child entities. if (page.PageTags != null) { foreach (var pageTag in page.PageTags) { Repository.Delete(pageTag); } } if (page.PageContents != null) { foreach (var pageContent in page.PageContents) { Repository.Delete(pageContent); } } if (page.Options != null) { foreach (var option in page.Options) { Repository.Delete(option); } } if (page.AccessRules != null) { var rules = page.AccessRules.ToList(); rules.ForEach(page.RemoveRule); } if (page.MasterPages != null) { foreach (var master in page.MasterPages) { Repository.Delete(master); } } // Delete page Repository.Delete <Root.Models.Page>(request.PageId, request.Version); // Commit UnitOfWork.Commit(); var updatedSitemaps = new List <Models.Sitemap>(); foreach (var node in updatedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeUpdated(node); if (!updatedSitemaps.Contains(node.Sitemap)) { updatedSitemaps.Add(node.Sitemap); } } foreach (var node in deletedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeDeleted(node); if (!updatedSitemaps.Contains(node.Sitemap)) { updatedSitemaps.Add(node.Sitemap); } } foreach (var updatedSitemap in updatedSitemaps) { Events.SitemapEvents.Instance.OnSitemapUpdated(updatedSitemap); } // Notifying, that page is deleted. Events.PageEvents.Instance.OnPageDeleted(page); if (sitemaps.Any(tuple => !tuple.Value)) { // Some sitemaps where skipped, because user has no permission to edit. Context.Messages.AddSuccess(PagesGlobalization.DeletePage_SitemapSkipped_Message); } return(true); }
public GetPagePropertiesResponse Get(GetPagePropertiesRequest request) { var query = repository.AsQueryable <Module.Pages.Models.PageProperties>(); if (request.PageId.HasValue) { query = query.Where(page => page.Id == request.PageId.Value); } else { var url = urlService.FixUrl(request.PageUrl); query = query.Where(page => page.PageUrlHash == url.UrlHash()); } var response = query .Select(page => new GetPagePropertiesResponse { Data = new PagePropertiesModel { Id = page.Id, Version = page.Version, CreatedBy = page.CreatedByUser, CreatedOn = page.CreatedOn, LastModifiedBy = page.ModifiedByUser, LastModifiedOn = page.ModifiedOn, PageUrl = page.PageUrl, Title = page.Title, Description = page.Description, IsPublished = page.Status == PageStatus.Published, PublishedOn = page.PublishedOn, LayoutId = page.Layout != null && !page.Layout.IsDeleted ? page.Layout.Id : Guid.Empty, CategoryId = page.Category != null && !page.Category.IsDeleted ? page.Category.Id : (Guid?)null, IsArchived = page.IsArchived, IsMasterPage = page.IsMasterPage, LanguageGroupIdentifier = page.LanguageGroupIdentifier, LanguageId = page.Language != null ? page.Language.Id : (Guid?)null, MainImageId = page.Image != null && !page.Image.IsDeleted ? page.Image.Id : (Guid?)null, FeaturedImageId = page.FeaturedImage != null && !page.FeaturedImage.IsDeleted ? page.FeaturedImage.Id : (Guid?)null, SecondaryImageId = page.SecondaryImage != null && !page.SecondaryImage.IsDeleted ? page.SecondaryImage.Id : (Guid?)null, CustomCss = page.CustomCss, CustomJavaScript = page.CustomJS, UseCanonicalUrl = page.UseCanonicalUrl, UseNoFollow = page.UseNoFollow, UseNoIndex = page.UseNoIndex }, MetaData = request.Data.IncludeMetaData ? new MetadataModel { MetaTitle = page.MetaTitle, MetaDescription = page.MetaDescription, MetaKeywords = page.MetaKeywords } : null, Category = page.Category != null && !page.Category.IsDeleted && request.Data.IncludeCategory ? new CategoryModel { Id = page.Category.Id, Version = page.Category.Version, CreatedBy = page.Category.CreatedByUser, CreatedOn = page.Category.CreatedOn, LastModifiedBy = page.Category.ModifiedByUser, LastModifiedOn = page.Category.ModifiedOn, Name = page.Category.Name } : null, Layout = request.Data.IncludeLayout && !page.Layout.IsDeleted ? new LayoutModel { Id = page.Layout.Id, Version = page.Layout.Version, CreatedBy = page.Layout.CreatedByUser, CreatedOn = page.Layout.CreatedOn, LastModifiedBy = page.Layout.ModifiedByUser, LastModifiedOn = page.Layout.ModifiedOn, Name = page.Layout.Name, LayoutPath = page.Layout.LayoutPath, PreviewUrl = page.Layout.PreviewUrl } : null, MainImage = page.Image != null && !page.Image.IsDeleted && request.Data.IncludeImages ? new ImageModel { Id = page.Image.Id, Version = page.Image.Version, CreatedBy = page.Image.CreatedByUser, CreatedOn = page.Image.CreatedOn, LastModifiedBy = page.Image.ModifiedByUser, LastModifiedOn = page.Image.ModifiedOn, Title = page.Image.Title, Caption = page.Image.Caption, Url = fileUrlResolver.EnsureFullPathUrl(page.Image.PublicUrl), ThumbnailUrl = fileUrlResolver.EnsureFullPathUrl(page.Image.PublicThumbnailUrl) } : null, FeaturedImage = page.FeaturedImage != null && !page.FeaturedImage.IsDeleted && request.Data.IncludeImages ? new ImageModel { Id = page.FeaturedImage.Id, Version = page.FeaturedImage.Version, CreatedBy = page.FeaturedImage.CreatedByUser, CreatedOn = page.FeaturedImage.CreatedOn, LastModifiedBy = page.FeaturedImage.ModifiedByUser, LastModifiedOn = page.FeaturedImage.ModifiedOn, Title = page.FeaturedImage.Title, Caption = page.FeaturedImage.Caption, Url = fileUrlResolver.EnsureFullPathUrl(page.FeaturedImage.PublicUrl), ThumbnailUrl = fileUrlResolver.EnsureFullPathUrl(page.FeaturedImage.PublicThumbnailUrl) } : null, SecondaryImage = page.SecondaryImage != null && !page.SecondaryImage.IsDeleted && request.Data.IncludeImages ? new ImageModel { Id = page.SecondaryImage.Id, Version = page.SecondaryImage.Version, CreatedBy = page.SecondaryImage.CreatedByUser, CreatedOn = page.SecondaryImage.CreatedOn, LastModifiedBy = page.SecondaryImage.ModifiedByUser, LastModifiedOn = page.SecondaryImage.ModifiedOn, Title = page.SecondaryImage.Title, Caption = page.SecondaryImage.Caption, Url = fileUrlResolver.EnsureFullPathUrl(page.SecondaryImage.PublicUrl), ThumbnailUrl = fileUrlResolver.EnsureFullPathUrl(page.SecondaryImage.PublicThumbnailUrl) } : null, Language = page.Language != null && !page.Language.IsDeleted && request.Data.IncludeLanguage ? new LanguageModel { Id = page.Language.Id, Version = page.Language.Version, CreatedBy = page.Language.CreatedByUser, CreatedOn = page.Language.CreatedOn, LastModifiedBy = page.Language.ModifiedByUser, LastModifiedOn = page.Language.ModifiedOn, Name = page.Language.Name, Code = page.Language.Code, } : null, }) .FirstOne(); if (request.Data.IncludeTags) { response.Tags = LoadTags(response.Data.Id); } if (request.Data.IncludePageContents) { response.PageContents = LoadPageContents(response.Data.Id); } if (request.Data.IncludePageOptions) { // Get layout options, page options and merge them var layoutOptions = repository .AsQueryable <LayoutOption>(lo => lo.Layout.Id == response.Data.LayoutId).ToList(); var pageOptions = repository .AsQueryable <PageOption>(p => p.Page.Id == response.Data.Id) .ToList(); response.PageOptions = optionService .GetMergedOptionValuesForEdit(layoutOptions, pageOptions) .Select(o => new OptionModel { Key = o.OptionKey, Value = o.OptionValue, DefaultValue = o.OptionDefaultValue, Type = ((Root.OptionType)(int) o.Type) }) .ToList(); } if (request.Data.IncludePageTranslations && response.Data.LanguageGroupIdentifier.HasValue) { // Get layout options, page options and merge them response.PageTranslations = repository .AsQueryable <Module.Pages.Models.PageProperties>() .Where(p => p.LanguageGroupIdentifier == response.Data.LanguageGroupIdentifier) .OrderBy(p => p.Title) .Select(p => new PageTranslationModel { Id = p.Id, Title = p.Title, PageUrl = p.PageUrl, LanguageId = p.Language != null ? p.Language.Id: (Guid?)null, LanguageCode = p.Language != null ? p.Language.Code : null, }) .ToList(); } return(response); }
private PageProperties ClonePage(System.Guid pageId, string pageTitle, string pageUrl, IEnumerable <IAccessRule> userAccessList, bool cloneAsMasterPage, System.Guid?languageId, System.Guid?languageGroupIdentifier) { var principal = securityService.GetCurrentPrincipal(); if (cloneAsMasterPage) { accessControlService.DemandAccess(principal, RootModuleConstants.UserRoles.Administration); } else { accessControlService.DemandAccess(principal, RootModuleConstants.UserRoles.EditContent); } // Create / fix page url if (pageUrl == null && !string.IsNullOrWhiteSpace(pageTitle)) { pageUrl = pageService.CreatePagePermalink(pageTitle, null, pageId, languageId); } else { pageUrl = urlService.FixUrl(pageUrl); pageService.ValidatePageUrl(pageUrl); } var page = repository .AsQueryable <PageProperties>() .Where(f => f.Id == pageId) .FetchMany(f => f.Options) .FetchMany(f => f.Categories).ThenFetch(c => c.Category).ThenFetch(c => c.CategoryTree) .FetchMany(f => f.PageContents).ThenFetch(f => f.Region) .FetchMany(f => f.PageContents).ThenFetch(f => f.Content) .FetchMany(f => f.PageContents).ThenFetchMany(f => f.Options) .FetchMany(f => f.PageTags).ThenFetch(f => f.Tag) .FetchMany(f => f.MasterPages).ThenFetch(f => f.Master) .ToList().FirstOne(); ValidateCloningPage(page, languageId, languageGroupIdentifier); unitOfWork.BeginTransaction(); // Detach page to avoid duplicate saving. repository.Detach(page); repository.Detach(page.MasterPage); page.MasterPages.ForEach(mp => repository.Detach(mp.Master)); page.PageContents.ForEach(repository.Detach); page.PageTags.ForEach(repository.Detach); page.Options.ForEach(repository.Detach); page.Categories.ForEach(repository.Detach); page.SaveUnsecured = true; var pageContents = page.PageContents.Distinct().ToList(); var pageTags = page.PageTags.Distinct().ToList(); var pageOptions = page.Options.Distinct().ToList(); var pageCategories = page.Categories.Distinct().ToList(); var masterPages = page.MasterPages != null?page.MasterPages.Distinct().ToList() : new List <MasterPage>(); // Clone page with security var newPage = ClonePageOnly(page, userAccessList, pageTitle, pageUrl, cloneAsMasterPage); if (languageId.HasValue) { if (languageId.Value.HasDefaultValue()) { newPage.Language = null; } else { newPage.Language = repository.AsProxy <Language>(languageId.Value); } } if (languageGroupIdentifier.HasValue) { newPage.LanguageGroupIdentifier = languageGroupIdentifier.Value; } else { newPage.LanguageGroupIdentifier = null; } repository.Save(newPage); // Clone contents. var createdContents = new List <Root.Models.Content>(); var createdPageContents = new List <PageContent>(); var clonedPageContentReferences = new Dictionary <PageContent, PageContent>(pageContents.Count); pageContents.ForEach(pageContent => ClonePageContent(pageContent, newPage, createdContents, createdPageContents, clonedPageContentReferences)); UpdateParentPageContents(pageContents, clonedPageContentReferences); // Clone tags. pageTags.ForEach(pageTag => ClonePageTags(pageTag, newPage)); // Clone options. pageOptions.ForEach(pageOption => ClonePageOption(pageOption, newPage)); // Clone master pages masterPages.ForEach(masterPage => CloneMasterPages(masterPage, newPage)); // Clone categories pages pageCategories.ForEach(category => CloneCategories(category, newPage)); // Set language identifier for parent page, if it hasn't and child is cloned from the parent. var parentChanged = false; if (languageGroupIdentifier.HasValue && !page.LanguageGroupIdentifier.HasValue) { page.LanguageGroupIdentifier = languageGroupIdentifier.Value; parentChanged = true; repository.Save(page); } unitOfWork.Commit(); // Fire events. (NOTE: do not change event order!!!) Events.PageEvents.Instance.OnPageCloned(newPage); createdContents.Where(c => c is HtmlContent).ForEach(c => Events.PageEvents.Instance.OnHtmlContentCreated((HtmlContent)c)); createdPageContents.ForEach(Events.PageEvents.Instance.OnPageContentInserted); // Fire event about parent page changes if (parentChanged) { Events.PageEvents.Instance.OnPagePropertiesChanged(page); } return(newPage); }
/// <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); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>Save response.</returns> /// <exception cref="CmsException">Failed to save page properties.</exception> public SavePageResponse Execute(EditPagePropertiesViewModel request) { UnitOfWork.BeginTransaction(); var page = Repository.First <PageProperties>(request.Id); Models.Redirect redirectCreated = null; bool initialSeoStatus = page.HasSEO; request.PageUrl = urlService.FixUrl(request.PageUrl); if (!string.Equals(page.PageUrl, request.PageUrl, StringComparison.OrdinalIgnoreCase)) { pageService.ValidatePageUrl(request.PageUrl, request.Id); if (request.RedirectFromOldUrl) { var redirect = redirectService.CreateRedirectEntity(page.PageUrl, request.PageUrl); if (redirect != null) { Repository.Save(redirect); redirectCreated = redirect; } } page.NodeCountInSitemap = request.UpdateSitemap ? sitemapService.ChangeUrl(page.PageUrl, request.PageUrl) : sitemapService.NodesWithUrl(request.PageUrl); page.PageUrl = request.PageUrl; } page.Layout = Repository.AsProxy <Root.Models.Layout>(request.TemplateId); page.Category = request.CategoryId.HasValue ? Repository.AsProxy <Category>(request.CategoryId.Value) : null; page.Title = request.PageName; page.CustomCss = request.PageCSS; page.CustomJS = request.PageJavascript; page.IsPublic = request.IsVisibleToEveryone; page.UseNoFollow = request.UseNoFollow; page.UseNoIndex = request.UseNoIndex; page.Version = request.Version; if (request.Image != null && request.Image.ImageId.HasValue) { page.Image = Repository.AsProxy <MediaImage>(request.Image.ImageId.Value); } else { page.Image = null; } Repository.Save(page); // Save tags IList <Root.Models.Tag> newTags; tagService.SavePageTags(page, request.Tags, out newTags); UnitOfWork.Commit(); // Notify about page properties change. PagesApiContext.Events.OnPagePropertiesChanged(page); // Notify about redirect creation. if (redirectCreated != null) { PagesApiContext.Events.OnRedirectCreated(redirectCreated); } // Notify about SEO status change. if (initialSeoStatus != page.HasSEO) { PagesApiContext.Events.OnPageSeoStatusChanged(page); } // Notify about new tags. PagesApiContext.Events.OnTagCreated(newTags); return(new SavePageResponse(page)); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>Save response.</returns> /// <exception cref="CmsException">Failed to save page properties.</exception> public SavePageResponse Execute(EditPagePropertiesViewModel request) { UnitOfWork.BeginTransaction(); var page = Repository .AsQueryable <PageProperties>(p => p.Id == request.Id) .FetchMany(p => p.Options) .Fetch(p => p.Layout).ThenFetchMany(l => l.LayoutOptions) .ToList() .FirstOrDefault(); Models.Redirect redirectCreated = null; bool initialSeoStatus = page.HasSEO; request.PageUrl = urlService.FixUrl(request.PageUrl); if (!string.Equals(page.PageUrl, request.PageUrl)) { pageService.ValidatePageUrl(request.PageUrl, request.Id); if (request.RedirectFromOldUrl) { var redirect = redirectService.CreateRedirectEntity(page.PageUrl, request.PageUrl); if (redirect != null) { Repository.Save(redirect); redirectCreated = redirect; } } page.NodeCountInSitemap = request.UpdateSitemap ? sitemapService.ChangeUrl(page.PageUrl, request.PageUrl) : sitemapService.NodesWithUrl(request.PageUrl); page.PageUrl = request.PageUrl; } page.PageUrlLowerTrimmed = page.PageUrl.LowerTrimmedUrl(); page.Layout = Repository.AsProxy <Root.Models.Layout>(request.TemplateId); page.Category = request.CategoryId.HasValue ? Repository.AsProxy <CategoryEntity>(request.CategoryId.Value) : null; page.Title = request.PageName; page.CustomCss = request.PageCSS; page.CustomJS = request.PageJavascript; if (request.IsVisibleToEveryone) { page.Status = PageStatus.Published; page.PublishedOn = DateTime.Now; } else { page.Status = PageStatus.Unpublished; } page.UseNoFollow = request.UseNoFollow; page.UseNoIndex = request.UseNoIndex; page.UseCanonicalUrl = request.UseCanonicalUrl; page.IsArchived = request.IsArchived; page.Version = request.Version; page.Image = request.Image != null && request.Image.ImageId.HasValue ? Repository.AsProxy <MediaImage>(request.Image.ImageId.Value) : null; page.SecondaryImage = request.SecondaryImage != null && request.SecondaryImage.ImageId.HasValue ? Repository.AsProxy <MediaImage>(request.SecondaryImage.ImageId.Value) : null; page.FeaturedImage = request.FeaturedImage != null && request.FeaturedImage.ImageId.HasValue ? Repository.AsProxy <MediaImage>(request.FeaturedImage.ImageId.Value) : null; var optionValues = page.Options.Distinct(); var parentOptions = page.Layout.LayoutOptions.Distinct(); optionService.SaveOptionValues(request.OptionValues, optionValues, parentOptions, () => new Root.Models.PageOption { Page = page }); if (cmsConfiguration.AccessControlEnabled) { accessControlService.UpdateAccessControl(request.UserAccessList, request.Id); } Repository.Save(page); // Save tags IList <Root.Models.Tag> newTags; tagService.SavePageTags(page, request.Tags, out newTags); UnitOfWork.Commit(); // Notify about page properties change. Events.PageEvents.Instance.OnPagePropertiesChanged(page); // Notify about redirect creation. if (redirectCreated != null) { Events.PageEvents.Instance.OnRedirectCreated(redirectCreated); } // Notify about SEO status change. if (initialSeoStatus != page.HasSEO) { Events.PageEvents.Instance.OnPageSeoStatusChanged(page); } // Notify about new tags. Events.RootEvents.Instance.OnTagCreated(newTags); return(new SavePageResponse(page)); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>Save response.</returns> /// <exception cref="CmsException">Failed to save page properties.</exception> public SavePageResponse Execute(EditPagePropertiesViewModel request) { UnitOfWork.BeginTransaction(); var pageQuery = Repository .AsQueryable <PageProperties>(p => p.Id == request.Id) .FetchMany(p => p.Options) .Fetch(p => p.Layout).ThenFetchMany(l => l.LayoutOptions) .AsQueryable(); if (cmsConfiguration.Security.AccessControlEnabled) { pageQuery = pageQuery.FetchMany(f => f.AccessRules); } var page = pageQuery.ToList().FirstOne(); if (cmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(page, Context.Principal, AccessLevel.ReadWrite, RootModuleConstants.UserRoles.EditContent, RootModuleConstants.UserRoles.PublishContent); } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent, RootModuleConstants.UserRoles.PublishContent); } Models.Redirect redirectCreated = null; bool initialSeoStatus = page.HasSEO; request.PageUrl = urlService.FixUrl(request.PageUrl); if (!string.Equals(page.PageUrl, request.PageUrl)) { pageService.ValidatePageUrl(request.PageUrl, request.Id); if (request.RedirectFromOldUrl) { var redirect = redirectService.CreateRedirectEntity(page.PageUrl, request.PageUrl); if (redirect != null) { Repository.Save(redirect); redirectCreated = redirect; } } page.NodeCountInSitemap = request.UpdateSitemap ? sitemapService.ChangeUrl(page.PageUrl, request.PageUrl) : sitemapService.NodesWithUrl(request.PageUrl); page.PageUrl = request.PageUrl; } page.PageUrlHash = page.PageUrl.UrlHash(); page.Layout = Repository.AsProxy <Root.Models.Layout>(request.TemplateId); page.Category = request.CategoryId.HasValue ? Repository.AsProxy <CategoryEntity>(request.CategoryId.Value) : null; page.Title = request.PageName; page.CustomCss = request.PageCSS; page.CustomJS = request.PageJavascript; var publishDraftContent = false; if (request.CanPublishPage) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.PublishContent); if (request.IsPagePublished) { if (page.Status != PageStatus.Published) { page.Status = PageStatus.Published; page.PublishedOn = DateTime.Now; publishDraftContent = true; } } else { page.Status = PageStatus.Unpublished; } } page.UseNoFollow = request.UseNoFollow; page.UseNoIndex = request.UseNoIndex; page.UseCanonicalUrl = request.UseCanonicalUrl; page.IsArchived = request.IsArchived; page.Version = request.Version; page.Image = request.Image != null && request.Image.ImageId.HasValue ? Repository.AsProxy <MediaImage>(request.Image.ImageId.Value) : null; page.SecondaryImage = request.SecondaryImage != null && request.SecondaryImage.ImageId.HasValue ? Repository.AsProxy <MediaImage>(request.SecondaryImage.ImageId.Value) : null; page.FeaturedImage = request.FeaturedImage != null && request.FeaturedImage.ImageId.HasValue ? Repository.AsProxy <MediaImage>(request.FeaturedImage.ImageId.Value) : null; var optionValues = page.Options.Distinct(); var parentOptions = page.Layout.LayoutOptions.Distinct(); optionService.SaveOptionValues(request.OptionValues, optionValues, parentOptions, () => new PageOption { Page = page }); if (cmsConfiguration.Security.AccessControlEnabled) { page.AccessRules.RemoveDuplicateEntities(); var accessRules = request.UserAccessList != null?request.UserAccessList.Cast <IAccessRule>().ToList() : null; accessControlService.UpdateAccessControl(page, accessRules); } Repository.Save(page); // Save tags IList <Tag> newTags; tagService.SavePageTags(page, request.Tags, out newTags); if (publishDraftContent) { contentService.PublishDraftContent(page.Id); } UnitOfWork.Commit(); // Notify about page properties change. Events.PageEvents.Instance.OnPagePropertiesChanged(page); // Notify about redirect creation. if (redirectCreated != null) { Events.PageEvents.Instance.OnRedirectCreated(redirectCreated); } // Notify about SEO status change. if (initialSeoStatus != page.HasSEO) { Events.PageEvents.Instance.OnPageSeoStatusChanged(page); } // Notify about new tags. Events.RootEvents.Instance.OnTagCreated(newTags); return(new SavePageResponse(page)); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>Blog post view model</returns> public SaveBlogPostCommandResponse Execute(BlogPostViewModel request) { if (request.DesirableStatus == ContentStatus.Published) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.PublishContent); } var layout = LoadLayout(); var region = LoadRegion(); var isNew = request.Id.HasDefaultValue(); var userCanEdit = false; if (isNew || request.DesirableStatus != ContentStatus.Published) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); userCanEdit = true; } else { 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) { blogPost = Repository.First <BlogPost>(request.Id); content = Repository.FirstOrDefault <BlogPostContent>(c => c.PageContents.Any(x => x.Page == blogPost && x.Region == region && !x.IsDeleted)); if (content != null) { pageContent = Repository.FirstOrDefault <PageContent>(c => c.Page == blogPost && c.Region == region && !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(); AddDefaultAccessRules(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 = blogService.CreateBlogPermalink(request.Title); } blogPost.MetaTitle = request.Title; blogPost.Layout = layout; UpdateStatus(blogPost, request.DesirableStatus); } else if (request.DesirableStatus == ContentStatus.Published) { 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); // Save tags if user has edit right. 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(new SaveBlogPostCommandResponse { Id = blogPost.Id, Version = blogPost.Version, Title = blogPost.Title, PageUrl = blogPost.PageUrl, ModifiedByUser = blogPost.ModifiedByUser, ModifiedOn = blogPost.ModifiedOn.ToFormattedDateString(), CreatedOn = blogPost.CreatedOn.ToFormattedDateString(), PageStatus = blogPost.Status, DesirableStatus = request.DesirableStatus, PageContentId = pageContent.Id }); }
public Redirect SaveRedirect(ViewModels.SiteSettings.SiteSettingRedirectViewModel model, bool createIfNotExists = false) { var isRedirectInternal = urlService.ValidateInternalUrl(model.RedirectUrl); if (!isRedirectInternal && urlService.ValidateInternalUrl(urlService.FixUrl(model.RedirectUrl))) { isRedirectInternal = true; } model.PageUrl = urlService.FixUrl(model.PageUrl); if (isRedirectInternal) { model.RedirectUrl = urlService.FixUrl(model.RedirectUrl); } // Validate request if (!urlService.ValidateInternalUrl(model.PageUrl)) { var message = PagesGlobalization.SaveRedirect_InvalidPageUrl_Message; var logMessage = string.Format("Invalid page url {0}.", model.PageUrl); throw new ValidationException(() => message, logMessage); } if (!urlService.ValidateExternalUrl(model.RedirectUrl)) { var message = PagesGlobalization.SaveRedirect_InvalidRedirectUrl_Message; var logMessage = string.Format("Invalid redirect url {0}.", model.RedirectUrl); throw new ValidationException(() => message, logMessage); } // Validate for url patterns string patternsValidationMessage; if (!urlService.ValidateUrlPatterns(model.PageUrl, out patternsValidationMessage)) { var logMessage = string.Format("{0}. URL: {1}.", patternsValidationMessage, model.PageUrl); throw new ValidationException(() => patternsValidationMessage, logMessage); } if (isRedirectInternal && !urlService.ValidateUrlPatterns(model.RedirectUrl, out patternsValidationMessage, PagesGlobalization.SaveRedirect_RedirectUrl_Name)) { var logMessage = string.Format("{0}. URL: {1}.", patternsValidationMessage, model.PageUrl); throw new ValidationException(() => patternsValidationMessage, logMessage); } ValidateRedirectExists(model.PageUrl, model.Id); ValidateForCircularLoop(model.PageUrl, model.RedirectUrl, model.Id); Redirect redirect = null; var isNew = model.Id.HasDefaultValue(); if (!isNew) { redirect = repository.FirstOrDefault <Redirect>(model.Id); isNew = redirect == null; if (isNew && !createIfNotExists) { throw new EntityNotFoundException(typeof(Redirect), model.Id); } } if (isNew) { redirect = new Redirect { Id = model.Id }; } if (model.Version > 0) { redirect.Version = model.Version; } redirect.PageUrl = model.PageUrl; redirect.RedirectUrl = model.RedirectUrl; repository.Save(redirect); unitOfWork.Commit(); // Notify. if (isNew) { Events.PageEvents.Instance.OnRedirectCreated(redirect); } else { Events.PageEvents.Instance.OnRedirectUpdated(redirect); } return(redirect); }
/// <summary> /// Saves the blog post. /// </summary> /// <param name="request">The request.</param> /// <param name="childContentOptionValues">The child content option values.</param> /// <param name="principal">The principal.</param> /// <param name="errorMessages">The error messages.</param> /// <returns> /// Saved blog post entity /// </returns> /// <exception cref="System.ComponentModel.DataAnnotations.ValidationException"></exception> /// <exception cref="SecurityException">Forbidden: Access is denied.</exception> public BlogPost SaveBlogPost(BlogPostViewModel request, IList <ContentOptionValuesViewModel> childContentOptionValues, IPrincipal principal, out string[] errorMessages) { errorMessages = new string[0]; 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 }; } var isNew = request.Id.HasDefaultValue(); var userCanEdit = securityService.IsAuthorized(RootModuleConstants.UserRoles.EditContent); ValidateData(isNew, request); BlogPost blogPost; BlogPostContent content; PageContent pageContent; GetBlogPostAndContentEntities(request, principal, roles, ref isNew, out content, out pageContent, out blogPost); var beforeChange = new UpdatingBlogModel(blogPost); // Master page / layout Layout layout; Page masterPage; Region region; LoadDefaultLayoutAndRegion(out layout, out masterPage, out region); 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); } } if (pageContent.Region == null) { pageContent.Region = region; } // Load master pages for updating page's master path and page's children master path IList <Guid> newMasterIds; IList <Guid> oldMasterIds; IList <Guid> childrenPageIds; IList <MasterPage> existingChildrenMasterPages; PrepareForUpdateChildrenMasterPages(isNew, blogPost, request, out newMasterIds, out oldMasterIds, out childrenPageIds, out existingChildrenMasterPages); // TODO: TEST AND TRY TO FIX IT: TRANSACTION HERE IS REQUIRED! // UnitOfWork.BeginTransaction(); // NOTE: this causes concurrent data exception. Redirect redirectCreated = null; if (!isNew && userCanEdit && !string.Equals(blogPost.PageUrl, request.BlogUrl) && !string.IsNullOrWhiteSpace(request.BlogUrl)) { 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); } // Push to change modified data each time. blogPost.ModifiedOn = DateTime.Now; 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, null, blogPost.Category != null ? (Guid?)blogPost.Category.Id : null); } 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 = SaveContentWithStatusUpdate(isNew, newContent, request, principal); pageContent.Content = content; optionService.SaveChildContentOptions(content, childContentOptionValues, request.DesirableStatus); blogPost.PageUrlHash = blogPost.PageUrl.UrlHash(); blogPost.UseCanonicalUrl = request.UseCanonicalUrl; MapExtraProperties(isNew, blogPost, content, pageContent, request, principal); // Notify about page properties changing. var cancelEventArgs = Events.BlogEvents.Instance.OnBlogChanging(beforeChange, new UpdatingBlogModel(blogPost)); if (cancelEventArgs.Cancel) { errorMessages = cancelEventArgs.CancellationErrorMessages.ToArray(); return(null); } repository.Save(blogPost); repository.Save(content); repository.Save(pageContent); masterPageService.UpdateChildrenMasterPages(existingChildrenMasterPages, oldMasterIds, newMasterIds, childrenPageIds); pageContent.Content = content; blogPost.PageContents = new [] { pageContent }; IList <Tag> newTags = null; if (userCanEdit) { newTags = SaveTags(blogPost, request); } // Commit unitOfWork.Commit(); // Notify about new created tags. Events.RootEvents.Instance.OnTagCreated(newTags); // Notify about new or updated blog post. if (isNew) { Events.BlogEvents.Instance.OnBlogCreated(blogPost); } else { Events.BlogEvents.Instance.OnBlogUpdated(blogPost); } // Notify about redirect creation. if (redirectCreated != null) { Events.PageEvents.Instance.OnRedirectCreated(redirectCreated); } return(blogPost); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The page view model.</param> /// <returns>Created page</returns> public virtual SavePageResponse Execute(AddNewPageViewModel request) { if (request.CreateMasterPage) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.Administration); } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } if (!request.MasterPageId.HasValue && !request.TemplateId.HasValue) { var message = RootGlobalization.MasterPage_Or_Layout_ShouldBeSelected_ValidationMessage; throw new ValidationException(() => message, message); } if (request.MasterPageId.HasValue && request.TemplateId.HasValue) { var logMessage = string.Format("Only one of master page and layout can be selected. LayoutId: {0}, MasterPageId: {1}", request.MasterPageId, request.TemplateId); var message = RootGlobalization.MasterPage_Or_Layout_OnlyOne_ShouldBeSelected_ValidationMessage; throw new ValidationException(() => message, logMessage); } // Create / fix page url. var pageUrl = request.PageUrl; var createPageUrl = pageUrl == null; if (createPageUrl && !string.IsNullOrWhiteSpace(request.PageTitle)) { pageUrl = pageService.CreatePagePermalink(request.PageTitle, request.ParentPageUrl, null, request.LanguageId); } else { pageUrl = urlService.FixUrl(pageUrl); // Validate Url pageService.ValidatePageUrl(pageUrl); } var page = new PageProperties { PageUrl = pageUrl, PageUrlHash = pageUrl.UrlHash(), Title = request.PageTitle, MetaTitle = request.PageTitle, Status = request.CreateMasterPage ? PageStatus.Published : PageStatus.Unpublished, IsMasterPage = request.CreateMasterPage }; if (request.MasterPageId.HasValue) { page.MasterPage = Repository.AsProxy <Root.Models.Page>(request.MasterPageId.Value); masterPageService.SetPageMasterPages(page, request.MasterPageId.Value); } else { page.Layout = Repository.AsProxy <Root.Models.Layout>(request.TemplateId.Value); } if (cmsConfiguration.EnableMultilanguage) { if (request.LanguageId.HasValue && !request.LanguageId.Value.HasDefaultValue()) { page.Language = Repository.AsProxy <Language>(request.LanguageId.Value); } } page.Options = optionService.SaveOptionValues(request.OptionValues, null, () => new PageOption { Page = page }); Repository.Save(page); // Update access control if enabled: if (cmsConfiguration.Security.AccessControlEnabled) { AccessControlService.UpdateAccessControl(page, request.UserAccessList != null ? request.UserAccessList.Cast <IAccessRule>().ToList() : null); } UnitOfWork.Commit(); // Notifying, that page is created Events.PageEvents.Instance.OnPageCreated(page); var response = new SavePageResponse(page) { IsSitemapActionEnabled = ConfigurationHelper.IsSitemapActionEnabledAfterAddingNewPage(cmsConfiguration) }; return(response); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns></returns> public virtual bool Execute(DeletePageViewModel request) { var page = Repository.First <PageProperties>(request.PageId); if (page.Version != request.Version) { throw new ConcurrentDataException(page); } request.RedirectUrl = urlService.FixUrl(request.RedirectUrl); IList <SitemapNode> sitemapNodes = null; if (request.UpdateSitemap) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } if (request.UpdateSitemap && page.NodeCountInSitemap > 0) { sitemapNodes = sitemapService.GetNodesByUrl(page.PageUrl); foreach (var node in sitemapNodes) { if (node.ChildNodes.Count > 0) { var logMessage = string.Format("Sitemap node {0} has {1} child nodes.", node.Id, node.ChildNodes.Count); throw new ValidationException(() => PagesGlobalization.DeletePageCommand_SitemapNodeHasChildNodes_Message, logMessage); } } } UnitOfWork.BeginTransaction(); if (!string.IsNullOrWhiteSpace(request.RedirectUrl)) { if (string.Equals(page.PageUrl, request.RedirectUrl, StringComparison.OrdinalIgnoreCase)) { var logMessage = string.Format("Circular redirect loop from url {0} to url {0}.", request.RedirectUrl); throw new ValidationException(() => PagesGlobalization.ValidatePageUrlCommand_SameUrlPath_Message, logMessage); } // Validate url if (!urlService.ValidateUrl(request.RedirectUrl)) { var logMessage = string.Format("Invalid redirect url {0}.", request.RedirectUrl); throw new ValidationException(() => PagesGlobalization.ValidatePageUrlCommand_InvalidUrlPath_Message, logMessage); } string patternsValidationMessage; if (!urlService.ValidateUrlPatterns(request.RedirectUrl, out patternsValidationMessage, PagesGlobalization.DeletePage_RedirectUrl_Name)) { var logMessage = string.Format("{0}. URL: {1}.", patternsValidationMessage, request.RedirectUrl); throw new ValidationException(() => patternsValidationMessage, logMessage); } var redirect = redirectService.GetPageRedirect(page.PageUrl); if (redirect != null) { redirect.RedirectUrl = request.RedirectUrl; } else { redirect = redirectService.CreateRedirectEntity(page.PageUrl, request.RedirectUrl); } if (redirect != null) { Repository.Save(redirect); } } // Delete child entities. if (page.PageTags != null) { foreach (var pageTag in page.PageTags) { Repository.Delete(pageTag); } } if (page.PageContents != null) { foreach (var pageContent in page.PageContents) { Repository.Delete(pageContent); } } if (page.Options != null) { foreach (var option in page.Options) { Repository.Delete(option); } } if (page.AccessRules != null) { var rules = page.AccessRules.ToList(); rules.ForEach(page.RemoveRule); } // Delete sitemapNodes. if (sitemapNodes != null) { foreach (var node in sitemapNodes) { sitemapService.DeleteNodeWithoutPageUpdate(node); } page.NodeCountInSitemap -= sitemapNodes.Count; Repository.Save(page); } // Delete page Repository.Delete <Root.Models.Page>(request.PageId, request.Version); // Commit UnitOfWork.Commit(); if (sitemapNodes != null && sitemapNodes.Count > 0) { foreach (var node in sitemapNodes) { Events.SitemapEvents.Instance.OnSitemapNodeUpdated(node); } Events.SitemapEvents.Instance.OnSitemapUpdated(); } // Notifying, that page is deleted. Events.PageEvents.Instance.OnPageDeleted(page); return(true); }