/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>Execution result.</returns> public bool Execute(SitemapViewModel request) { var sitemap = Repository .AsQueryable <Models.Sitemap>() .Where(map => map.Id == request.Id) .FetchMany(map => map.AccessRules) .Distinct() .ToList() .First(); var roles = new[] { RootModuleConstants.UserRoles.EditContent }; if (CmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(sitemap, Context.Principal, AccessLevel.ReadWrite, roles); } UnitOfWork.BeginTransaction(); if (sitemap.AccessRules != null) { var rules = sitemap.AccessRules.ToList(); rules.ForEach(sitemap.RemoveRule); } sitemap = Repository.Delete <Models.Sitemap>(request.Id, request.Version); UnitOfWork.Commit(); Events.SitemapEvents.Instance.OnSitemapDeleted(sitemap); return(true); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns></returns> public ClonePageWithLanguageViewModel Execute(GetPageForCloningWithLanguageCommandRequest request) { var pageFutureQuery = Repository .AsQueryable <PageProperties>() .Where(p => p.Id == request.PageId && !p.IsDeleted) .Select(p => new { Model = new ClonePageWithLanguageViewModel { PageId = p.Id, IsMasterPage = p.IsMasterPage }, LanguageGroupIdentifier = p.LanguageGroupIdentifier, LanguageId = p.Language != null ? p.Language.Id : (System.Guid?)null }) .ToFuture(); var languagesFuture = languageService.GetLanguagesLookupValues(); var result = pageFutureQuery.FirstOne(); var model = result.Model; model.Languages = languagesFuture.ToList(); model.ShowWarningAboutNoCultures = !model.Languages.Any(); if (model.IsMasterPage) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.Administration); } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } IList <UserAccessViewModel> accessRules; if (cmsConfiguration.Security.AccessControlEnabled) { accessRules = Repository .AsQueryable <Root.Models.Page>() .Where(x => x.Id == request.PageId && !x.IsDeleted) .SelectMany(x => x.AccessRules) .OrderBy(x => x.Identity) .ToFuture() .ToList() .Select(x => new UserAccessViewModel(x)) .ToList(); } else { accessRules = null; } model.AccessControlEnabled = cmsConfiguration.Security.AccessControlEnabled; model.UserAccessList = accessRules; AddRemoveLanguages(model.Languages, result.LanguageGroupIdentifier, result.LanguageId); return(model); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns><c>true</c> if succeeded, otherwise <c>false</c></returns> /// <exception cref="System.ComponentModel.DataAnnotations.ValidationException">If page status is not correct.</exception> public bool Execute(SavePagePublishStatusRequest request) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.PublishContent); // This would rise security exception if user has no access. var page = UnitOfWork.Session .QueryOver <PageProperties>().Where(p => p.Id == request.PageId && !p.IsDeleted) .SingleOrDefault <PageProperties>(); if (page != null) { if (page.IsMasterPage) { return(false); } var initialStatus = page.Status; if (page.Status == PageStatus.Draft || page.Status == PageStatus.Preview) { var message = string.Format(PagesGlobalization.SavePageStatus_PageIsInInappropriateStatus_Message); var logMessage = string.Format("Draft/Preview page id={0} can not be published.", page.Id); throw new ValidationException(() => message, logMessage); } if (request.IsPublished) { page.Status = PageStatus.Published; page.PublishedOn = DateTime.Now; } else { page.Status = PageStatus.Unpublished; } // NOTE: When transaction is enabled exception is raised from DefaultEntityTrackingService.DemandReadWriteRule() saying that DB timeouted... // UnitOfWork.BeginTransaction(); Repository.Save(page); if (request.IsPublished) { contentService.PublishDraftContent(page.Id); } UnitOfWork.Commit(); if (page.Status != initialStatus) { Events.PageEvents.Instance.OnPagePublishStatusChanged(page); } } return(true); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns> /// <c>true</c>, if successfully restored. /// </returns> public bool Execute(RestorePageContentViewModel request) { var content = Repository .AsQueryable <Root.Models.Content>(p => p.Id == request.PageContentId) .Fetch(f => f.Original) .First(); var contentType = content.GetType(); if (contentType == typeof(HtmlContentWidget) || contentType == typeof(ServerControlWidget)) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.Administration); } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.PublishContent); if (content.Original != null) { var pageContent = Repository.AsQueryable <Root.Models.PageContent>() .Where(x => x.Content.Id == content.Original.Id && !x.IsDeleted) .Fetch(x => x.Page) .ThenFetchMany(x => x.AccessRules) .ToList() .FirstOrDefault(); if (pageContent != null) { AccessControlService.DemandAccess(pageContent.Page, Context.Principal, AccessLevel.ReadWrite); // Check if user has confirmed the deletion of regions in content. if (!request.IsUserConfirmed && pageContent.Page.IsMasterPage) { var hasAnyChildren = contentService.CheckIfContentHasDeletingChildren(pageContent.Page.Id, content.Original.Id, ((HtmlContent)content).Html); if (hasAnyChildren) { var message = PagesGlobalization.RestoreContent_ContentHasChildrenContents_RegionDeleteConfirmationMessage; var logMessage = string.Format("User is trying to restore content with regions which has children contents. Confirmation is required. PageContentId: {0}, ContentId: {1}, PageId: {2}", pageContent.Id, content.Id, pageContent.Page.Id); throw new ConfirmationRequestException(() => message, logMessage); } } } } } var restoredContent = contentService.RestoreContentFromArchive(content); UnitOfWork.Commit(); Events.RootEvents.Instance.OnContentRestored(restoredContent); return(true); }
/// <summary> /// Executes this command. /// </summary> /// <param name="fileId">The file id.</param> /// <returns>The view model.</returns> public virtual FileViewModel Execute(Guid fileId) { var fileQuery = Repository.AsQueryable <MediaFile>().Where(f => f.Id == fileId && !f.IsDeleted); if (configuration.Security.AccessControlEnabled) { fileQuery = fileQuery.FetchMany(f => f.AccessRules); } var file = fileQuery.ToList().FirstOne(); var model = new FileViewModel { Id = file.Id.ToString(), Title = file.Title, Description = file.Description, Url = fileUrlResolver.EnsureFullPathUrl(file.PublicUrl), Version = file.Version.ToString(CultureInfo.InvariantCulture), FileName = file.OriginalFileName, FileExtension = file.OriginalFileExtension, FileSize = file.SizeAsText(), Tags = tagService.GetMediaTagNames(fileId), Image = file.Image == null || file.Image.IsDeleted ? null : new ImageSelectorViewModel { ImageId = file.Image.Id, ImageVersion = file.Image.Version, ImageUrl = fileUrlResolver.EnsureFullPathUrl(file.Image.PublicUrl), ThumbnailUrl = fileUrlResolver.EnsureFullPathUrl(file.Image.PublicThumbnailUrl), ImageTooltip = file.Image.Caption, FolderId = file.Image.Folder != null ? file.Image.Folder.Id : (Guid?)null }, AccessControlEnabled = configuration.Security.AccessControlEnabled }; model.Categories = categoryService.GetSelectedCategories <Media, MediaCategory>(fileId); if (configuration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(file, Context.Principal, AccessLevel.Read); model.UserAccessList = file.AccessRules.Select(f => new UserAccessViewModel(f)).ToList(); model.Url = fileService.GetDownloadFileUrl(MediaType.File, model.Id.ToGuidOrDefault(), model.Url); SetIsReadOnly(model, ((IAccessSecuredObject)file).AccessRules); } model.CategoriesFilterKey = file.GetCategorizableItemKey(); model.CategoriesLookupList = categoryService.GetCategoriesLookupList(model.CategoriesFilterKey); return(model); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>The view model with list of history view models.</returns> public SitemapHistoryViewModel Execute(GetSitemapHistoryRequest request) { var currentVersionQuery = Repository.AsQueryable <Models.Sitemap>() .Where(map => map.Id == request.SitemapId); if (cmsConfiguration.Security.AccessControlEnabled) { currentVersionQuery = currentVersionQuery.FetchMany(f => f.AccessRules); } var currentVersion = currentVersionQuery.Distinct().ToList().First(); if (cmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(currentVersion, Context.Principal, AccessLevel.Read); } var history = new List <SitemapHistoryItem> { new SitemapHistoryItem { Id = currentVersion.Id, Version = currentVersion.Version, SitemapTitle = currentVersion.Title, StatusName = NavigationGlobalization.SitemapStatus_Active, ArchivedOn = null, ArchivedByUser = null, CanCurrentUserRestoreIt = false } }; var historyEntities = sitemapService.GetSitemapHistory(request.SitemapId); history.AddRange( historyEntities.Select( archive => new SitemapHistoryItem { Id = archive.Id, Version = archive.Version, SitemapTitle = archive.Title, StatusName = NavigationGlobalization.SitemapStatus_Archived, ArchivedOn = archive.CreatedOn, ArchivedByUser = archive.CreatedByUser, CanCurrentUserRestoreIt = true }).ToList()); history = AddSortAndPaging(history, request); return(new SitemapHistoryViewModel(history, request, history.Count, request.SitemapId)); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>Execution result.</returns> public SitemapNodeViewModel Execute(SitemapNodeViewModel request) { var sitemap = Repository.AsQueryable <Models.Sitemap>() .Where(map => map.Id == request.SitemapId) .FetchMany(f => f.AccessRules) .FetchMany(map => map.Nodes) .ThenFetch(mapNode => mapNode.Page) .FetchMany(map => map.Nodes) .ThenFetch(mapNode => mapNode.Translations) .Distinct() .ToList() .First(); if (CmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(sitemap, Context.Principal, AccessLevel.ReadWrite); } UnitOfWork.BeginTransaction(); if (!request.SitemapId.HasDefaultValue()) { SitemapService.ArchiveSitemap(sitemap); } bool updatedInDB; var node = SitemapService.SaveNode(out updatedInDB, sitemap, request.Id, request.Version, request.Url, request.Title, request.Macro, request.PageId, request.UsePageTitleAsNodeTitle, request.DisplayOrder, request.ParentId); UnitOfWork.Commit(); if (updatedInDB) { if (request.Id.HasDefaultValue()) { Events.SitemapEvents.Instance.OnSitemapNodeCreated(node); } else { Events.SitemapEvents.Instance.OnSitemapNodeUpdated(node); } Events.SitemapEvents.Instance.OnSitemapUpdated(node.Sitemap); } return(new SitemapNodeViewModel { Id = node.Id, Version = node.Version }); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns> /// <c>true</c>, if successfully restored. /// </returns> public SiteSettingSitemapViewModel Execute(SitemapRestoreViewModel request) { var archive = Repository.AsQueryable <SitemapArchive>() .Where(sitemapArchive => sitemapArchive.Id == request.SitemapVersionId) .Fetch(sitemapArchive => sitemapArchive.Sitemap) .ThenFetchMany(f => f.AccessRules) .Fetch(sitemapArchive => sitemapArchive.Sitemap) .ThenFetchMany(map => map.Nodes) .ThenFetch(node => node.Page) .Fetch(sitemapArchive => sitemapArchive.Sitemap) .ThenFetchMany(map => map.Nodes) .ThenFetchMany(node => node.Translations) .Distinct() .ToList() .First(); if (CmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(archive.Sitemap, Context.Principal, AccessLevel.ReadWrite); } // TODO: do we need a such confirmation? // // Check if user has confirmed restoration if exist nodes linked to deleted pages. // if (!request.IsUserConfirmed) // { // var hasDeletedPages = SitemapService.CheckIfArchiveHasDeletedPages(archive); // if (hasDeletedPages) // { // var message = NavigationGlobalization.RestoreSitemap_ArchiveHasDeletedPages_RestoreConfirmationMessage; // var logMessage = string.Format("User is trying to restore sitemap which has deleted pages. Confirmation is required. archiveId: {0}, sitemapId: {1}", archive.Id, archive.Sitemap.Id); // throw new ConfirmationRequestException(() => message, logMessage); // } // } UnitOfWork.BeginTransaction(); SitemapService.ArchiveSitemap(archive.Sitemap); var restoredSitemap = SitemapService.RestoreSitemapFromArchive(archive); UnitOfWork.Commit(); Events.SitemapEvents.Instance.OnSitemapRestored(restoredSitemap); return(new SiteSettingSitemapViewModel { Id = restoredSitemap.Id, Title = restoredSitemap.Title, Version = restoredSitemap.Version }); }
public MultiFileUploadViewModel Execute(GetMultiFileUploadRequest request) { var model = new MultiFileUploadViewModel(); model.RootFolderId = request.FolderId; model.RootFolderType = request.Type; model.ReuploadMediaId = request.ReuploadMediaId; model.SelectedFolderId = Guid.Empty; model.UploadedFiles = null; var foldersQuery = Repository.AsQueryable <MediaFolder>().Where(f => f.Type == request.Type); if (request.FolderId == Guid.Empty) { foldersQuery = foldersQuery.Where(f => f.Folder == null); } else { foldersQuery = foldersQuery.Where(f => f.Folder.Id == request.FolderId); } model.Folders = foldersQuery .OrderBy(f => f.Title) .Select(f => new Tuple <Guid, string>(f.Id, f.Title)) .ToList(); model.Folders.Insert(0, new Tuple <Guid, string>(Guid.Empty, "..")); if (request.Type != MediaType.Image && cmsConfiguration.Security.AccessControlEnabled) { if (!request.ReuploadMediaId.HasDefaultValue()) { var media = Repository.AsQueryable <Media>(m => m.Id == request.ReuploadMediaId).FirstOne(); var file = media as MediaFile; if (file != null) { AccessControlService.DemandAccess(file, Context.Principal, AccessLevel.ReadWrite); } } else { var principal = SecurityService.GetCurrentPrincipal(); model.UserAccessList = AccessControlService.GetDefaultAccessList(principal).Cast <UserAccessViewModel>().ToList(); model.AccessControlEnabled = cmsConfiguration.Security.AccessControlEnabled; } } return(model); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException"></exception> public ClonePageViewModel Execute(Guid request) { var pageQuery = Repository .AsQueryable <PageProperties>() .Where(p => p.Id == request && !p.IsDeleted) .Select(p => new ClonePageViewModel { PageId = p.Id, IsMasterPage = p.IsMasterPage }) .ToFuture(); ClonePageViewModel model; IList <UserAccessViewModel> accessRules; if (cmsConfiguration.Security.AccessControlEnabled) { accessRules = Repository .AsQueryable <Root.Models.Page>() .Where(x => x.Id == request && !x.IsDeleted) .SelectMany(x => x.AccessRules) .OrderBy(x => x.Identity) .ToFuture() .ToList() .Select(x => new UserAccessViewModel(x)) .ToList(); } else { accessRules = null; } model = pageQuery.FirstOne(); model.AccessControlEnabled = cmsConfiguration.Security.AccessControlEnabled; model.UserAccessList = accessRules; if (model.IsMasterPage) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.Administration); } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } return(model); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>Media preview.</returns> public MediaPreviewViewModel Execute(Guid request) { var response = new MediaPreviewViewModel(); var media = Repository .AsQueryable <Media>(m => m.Id == request) .Fetch(m => m.Original) .FirstOne(); var image = media as MediaImage; if (image != null) { response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_Caption, image.Caption); response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_ImageDimensions, string.Format("{0} x {1}", image.Width, image.Height)); response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_PublicThumbnailUrl, fileUrlResolver.EnsureFullPathUrl(image.PublicThumbnailUrl), true); response.AddProperty(image.Caption, fileUrlResolver.EnsureFullPathUrl(image.PublicUrl), isImageUrl: true); } var file = media as MediaFile; if (file != null) { if (cmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(file.Original as MediaFile ?? file, Context.Principal, AccessLevel.Read); } var publicUrl = fileService.GetDownloadFileUrl(MediaType.File, file.Id, fileUrlResolver.EnsureFullPathUrl(file.PublicUrl)); response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_Title, file.Title); response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_Description, file.Description); response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_FileSize, file.SizeAsText()); response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_PublicUrl, publicUrl, true); if (media.Image != null) { response.AddProperty(media.Image.Caption, fileUrlResolver.EnsureFullPathUrl(media.Image.PublicUrl), isImageUrl: true); } } response.Properties = response.Properties.OrderByDescending(o => o.Title).ToList(); return(response); }
/// <summary> /// Executes the specified id. /// </summary> /// <param name="id">The id.</param> /// <returns> /// Response type of <see cref="DownloadFileCommandResponse" /> /// </returns> /// <exception cref="System.Web.HttpException">403;Access Forbidden</exception> public DownloadFileCommandResponse Execute(Guid id) { // Load file var fileQuery = Repository.AsQueryable <MediaFile>(f => f.Id == id && !f.IsDeleted); if (cmsConfiguration.Security.AccessControlEnabled) { fileQuery = fileQuery.FetchMany(f => f.AccessRules); } var file = fileQuery.ToList().FirstOne(); // Access control is ALWAYS disabled for images var accesControlEnabled = cmsConfiguration.Security.AccessControlEnabled && file.Type != MediaType.Image; if (!accesControlEnabled || !storageService.SecuredUrlsEnabled) { return(new DownloadFileCommandResponse { RedirectUrl = fileUrlResolver.EnsureFullPathUrl(file.PublicUrl) }); } // Get download URL with security token try { AccessControlService.DemandAccess(file, Context.Principal, AccessLevel.Read); } catch (SecurityException) { return(new DownloadFileCommandResponse { HasNoAccess = true }); } var url = storageService.GetSecuredUrl(file.FileUri); return(new DownloadFileCommandResponse { RedirectUrl = url }); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="pageContentId">The id of the archived page content version.</param> /// <returns>True, if restore is successfull</returns> public bool Execute(Guid pageContentId) { var content = Repository .AsQueryable <Root.Models.Content>(p => p.Id == pageContentId) .Fetch(f => f.Original) .First(); var contentType = content.GetType(); if (contentType == typeof(HtmlContentWidget) || contentType == typeof(ServerControlWidget)) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.Administration); } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.PublishContent); if (content.Original != null) { var pageContent = Repository.AsQueryable <Root.Models.PageContent>() .Where(x => x.Content.Id == content.Original.Id && !x.IsDeleted) .Fetch(x => x.Page) .ThenFetchMany(x => x.AccessRules) .ToList() .FirstOrDefault(); if (pageContent != null) { AccessControlService.DemandAccess(pageContent.Page, Context.Principal, AccessLevel.ReadWrite); } } } contentService.RestoreContentFromArchive(content); UnitOfWork.Commit(); return(true); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> public SitemapViewModel Execute(SitemapViewModel request) { createdNodes.Clear(); updatedNodes.Clear(); deletedNodes.Clear(); var createNew = request.Id.HasDefaultValue(); Models.Sitemap sitemap; if (!createNew) { var sitemapQuery = Repository.AsQueryable <Models.Sitemap>().Where(s => s.Id == request.Id); if (CmsConfiguration.Security.AccessControlEnabled) { sitemapQuery = sitemapQuery.FetchMany(f => f.AccessRules); } sitemap = sitemapQuery.ToList().First(); if (CmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(sitemap, Context.Principal, AccessLevel.ReadWrite); } } else { sitemap = new Models.Sitemap() { AccessRules = new List <AccessRule>() }; } var nodeList = !createNew?Repository.AsQueryable <SitemapNode>() .Where(node => node.Sitemap.Id == sitemap.Id) .ToFuture() : new List <SitemapNode>(); var translationList = !createNew ? Repository.AsQueryable <SitemapNodeTranslation>() .Where(t => t.Node.Sitemap.Id == sitemap.Id) .Fetch(t => t.Node) .ToFuture() : new List <SitemapNodeTranslation>(); UnitOfWork.BeginTransaction(); if (!createNew) { SitemapService.ArchiveSitemap(request.Id); } if (CmsConfiguration.Security.AccessControlEnabled) { sitemap.AccessRules.RemoveDuplicateEntities(); var accessRules = request.UserAccessList != null?request.UserAccessList.Cast <IAccessRule>().ToList() : null; AccessControlService.UpdateAccessControl(sitemap, accessRules); } sitemap.Title = request.Title; sitemap.Version = request.Version; Repository.Save(sitemap); SaveNodeList(sitemap, request.RootNodes, null, nodeList.ToList(), translationList.ToList()); IList <Tag> newTags; TagService.SaveTags(sitemap, request.Tags, out newTags); UnitOfWork.Commit(); foreach (var node in createdNodes) { Events.SitemapEvents.Instance.OnSitemapNodeCreated(node); } foreach (var node in updatedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeUpdated(node); } foreach (var node in deletedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeDeleted(node); } if (createNew) { Events.SitemapEvents.Instance.OnSitemapCreated(sitemap); } else { Events.SitemapEvents.Instance.OnSitemapUpdated(sitemap); } Events.RootEvents.Instance.OnTagCreated(newTags); return(GetModelMainData(sitemap)); }
/// <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); }
/// <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)); }
public SavePageHtmlContentResponse Execute(PageContentViewModel request) { if (request.DesirableStatus == ContentStatus.Published) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.PublishContent); } if (request.Id == default(Guid) || request.DesirableStatus != ContentStatus.Published) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } PageContent pageContent; var isNew = request.Id.HasDefaultValue(); if (!isNew) { var query = Repository .AsQueryable <PageContent>() .Where(f => f.Id == request.Id && !f.IsDeleted) .AsQueryable(); if (!request.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 (!request.IsUserConfirmed && pageContent.Page.IsMasterPage) { var hasAnyChildren = contentService.CheckIfContentHasDeletingChildren(request.PageId, request.ContentId, request.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}", request.Id, request.ContentId, request.PageId); throw new ConfirmationRequestException(() => message, logMessage); } } } else { pageContent = new PageContent(); pageContent.Order = contentService.GetPageContentNextOrderNumber(request.PageId); if (configuration.Security.AccessControlEnabled) { pageContent.Page = Repository .AsQueryable <Root.Models.Page>(p => p.Id == request.PageId) .FetchMany(p => p.AccessRules) .ToList() .FirstOne(); } } // Deman 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>(request.PageId); } pageContent.Region = Repository.AsProxy <Region>(request.RegionId); var contentToSave = new HtmlContent { Id = request.ContentId, ActivationDate = request.LiveFrom, ExpirationDate = TimeHelper.FormatEndDate(request.LiveTo), Name = request.ContentName, Html = request.PageContent ?? string.Empty, UseCustomCss = request.EnabledCustomCss, CustomCss = request.CustomCss, UseCustomJs = request.EanbledCustomJs, CustomJs = request.CustomJs, EditInSourceMode = request.EditInSourceMode }; // Preserve content if user is not authorized to change it. if (!SecurityService.IsAuthorized(RootModuleConstants.UserRoles.EditContent) && request.Id != default(Guid)) { var originalContent = Repository.First <HtmlContent>(request.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, request.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 (request.DesirableStatus != ContentStatus.Preview) { if (isNew) { Events.PageEvents.Instance.OnPageContentInserted(pageContent); Events.PageEvents.Instance.OnHtmlContentCreated((HtmlContent)pageContent.Content); } 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>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 }); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="id">The page id.</param> /// <returns></returns> public EditPagePropertiesViewModel Execute(Guid id) { var modelQuery = Repository .AsQueryable <PageProperties>() .Where(p => p.Id == id) .Select(page => new { Model = new EditPagePropertiesViewModel { Id = page.Id, Version = page.Version, PageName = page.Title, PageUrl = page.PageUrl, ForceAccessProtocol = page.ForceAccessProtocol, PageCSS = page.CustomCss, PageJavascript = page.CustomJS, UseNoFollow = page.UseNoFollow, UseNoIndex = page.UseNoIndex, UseCanonicalUrl = page.UseCanonicalUrl, IsPagePublished = page.Status == PageStatus.Published, IsArchived = page.IsArchived, IsMasterPage = page.IsMasterPage, TemplateId = page.Layout.Id, MasterPageId = page.MasterPage.Id, CategoryId = page.Category.Id, LanguageId = page.Language.Id, AccessControlEnabled = cmsConfiguration.Security.AccessControlEnabled, IsInSitemap = page.PagesView.IsInSitemap, Image = page.Image == null || page.Image.IsDeleted ? null : new ImageSelectorViewModel { ImageId = page.Image.Id, ImageVersion = page.Image.Version, ImageUrl = fileUrlResolver.EnsureFullPathUrl(page.Image.PublicUrl), ThumbnailUrl = fileUrlResolver.EnsureFullPathUrl(page.Image.PublicThumbnailUrl), ImageTooltip = page.Image.Caption, FolderId = page.Image.Folder != null ? page.Image.Folder.Id : (Guid?)null }, SecondaryImage = page.SecondaryImage == null || page.SecondaryImage.IsDeleted ? null : new ImageSelectorViewModel { ImageId = page.SecondaryImage.Id, ImageVersion = page.SecondaryImage.Version, ImageUrl = fileUrlResolver.EnsureFullPathUrl(page.SecondaryImage.PublicUrl), ThumbnailUrl = fileUrlResolver.EnsureFullPathUrl(page.SecondaryImage.PublicThumbnailUrl), ImageTooltip = page.SecondaryImage.Caption, FolderId = page.SecondaryImage.Folder != null ? page.SecondaryImage.Folder.Id : (Guid?)null }, FeaturedImage = page.FeaturedImage == null || page.FeaturedImage.IsDeleted ? null : new ImageSelectorViewModel { ImageId = page.FeaturedImage.Id, ImageVersion = page.FeaturedImage.Version, ImageUrl = fileUrlResolver.EnsureFullPathUrl(page.FeaturedImage.PublicUrl), ThumbnailUrl = fileUrlResolver.EnsureFullPathUrl(page.FeaturedImage.PublicThumbnailUrl), ImageTooltip = page.FeaturedImage.Caption, FolderId = page.FeaturedImage.Folder != null ? page.FeaturedImage.Folder.Id : (Guid?)null } }, LanguageGroupIdentifier = page.LanguageGroupIdentifier }) .ToFuture(); var tagsFuture = tagService.GetPageTagNames(id); var categories = categoryService.GetCategories(); var languagesFuture = (cmsConfiguration.EnableMultilanguage) ? languageService.GetLanguages() : null; IEnumerable <AccessRule> userAccessFuture; if (cmsConfiguration.Security.AccessControlEnabled) { userAccessFuture = Repository .AsQueryable <Root.Models.Page>() .Where(x => x.Id == id && !x.IsDeleted) .SelectMany(x => x.AccessRules) .OrderBy(x => x.IsForRole) .ThenBy(x => x.Identity) .ToFuture(); } else { userAccessFuture = null; } var model = modelQuery.ToList().FirstOrDefault(); if (model != null && model.Model != null) { if (model.Model.IsMasterPage) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.Administration); } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.MultipleRoles(RootModuleConstants.UserRoles.EditContent, RootModuleConstants.UserRoles.PublishContent)); } model.Model.Tags = tagsFuture.ToList(); model.Model.RedirectFromOldUrl = true; model.Model.Categories = categories; model.Model.PageAccessProtocols = this.GetProtocolForcingTypes(); model.Model.UpdateSitemap = true; model.Model.CustomOptions = optionService.GetCustomOptions(); model.Model.ShowTranslationsTab = cmsConfiguration.EnableMultilanguage && !model.Model.IsMasterPage; if (model.Model.ShowTranslationsTab) { model.Model.Languages = languagesFuture.ToList(); if (!model.Model.Languages.Any()) { model.Model.TranslationMessages = new UserMessages(); model.Model.TranslationMessages.AddInfo(PagesGlobalization.EditPageProperties_TranslationsTab_NoLanguagesCreated_Message); } if (model.LanguageGroupIdentifier.HasValue) { model.Model.Translations = pageService.GetPageTranslations(model.LanguageGroupIdentifier.Value).ToList(); } } // Get layout options, page options and merge them model.Model.OptionValues = optionService.GetMergedMasterPagesOptionValues(model.Model.Id, model.Model.MasterPageId, model.Model.TemplateId); if (userAccessFuture != null) { model.Model.UserAccessList = userAccessFuture.Select(x => new UserAccessViewModel(x)).ToList(); var rules = model.Model.UserAccessList.Cast <IAccessRule>().ToList(); SetIsReadOnly(model.Model, rules); } model.Model.CanPublishPage = SecurityService.IsAuthorized(Context.Principal, RootModuleConstants.UserRoles.PublishContent); // Get templates model.Model.Templates = layoutService.GetAvailableLayouts(id, model.Model.MasterPageId).ToList(); model.Model.Templates .Where(x => x.TemplateId == model.Model.TemplateId || x.TemplateId == model.Model.MasterPageId) .Take(1).ToList() .ForEach(x => x.IsActive = true); } return(model != null ? model.Model : null); }
/// <summary> /// Executes this command. /// </summary> public ConfirmUploadResponse Execute(MultiFileUploadViewModel request) { ConfirmUploadResponse response = new ConfirmUploadResponse { SelectedFolderId = request.SelectedFolderId ?? Guid.Empty, ReuploadMediaId = request.ReuploadMediaId }; if (request.UploadedFiles != null && request.UploadedFiles.Count > 0) { MediaFolder folder = null; if (request.SelectedFolderId != null && request.SelectedFolderId.Value != Guid.Empty) { folder = Repository.AsProxy <MediaFolder>(request.SelectedFolderId.Value); if (folder.IsDeleted) { response.FolderIsDeleted = true; return(response); } } UnitOfWork.BeginTransaction(); List <MediaFile> files = new List <MediaFile>(); var updateAccessControl = true; if (request.ReuploadMediaId.HasDefaultValue()) { UpdateMedia(request, folder, files); } else { // Re-upload performed. var fileId = request.UploadedFiles.FirstOrDefault(); var file = Repository.FirstOrDefault <MediaFile>(fileId); if (!fileId.HasDefaultValue()) { var originalMedia = Repository.First <MediaFile>(request.ReuploadMediaId); if (cmsConfiguration.Security.AccessControlEnabled && !(originalMedia is IAccessControlDisabled)) { AccessControlService.DemandAccess(originalMedia, Context.Principal, AccessLevel.ReadWrite); } file.Original = originalMedia; // Do not update access control, if re-uploading updateAccessControl = false; file.Title = originalMedia.Title; file.Description = originalMedia.Description; file.IsArchived = originalMedia.IsArchived; file.Folder = originalMedia.Folder; file.Image = originalMedia.Image; if (file is MediaImage && originalMedia is MediaImage) { ((MediaImage)file).Caption = ((MediaImage)originalMedia).Caption; ((MediaImage)file).ImageAlign = ((MediaImage)originalMedia).ImageAlign; } file.IsTemporary = false; file.PublishedOn = DateTime.Now; var temp = (MediaFile)file.Clone(); originalMedia.CopyDataTo(file); temp.CopyDataTo(originalMedia); files.Add(originalMedia); } } if (updateAccessControl && cmsConfiguration.Security.AccessControlEnabled) { foreach (var file in files) { if (!(file is MediaImage)) { var currentFile = file; var fileEntity = Repository.AsQueryable <MediaFile>().Where(f => f.Id == currentFile.Id).FetchMany(f => f.AccessRules).ToList().FirstOne(); accessControlService.UpdateAccessControl( fileEntity, request.UserAccessList != null ? request.UserAccessList.Cast <IAccessRule>().ToList() : new List <IAccessRule>()); } } } UnitOfWork.Commit(); if (request.ReuploadMediaId.HasDefaultValue()) { foreach (var file in files) { if (file is MediaImage) { file.PublicUrl += string.Format("?{0}", DateTime.Now.ToString(MediaManagerModuleDescriptor.HardLoadImageDateTimeFormat)); ((MediaImage)file).PublicThumbnailUrl += string.Format("?{0}", DateTime.Now.ToString(MediaManagerModuleDescriptor.HardLoadImageDateTimeFormat)); } } } response.Medias = files.Select(Convert).ToList(); // Notify. foreach (var mediaFile in files) { Events.MediaManagerEvents.Instance.OnMediaFileUpdated(mediaFile); } } return(response); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns></returns> public SortPageContentCommandResponse Execute(PageContentSortViewModel request) { UnitOfWork.BeginTransaction(); var sortedPageContents = new List <PageContent>(); var regionIds = request.PageContents.Select(r => r.RegionId).Distinct().ToArray(); var parentPageContentIds = request.PageContents.Where(r => r.ParentPageContentId.HasValue).Select(r => r.ParentPageContentId.Value); var pageContentIds = request.PageContents.Select(r => r.PageContentId).Concat(parentPageContentIds).Distinct().ToArray(); var response = new SortPageContentCommandResponse { PageContents = request.PageContents }; // Load all page contents from all regions from request var contentsFuture = Repository .AsQueryable <PageContent>() .Where(f => f.Page.Id == request.PageId && (regionIds.Contains(f.Region.Id) || pageContentIds.Contains(f.Id))) .ToFuture(); // Demand access if (cmsConfiguration.Security.AccessControlEnabled) { var page = Repository .AsQueryable <Root.Models.Page>() .Where(p => p.Id == request.PageId) .FetchMany(p => p.AccessRules) .ToFuture() .ToList() .FirstOne(); AccessControlService.DemandAccess(page, Context.Principal, AccessLevel.ReadWrite, RootModuleConstants.UserRoles.EditContent); } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } var pageContents = contentsFuture.ToList(); request.PageContents .GroupBy(group => new System.Tuple <Guid, Guid?>(group.RegionId, group.ParentPageContentId)) .ForEach(group => { var regionId = group.Key.Item1; var parentPageContentId = group.Key.Item2; var region = Repository.AsProxy <Region>(regionId); var index = 0; foreach (var viewModel in group) { var pageContent = pageContents.FirstOrDefault(f => f.Id == viewModel.PageContentId); PageContent parentPageContent = null; if (parentPageContentId.HasValue && !parentPageContentId.Value.HasDefaultValue()) { parentPageContent = pageContents.Where(f => f.Id == parentPageContentId).FirstOne(); } if (pageContent == null) { throw new EntityNotFoundException(typeof(PageContent), Guid.Empty); } if (pageContent.Order != index || pageContent.Region.Id != regionId || pageContent.Parent == null && parentPageContent != null || pageContent.Parent != null && parentPageContent == null || (pageContent.Parent != null && parentPageContent != null && parentPageContent.Id != pageContent.Parent.Id)) { if (pageContent.Version != viewModel.Version) { throw new ConcurrentDataException(pageContent); } pageContent.Order = index; pageContent.Region = region; pageContent.Parent = parentPageContent; sortedPageContents.Add(pageContent); Repository.Save(pageContent); } index++; } }); UnitOfWork.Commit(); // Notify foreach (var pageContent in sortedPageContents) { // Notify. Events.PageEvents.Instance.OnPageContentSorted(pageContent); } // Update versions foreach (var pageContent in pageContents) { var responseContent = response.PageContents.FirstOrDefault(pc => pc.PageContentId == pageContent.Id); if (responseContent != null) { responseContent.Version = pageContent.Version; } } return(response); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>Media preview.</returns> public MediaPreviewViewModel Execute(Guid request) { var response = new MediaPreviewViewModel(); var media = Repository.AsQueryable <Media>(m => m.Id == request).Fetch(m => m.Original).FirstOne(); var file = media as MediaFile; if (file != null) { var image = media as MediaImage; if (cmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(file.Original as MediaFile ?? file, Context.Principal, AccessLevel.Read); } response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_Title, file.Title); if (image != null) { response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_Caption, image.Caption); } var publicUrl = fileService.GetDownloadFileUrl(MediaType.File, file.Id, fileUrlResolver.EnsureFullPathUrl(file.PublicUrl)); response.AddUrl(MediaGlobalization.MediaHistory_Preview_Properties_PublicUrl, publicUrl); if (image != null) { response.AddUrl( MediaGlobalization.MediaHistory_Preview_Properties_PublicThumbnailUrl, fileUrlResolver.EnsureFullPathUrl( image.PublicThumbnailUrl + string.Format("?{0}", DateTime.Now.ToString(MediaManagerModuleDescriptor.HardLoadImageDateTimeFormat)))); } response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_FileSize, file.SizeAsText()); if (image != null) { var dimensionCalculator = new ImageDimensionsCalculator(image); if (dimensionCalculator.Height != dimensionCalculator.ResizedCroppedHeight || dimensionCalculator.Width != dimensionCalculator.ResizedCroppedWidth) { response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_CroppedImageDimensions, string.Format("{0} x {1}", dimensionCalculator.ResizedCroppedWidth, dimensionCalculator.ResizedCroppedHeight)); } response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_ImageDimensions, string.Format("{0} x {1}", dimensionCalculator.Width, dimensionCalculator.Height)); } if (!string.IsNullOrWhiteSpace(file.Description)) { response.AddProperty(MediaGlobalization.MediaHistory_Preview_Properties_Description, file.Description); } if (media.Image != null) { response.AddImage( media.Image.Caption, fileUrlResolver.EnsureFullPathUrl( media.Image.PublicUrl + string.Format("?{0}", DateTime.Now.ToString(MediaManagerModuleDescriptor.HardLoadImageDateTimeFormat)))); } if (image != null) { response.AddImage( image.Caption, fileUrlResolver.EnsureFullPathUrl( image.PublicUrl + string.Format("?{0}", DateTime.Now.ToString(MediaManagerModuleDescriptor.HardLoadImageDateTimeFormat)))); } } return(response); }
/// <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 the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>AddNewPage view model</returns> public AddNewPageViewModel Execute(AddNewPageCommandRequest request) { if (request.CreateMasterPage) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.Administration); } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } var showLanguages = cmsConfiguration.EnableMultilanguage && !request.CreateMasterPage; var languagesFuture = (showLanguages) ? languageService.GetLanguagesLookupValues() : null; var principal = securityService.GetCurrentPrincipal(); var model = new AddNewPageViewModel { ParentPageUrl = request.ParentPageUrl, Templates = layoutService.GetAvailableLayouts().ToList(), AccessControlEnabled = cmsConfiguration.Security.AccessControlEnabled, CreateMasterPage = request.CreateMasterPage, ShowLanguages = showLanguages }; if (showLanguages) { model.Languages = languagesFuture.ToList(); model.ShowLanguages = model.Languages.Any(); } if (model.Templates.Count > 0) { model.Templates.ToList().ForEach(x => x.IsActive = false); // Select current page as master var urlHash = request.ParentPageUrl.UrlHash(); model.Templates.Where(t => t.IsMasterPage && t.MasterUrlHash == urlHash).ToList().ForEach(x => x.IsActive = true); // Select current page's layout if (model.Templates.Count(t => t.IsActive) != 1) { // Try to get layout of the current page var currentPageLayout = repository .AsQueryable <Root.Models.Page>(p => p.PageUrlHash == request.ParentPageUrl.UrlHash()) .Select(p => new { MasterPageId = p.MasterPage != null ? p.MasterPage.Id : (System.Guid?)null, LayoutId = p.Layout != null ? p.Layout.Id : (System.Guid?)null }) .FirstOrDefault(); if (currentPageLayout != null) { if (currentPageLayout.MasterPageId.HasValue) { model.Templates .Where(t => t.IsMasterPage && t.TemplateId == currentPageLayout.MasterPageId.Value) .Take(1) .ToList().ForEach(x => x.IsActive = true); } else if (currentPageLayout.LayoutId.HasValue) { model.Templates .Where(t => !t.IsMasterPage && t.TemplateId == currentPageLayout.LayoutId.Value) .Take(1) .ToList().ForEach(x => x.IsActive = true); } } } // Select first layout as active if (model.Templates.Count(t => t.IsActive) != 1) { model.Templates.First().IsActive = true; } var active = model.Templates.First(t => t.IsActive); if (active != null) { if (active.IsMasterPage) { model.MasterPageId = active.TemplateId; model.UserAccessList = Repository .AsQueryable <Root.Models.Page>() .Where(x => x.Id == model.MasterPageId && !x.IsDeleted) .SelectMany(x => x.AccessRules) .OrderBy(x => x.Identity) .Select(x => new UserAccessViewModel(x)).ToList(); } else { model.TemplateId = active.TemplateId; model.UserAccessList = AccessControlService.GetDefaultAccessList(principal).Select(f => new UserAccessViewModel(f)).ToList(); } } if (model.TemplateId.HasValue) { model.OptionValues = layoutService.GetLayoutOptionValues(model.TemplateId.Value); } if (model.MasterPageId.HasValue) { model.OptionValues = masterPageService.GetMasterPageOptionValues(model.MasterPageId.Value); } model.CustomOptions = optionService.GetCustomOptions(); } return(model); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> public void Execute(List <SitemapViewModel> requests) { createdNodes.Clear(); updatedNodes.Clear(); deletedNodes.Clear(); var sitemapsToSave = new List <SaveModel>(); foreach (var request in requests) { var createNew = request.Id.HasDefaultValue(); Models.Sitemap sitemap; if (!createNew) { var sitemapQuery = Repository.AsQueryable <Models.Sitemap>() .Where(s => s.Id == request.Id); if (CmsConfiguration.Security.AccessControlEnabled) { sitemapQuery = sitemapQuery.FetchMany(f => f.AccessRules); } sitemapQuery = sitemapQuery.FetchMany(s => s.Nodes); sitemap = sitemapQuery.ToList().First(); // NOTE: bottleneck. TODO: remake with ToFuture to get all the sitemaps at once. if (CmsConfiguration.Security.AccessControlEnabled) { AccessControlService.DemandAccess(sitemap, Context.Principal, AccessLevel.ReadWrite); } } else { sitemap = new Models.Sitemap() { AccessRules = new List <AccessRule>(), Nodes = new List <SitemapNode>() }; } sitemapsToSave.Add(new SaveModel() { Model = request, Entity = sitemap, IsNew = createNew }); } UnitOfWork.BeginTransaction(); var createdTags = new List <Tag>(); foreach (var item in sitemapsToSave) { // Save/update only sitemap nodes. SaveNodeList(item.Entity, item.Model.RootNodes, null, item.Entity.Nodes.ToList()); } UnitOfWork.Commit(); foreach (var node in createdNodes) { Events.SitemapEvents.Instance.OnSitemapNodeCreated(node); } foreach (var node in updatedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeUpdated(node); } foreach (var node in deletedNodes) { Events.SitemapEvents.Instance.OnSitemapNodeDeleted(node); } foreach (var item in sitemapsToSave) { if (item.IsNew) { Events.SitemapEvents.Instance.OnSitemapCreated(item.Entity); } else { Events.SitemapEvents.Instance.OnSitemapUpdated(item.Entity); } } Events.RootEvents.Instance.OnTagCreated(createdTags); }
/// <summary> /// Executes the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns></returns> /// <exception cref="ConcurrentDataException"></exception> /// <exception cref="CmsException"></exception> public DestroyContentDraftCommandResponse Execute(DestroyContentDraftCommandRequest request) { var contentQuery = Repository .AsQueryable <Root.Models.Content>(p => p.Id == request.Id) .Fetch(f => f.Original).AsQueryable(); if (cmsConfiguration.Security.AccessControlEnabled) { contentQuery = contentQuery.FetchMany(f => f.PageContents).ThenFetch(f => f.Page).ThenFetchMany(f => f.AccessRules).AsQueryable(); } var content = contentQuery.ToList().FirstOrDefault(); // Throw concurrent data exception (user needs to reload page): // - content may be null, if looking for already deleted draft // - content may be changed, if looking for if (content == null || request.Version != content.Version) { throw new ConcurrentDataException(content ?? new Root.Models.Content()); } var pageContents = content.PageContents; // If content is published, try to get it's active draft if (content.Status == ContentStatus.Published) { content = Repository .AsQueryable <Root.Models.Content>(p => p.Original == content) .Where(c => c.Status == ContentStatus.Draft && !c.IsDeleted) .Fetch(f => f.Original) .FirstOrDefault(); if (content == null) { // Throw concurrent data exception (user needs to reload page): // - content may be null, if looking for already deleted draft throw new ConcurrentDataException(new Root.Models.Content()); } } if (content.Status != ContentStatus.Draft) { throw new CmsException(string.Format("Only draft version can be destroyed. Id: {0}, Status: {1}", content.Id, content.Status)); } if (content.Original == null) { throw new CmsException(string.Format("Draft version cannot be destroyed - it has no published original version. Id: {0}, Status: {1}", content.Id, content.Status)); } var contentType = content.GetType(); if (contentType == typeof(HtmlContentWidget) || contentType == typeof(ServerControlWidget)) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.Administration); } else { bool checkedAccess = false; if (content is HtmlContent) { var pageContent = pageContents.FirstOrDefault(); if (pageContent != null && pageContent.Page != null) { checkedAccess = true; AccessControlService.DemandAccess(pageContent.Page, Context.Principal, AccessLevel.ReadWrite, RootModuleConstants.UserRoles.EditContent); } } if (!checkedAccess) { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } } Repository.Delete(content); UnitOfWork.Commit(); var response = new DestroyContentDraftCommandResponse { PublishedId = content.Original.Id, Id = content.Original.Id, OriginalId = content.Original.Id, Version = content.Original.Version, OriginalVersion = content.Original.Version, WidgetName = content.Original.Name, IsPublished = true, HasDraft = false, DesirableStatus = ContentStatus.Published }; // Try to cast to widget var widget = content.Original as HtmlContentWidget; if (widget != null && widget.Category != null && !widget.Category.IsDeleted) { response.CategoryName = widget.Category.Name; } return(response); }
public ChangedContentResultViewModel 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) { contentService.CheckIfContentHasDeletingChildrenWithException(model.PageId, model.ContentId, model.PageContent); } } else { pageContent = new PageContent(); pageContent.Order = contentService.GetPageContentNextOrderNumber(model.PageId, model.ParentPageContentId); 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); if (!model.ParentPageContentId.HasDefaultValue()) { pageContent.Parent = Repository.AsProxy <PageContent>(model.ParentPageContentId); } else { pageContent.Parent = null; } 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); } } var contentData = (pageContent.Content.History != null ? pageContent.Content.History.FirstOrDefault(c => c.Status == ContentStatus.Draft) ?? pageContent.Content : pageContent.Content); var response = new ChangedContentResultViewModel { PageContentId = pageContent.Id, ContentId = contentData.Id, RegionId = pageContent.Region.Id, PageId = pageContent.Page.Id, DesirableStatus = request.Content.DesirableStatus, Title = contentData.Name, ContentVersion = contentData.Version, PageContentVersion = pageContent.Version, ContentType = HtmlContentAccessor.ContentWrapperType }; if (request.Content.IncludeChildRegions) { response.Regions = widgetService.GetWidgetChildRegionViewModels(contentData); } return(response); }
/// <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> /// 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 SortPageContentResponse Execute(PageContentSortViewModel request) { var response = new SortPageContentResponse(); UnitOfWork.BeginTransaction(); #region Updated page content Order if needed. var pageQuery = Repository.AsQueryable <PageContent>().Where(f => f.Page.Id == request.PageId && f.Region.Id == request.RegionId); if (cmsConfiguration.Security.AccessControlEnabled) { pageQuery = pageQuery.Fetch(f => f.Page).ThenFetchMany(f => f.AccessRules); } var pageContents = pageQuery.ToList(); // Demand access if (cmsConfiguration.Security.AccessControlEnabled) { if (pageContents.Count > 0) { var page = pageContents[0].Page; AccessControlService.DemandAccess(page, Context.Principal, AccessLevel.ReadWrite, RootModuleConstants.UserRoles.EditContent); } } else { AccessControlService.DemandAccess(Context.Principal, RootModuleConstants.UserRoles.EditContent); } var index = 0; foreach (var content in request.PageContents) { var pageContent = pageContents.FirstOrDefault(f => f.Id == content.Id); if (pageContent == null) { throw new EntityNotFoundException(typeof(PageContent), Guid.Empty); } if (pageContent.Order != index) { if (pageContent.Version != content.Version) { throw new ConcurrentDataException(pageContent); } pageContent.Order = index; Repository.Save(pageContent); response.UpdatedPageContents.Add(new ContentViewModel { Id = pageContent.Id }); } index++; } #endregion #region Get page content updated versions. // NOTE: Maybe, it is logical to place this code after UnitOfWork.Commit(), but in this way, NHibernate generates less traffic to DB. pageContents = Repository.AsQueryable <PageContent>().Where(f => f.Page.Id == request.PageId && f.Region.Id == request.RegionId).ToList(); foreach (var updatedPageContent in response.UpdatedPageContents) { var pageContent = pageContents.FirstOrDefault(f => f.Id == updatedPageContent.Id); if (pageContent == null) { throw new CmsException(string.Format("Content was not found by id={0}.", updatedPageContent.Id)); } updatedPageContent.Version = pageContent.Version; } #endregion UnitOfWork.Commit(); return(response); }