public async Task <IActionResult> CreateRevision(int pageId, IFormCollection request) { /* To be supplied in request body - * * Reason for change - e.g. Updated pricing information * Template ID * Collection of text components * Collection of media components * */ try { // Load page from database Page page = await _Db.Pages.FindAsync(pageId); if (page == null) { return(BadRequest("No page exists for given page ID")); } List <TextComponent> newRevisionTextComponents = request.Deserialize(typeof(List <TextComponent>), "textComponents"); List <MediaComponent> newRevisionMediaComponents = request.Deserialize(typeof(List <MediaComponent>), "imageComponents"); // Todo: Do this after the view has had template switching enabled // Load template from database // PageTemplate template = await _Db.PageTemplates // .FindAsync(request.Int("templateId")); // Fetch the original revision PageRevision old = await _Db.PageRevisions .Include(pr => pr.Template) .Include(pr => pr.RevisionMediaComponents) .ThenInclude(rmc => rmc.MediaComponent) .Include(pr => pr.RevisionTextComponents) .ThenInclude(rtc => rtc.TextComponent) .ThenInclude(tc => tc.CmsButton) .Where(pr => pr.Page == page) .OrderByDescending(pr => pr.CreatedAt) .FirstOrDefaultAsync(); var oldRevision = new { old.Template, TextComponents = old.RevisionTextComponents .Select(rtc => rtc.TextComponent) .OrderBy(tc => tc.SlotNo) .ToList(), MediaComponents = old.RevisionMediaComponents .Select(rmc => rmc.MediaComponent) .OrderBy(tc => tc.SlotNo) .ToList() }; // Create the new page revision PageRevision newRevision = new PageRevision { Page = page, Template = oldRevision.Template, Reason = request.Str("reason"), CreatedBy = await _Db.Accounts.FindAsync(User.AccountId()), }; // Assign the new revision an ID await _Db.AddAsync(newRevision); for (int i = 0; i < newRevision.Template.TextAreas; i++) { TextComponent textComponentToSave = null; // Only save a new text component if it has changed if (!newRevisionTextComponents[i].Equals(oldRevision.TextComponents[i])) { textComponentToSave = newRevisionTextComponents[i]; // Set ID to 0 so that EF Core assigns us a new one textComponentToSave.Id = 0; // Save a new button if the components button does not yet exist in database. if (textComponentToSave.CmsButton != null && !textComponentToSave.CmsButton.Equals(oldRevision.TextComponents[i].CmsButton)) { await _Db.AddAsync(textComponentToSave.CmsButton); } // Generate ID for the new TextComponent await _Db.AddAsync(textComponentToSave); } // Add association between component and new revision await _Db.AddAsync(new RevisionTextComponent { // Use the new components ID if it exists, other use existing (unchanged) component // from previous revision TextComponentId = textComponentToSave?.Id ?? oldRevision.TextComponents[i].Id, PageRevisionId = newRevision.Id }); } // Do the same for media components for (int i = 0; i < newRevision.Template.MediaAreas; i++) { MediaComponent mediaComponentToSave = null; // Only create new media component if the old one was modified if (!newRevisionMediaComponents[i].Equals(oldRevision.MediaComponents[i])) { mediaComponentToSave = newRevisionMediaComponents[i]; // Generate new ID mediaComponentToSave.Id = 0; await _Db.AddAsync(mediaComponentToSave); } // Add association to new revision await _Db.AddAsync(new RevisionMediaComponent { PageRevisionId = newRevision.Id, MediaComponentId = mediaComponentToSave?.Id ?? oldRevision.MediaComponents[i].Id }); } // Save changes await _Db.SaveChangesAsync(); _Logger.LogDebug("New page revision created for page {0} ({1}): {2}", pageId, page.Name, newRevision.Reason); return(Ok()); } catch (Exception ex) { _Logger.LogError("Error creating new revision for page {0}: {1}", pageId, ex.Message); _Logger.LogError(ex.StackTrace); return(BadRequest("Something went wrong, please try again later.")); } }