/// <summary> /// Saves the given page model /// </summary> /// <param name="model">The page model</param> /// <param name="isDraft">If the model should be saved as a draft</param> private async Task <IEnumerable <Guid> > Save <T>(T model, bool isDraft) where T : PageBase { return(await InTx(async session => { var backThen = new DateTime(2020, 1, 1, 0, 0, 0); var revisionNumber = (DateTime.Now - backThen).TotalMilliseconds; var type = App.PageTypes.GetById(model.TypeId); var affected = new List <Guid>(); var isNew = false; var lastModified = DateTime.MinValue; if (type == null) { return affected; } var page = await session.GetAsync <PageEntity>(model.Id).ConfigureAwait(false); // IQueryable<Page> pageQuery = _db.Pages; // if (isDraft) // { // pageQuery = pageQuery.AsNoTracking(); // } // var page = await pageQuery // .Include(p => p.Permissions) // .Include(p => p.Blocks).ThenInclude(b => b.Block).ThenInclude(b => b.Fields) // .Include(p => p.Fields) // .FirstOrDefaultAsync(p => p.Id == model.Id) // .ConfigureAwait(false); if (page == null) { isNew = true; } else { lastModified = page.LastModified; } if (model.OriginalPageId.HasValue) { var originalPage = await session.Query <PageEntity>().FirstOrDefaultAsync(p => p.Id == model.OriginalPageId).ConfigureAwait(false); //var originalPage = (await _db.Pages.AsNoTracking().FirstOrDefaultAsync(p => p.Id == model.OriginalPageId).ConfigureAwait(false)); var originalPageIsCopy = originalPage?.OriginalPageId.HasValue ?? false; if (originalPageIsCopy) { throw new InvalidOperationException("Can not set copy of a copy"); } var originalPageType = originalPage?.PageType.Id; if (originalPageType != model.TypeId) { throw new InvalidOperationException("Copy can not have a different content type"); } // Transform the model if (page == null) { page = new PageEntity() { //Id = model.Id != Guid.Empty ? model.Id : Guid.NewGuid(), Created = DateTime.Now, }; if (!isDraft) { await session.SaveAsync(page).ConfigureAwait(false); //await _db.Pages.AddAsync(page).ConfigureAwait(false); // Make room for the new page var dest = await session.Query <PageEntity>().Where(p => p.Site.Id == model.SiteId && p.Parent.Id == model.ParentId).ToListAsync().ConfigureAwait(false); //var dest = await _db.Pages.Where(p => p.SiteId == model.SiteId && p.ParentId == model.ParentId).ToListAsync().ConfigureAwait(false); affected.AddRange(MovePages(dest, page.Id, model.SiteId, model.SortOrder, true)); } } else { // Check if the page has been moved if (!isDraft && (page.Parent.Id != model.ParentId || page.SortOrder != model.SortOrder)) { var source = await session.Query <PageEntity>().Where(p => p.Site == page.Site && p.Parent == page.Parent && p.Id != model.Id).ToListAsync().ConfigureAwait(false); //var source = await _db.Pages.Where(p => p.SiteId == page.SiteId && p.ParentId == page.ParentId && p.Id != model.Id).ToListAsync().ConfigureAwait(false); var dest = page.Parent.Id == model.ParentId ? source : await session.Query <PageEntity>().Where(p => p.Site.Id == model.SiteId && p.Parent.Id == model.ParentId).ToListAsync().ConfigureAwait(false); //var dest = page.Parent.Id == model.ParentId ? source : await _db.Pages.Where(p => p.SiteId == model.SiteId && p.ParentId == model.ParentId).ToListAsync().ConfigureAwait(false); // Remove the old position for the page affected.AddRange(MovePages(source, page.Id, page.Site.Id, page.SortOrder + 1, false)); // Add room for the new position of the page affected.AddRange(MovePages(dest, page.Id, model.SiteId, model.SortOrder, true)); } } if (!isDraft && (isNew || page.Title != model.Title || page.NavigationTitle != model.NavigationTitle)) { // If this is new page or title has been updated it means // the global sitemap changes. Notify the service. affected.Add(page.Id); } page.ContentType = type.IsArchive ? "Blog" : "Page"; page.PageType = await session.GetAsync <PageTypeEntity>(model.TypeId).ConfigureAwait(false); //page.PageTypeId = model.TypeId; page.OriginalPageId = model.OriginalPageId; page.Site = await session.GetAsync <SiteEntity>(model.SiteId).ConfigureAwait(false); //page.SiteId = model.SiteId; page.Title = model.Title; page.NavigationTitle = model.NavigationTitle; page.Slug = model.Slug; page.Parent = await session.GetAsync <PageEntity>(model.ParentId).ConfigureAwait(false); //page.ParentId = model.ParentId; page.SortOrder = model.SortOrder; page.IsHidden = model.IsHidden; page.Route = model.Route; page.Published = model.Published; page.RevisionNumber = revisionNumber; //page.LastModified = DateTime.Now; page.Permissions.Clear(); foreach (var permission in model.Permissions) { page.Permissions.Add(new PagePermissionEntity { PageId = page.Id, Permission = permission }); } if (!isDraft) { // NHibernate tracks changes automatically and writes on commit //await _db.SaveChangesAsync().ConfigureAwait(false); } else { await MakeDraft(session, model, revisionNumber, lastModified, page).ConfigureAwait(false); // model.Id = await MakeDraft(session, page, revisionNumber, lastModified).ConfigureAwait(false); model.Id = page.Id; } return affected; } // Transform the model if (page == null) { page = new PageEntity { //Id = model.Id != Guid.Empty ? model.Id : Guid.NewGuid(), Parent = (model.ParentId != null && model.ParentId != Guid.Empty) ? await session.GetAsync <PageEntity>(model.ParentId).ConfigureAwait(false) : null, //ParentId = model.ParentId, SortOrder = model.SortOrder, PageType = await session.GetAsync <PageTypeEntity>(model.TypeId).ConfigureAwait(false), //PageTypeId = model.TypeId, //Created = DateTime.Now, RevisionNumber = revisionNumber, //LastModified = DateTime.Now, // ### Begin RT changes ### Title = model.Title, Site = await session.GetAsync <SiteEntity>(model.SiteId).ConfigureAwait(false), ContentType = type.IsArchive ? "Blog" : "Page" // ### End RT changes ##### }; if (!isDraft) { await session.SaveAsync(page).ConfigureAwait(false); model.Id = page.Id; // Only after the new entity object has been saved to NHibernate var dest = await session.Query <PageEntity>().Where(p => p.Site != null && p.Parent != null && p.Site.Id == model.SiteId && p.Parent.Id == model.ParentId).ToListAsync().ConfigureAwait(false); //var dest = await _db.Pages.Where(p => p.SiteId == model.SiteId && p.ParentId == model.ParentId).ToListAsync().ConfigureAwait(false); affected.AddRange(MovePages(dest, page.Id, model.SiteId, model.SortOrder, true)); } } else { // ### Begin RT changes ### page.Parent = (model.ParentId != null && model.ParentId != Guid.Empty) ? await session.GetAsync <PageEntity>(model.ParentId).ConfigureAwait(false) : null; // ### End RT changes ##### // Check if the page has been moved if (page.Parent != null && !isDraft && (page.Parent.Id != model.ParentId || page.SortOrder != model.SortOrder)) { // ### Begin RT changes ### // var siteId = $"Site id = '{page.Site.Id}'"; // var isPageParentNull = $"Page parent is null '{page.Parent == null}'"; // var parentId = $"Parent id = '{page.Parent.Id}'"; // ### End RT changes ##### var source = await session.Query <PageEntity>().Where(p => p.Site == page.Site && p.Parent == page.Parent && p.Id != model.Id).ToListAsync().ConfigureAwait(false); //var source = await _db.Pages.Where(p => p.SiteId == page.SiteId && p.ParentId == page.Parent.Id && p.Id != model.Id).ToListAsync().ConfigureAwait(false); var dest = page.Parent.Id == model.ParentId ? source : await session.Query <PageEntity>().Where(p => p.Site.Id == model.SiteId && p.Parent != null && p.Parent.Id == model.ParentId).ToListAsync().ConfigureAwait(false); //var dest = page.Parent.Id == model.ParentId ? source : await _db.Pages.Where(p => p.SiteId == model.SiteId && p.ParentId == model.ParentId).ToListAsync().ConfigureAwait(false); // Remove the old position for the page affected.AddRange(MovePages(source, page.Id, page.Site.Id, page.SortOrder + 1, false)); // Add room for the new position of the page affected.AddRange(MovePages(dest, page.Id, model.SiteId, model.SortOrder, true)); } page.LastModified = DateTime.Now; } if (isNew || page.Title != model.Title || page.NavigationTitle != model.NavigationTitle) { // If this is new page or title has been updated it means // the global sitemap changes. Notify the service. affected.Add(page.Id); } page = _contentService.Transform(model, type, page); page.ContentType = type.IsArchive ? "Blog" : "Page"; // Set if comments should be enabled page.EnableComments = model.EnableComments; page.CloseCommentsAfterDays = model.CloseCommentsAfterDays; // Update permissions page.Permissions.Clear(); foreach (var permission in model.Permissions) { page.Permissions.Add(new PagePermissionEntity { PageId = page.Id, Permission = permission }); } // Make sure foreign key is set for fields if (!isDraft) { foreach (var field in page.Fields) { if (field.Page == null) //if (field.PageId == Guid.Empty) { field.Page = page; //field.PageId = page.Id; await session.SaveOrUpdateAsync(field).ConfigureAwait(false); //await _db.PageFields.AddAsync(field).ConfigureAwait(false); } } } // Transform blocks var blockModels = model.Blocks; if (blockModels != null) { var blocks = _contentService.TransformBlocks(blockModels, session); var current = blocks.Select(b => b.Id).ToArray(); // Delete removed blocks var removed = page.Blocks .Where(b => !current.Contains(b.Block.Id) && !b.Block.IsReusable && b.Block.ParentId == null) .Select(b => b.Block); var removedItems = page.Blocks .Where(b => !current.Contains(b.Block.Id) && b.Block.ParentId != null && removed.Select(p => p.Id).ToList().Contains(b.Block.ParentId.Value)) .Select(b => b.Block); if (!isDraft) { foreach (var block in removed) { await session.DeleteAsync(block).ConfigureAwait(false); } //_db.Blocks.RemoveRange(removed); foreach (var block in removedItems) { await session.DeleteAsync(block).ConfigureAwait(false); } //_db.Blocks.RemoveRange(removedItems); } // Delete the old page blocks page.Blocks.Clear(); // Now map the new block for (var n = 0; n < blocks.Count; n++) { var block = await session.GetAsync <BlockEntity>(blocks[n].Id).ConfigureAwait(false); //var block = await session.Query<BlockEntity>().FirstOrDefaultAsync(b => b.Id == blocks[n].Id).ConfigureAwait(false); // IQueryable<BlockEntity> blockQuery = _db.Blocks; // if (isDraft) // { // blockQuery = blockQuery.AsNoTracking(); // } // var block = await blockQuery // .Include(b => b.Fields) // .FirstOrDefaultAsync(b => b.Id == blocks[n].Id) // .ConfigureAwait(false); if (block == null) { block = new BlockEntity { //Id = blocks[n].Id != Guid.Empty ? blocks[n].Id : Guid.NewGuid(), Created = DateTime.Now }; if (!isDraft) { session.Save(block); } } block.ParentId = blocks[n].ParentId; block.CLRType = blocks[n].CLRType; block.IsReusable = blocks[n].IsReusable; block.Title = blocks[n].Title; block.LastModified = DateTime.Now; session.Flush(); var currentFields = blocks[n].Fields.Select(f => f.FieldId).Distinct(); var removedFields = block.Fields.Where(f => !currentFields.Contains(f.FieldId)); if (!isDraft) { foreach (var field in removedFields) { await session.DeleteAsync(field).ConfigureAwait(false); } //_db.BlockFields.RemoveRange(removedFields); } foreach (var newField in blocks[n].Fields) { var field = block.Fields.FirstOrDefault(f => f.FieldId == newField.FieldId); if (field == null) { field = new BlockFieldEntity { //Id = newField.Id != Guid.Empty ? newField.Id : Guid.NewGuid(), Block = block, //BlockId = block.Id, FieldId = newField.FieldId //CLRType = newField.CLRType }; if (!isDraft) { //await session.SaveAsync(field).ConfigureAwait(false); //await _db.BlockFields.AddAsync(field).ConfigureAwait(false); } block.Fields.Add(field); } field.SortOrder = newField.SortOrder; field.CLRType = newField.CLRType; field.Value = newField.Value; if (!isDraft) { await session.SaveOrUpdateAsync(field).ConfigureAwait(false); } } // Create the page block var pageBlock = new PageBlockEntity { //Id = Guid.NewGuid(), Block = block, //BlockId = block.Id, Page = page, //PageId = page.Id, SortOrder = n }; if (!isDraft) { await session.SaveAsync(pageBlock).ConfigureAwait(false); //await _db.PageBlocks.AddAsync(pageBlock).ConfigureAwait(false); } page.Blocks.Add(pageBlock); } } if (!isDraft) { // NHibernate keeps track of changes and writes as needed. //await _db.SaveChangesAsync().ConfigureAwait(false); } else { await MakeDraft(session, model, revisionNumber, lastModified, page).ConfigureAwait(false); model.Id = page.Id; // model.Id = await MakeDraft(session, page, revisionNumber, lastModified).ConfigureAwait(false); } return affected; }).ConfigureAwait(false)); }
/// <summary> /// Transforms the given blocks to the internal data model. /// </summary> /// <param name="models">The blocks</param> /// <returns>The data model</returns> public IList <BlockEntity> TransformBlocks(IList <Block> models, ISession session) { var blocks = new List <BlockEntity>(); if (models != null) { for (var n = 0; n < models.Count; n++) { var type = App.Blocks.GetByType(models[n].GetType().FullName); if (type != null) { BlockEntity block = session.Get <BlockEntity>(models[n].Id) ?? new BlockEntity(); block.CLRType = models[n].GetType().FullName; block.Created = DateTime.Now; block.LastModified = DateTime.Now; // block = new BlockEntity() // { // //Id = models[n].Id != Guid.Empty ? models[n].Id : Guid.NewGuid(), // CLRType = models[n].GetType().FullName, // Created = DateTime.Now, // LastModified = DateTime.Now // }; session.SaveOrUpdate(block); foreach (var prop in models[n].GetType().GetProperties(App.PropertyBindings)) { if (typeof(IField).IsAssignableFrom(prop.PropertyType)) { // Only save fields to the database var field = new BlockFieldEntity() { //Id = Guid.NewGuid(), Block = block, //BlockId = block.Id, FieldId = prop.Name, SortOrder = 0, CLRType = prop.PropertyType.FullName, Value = App.SerializeObject(prop.GetValue(models[n]), prop.PropertyType) }; session.SaveOrUpdate(field); block.Fields.Add(field); } } blocks.Add(block); if (typeof(BlockGroup).IsAssignableFrom(models[n].GetType())) { var blockItems = TransformBlocks(((BlockGroup)models[n]).Items, session); if (blockItems.Count > 0) { foreach (var item in blockItems) { item.ParentId = block.Id; } blocks.AddRange(blockItems); } } } } } return(blocks); }