Example #1
0
        public async Task <IActionResult> Index(
            Guid?siteId,
            string query   = "",
            int sortMode   = 0, //sortMode: 0 = DisplayName asc, 1 = JoinDate desc, 2 = Last, First
            int pageNumber = 1,
            int pageSize   = -1
            )
        {
            ISiteSettings selectedSite;

            // only server admin site can edit other sites settings
            if ((siteId.HasValue) && (siteId.Value != Guid.Empty) && (siteId.Value != siteManager.CurrentSite.Id) && (siteManager.CurrentSite.IsServerAdminSite))
            {
                selectedSite = await siteManager.Fetch(siteId.Value);

                ViewData["Title"] = string.Format(CultureInfo.CurrentUICulture, sr["{0} - User Management"], selectedSite.SiteName);
            }
            else
            {
                selectedSite      = siteManager.CurrentSite;
                ViewData["Title"] = sr["User Management"];
            }

            var itemsPerPage = uiOptions.DefaultPageSize_UserList;

            if (pageSize > 0)
            {
                itemsPerPage = pageSize;
            }

            var siteMembers = await UserManager.GetPage(
                selectedSite.Id,
                pageNumber,
                itemsPerPage,
                query,
                sortMode);

            var count = await UserManager.CountUsers(selectedSite.Id, query);

            var model = new UserListViewModel();

            model.SiteId              = selectedSite.Id;
            model.UserList            = siteMembers;
            model.Paging.CurrentPage  = pageNumber;
            model.Paging.ItemsPerPage = itemsPerPage;
            model.Paging.TotalItems   = count;
            model.SortMode            = sortMode;
            model.AlphaQuery          = query; //TODO: sanitize?
            model.TimeZoneId          = await timeZoneIdResolver.GetUserTimeZoneId();

            return(View(model));
        }
Example #2
0
        public async Task <DateTime> ConvertToLocalTime(DateTime utcInput)
        {
            if (string.IsNullOrEmpty(_currentTimeZoneId))
            {
                _currentTimeZoneId = await _timeZoneIdResolver.GetUserTimeZoneId();
            }

            return(_timeZoneHelper.ConvertToLocalTime(utcInput, _currentTimeZoneId));
        }
Example #3
0
        public async Task <IActionResult> Index(
            Guid?siteId,
            string query   = "",
            int sortMode   = 1, //sortMode: 0 = DisplayName asc, 1 = JoinDate desc, 2 = Last, First
            int pageNumber = 1,
            int pageSize   = -1
            )
        {
            var selectedSite = await _siteManager.GetSiteForDataOperations(siteId);

            // only server admin site can edit other sites settings
            if (selectedSite.Id != _siteManager.CurrentSite.Id)
            {
                ViewData["Title"] = string.Format(CultureInfo.CurrentUICulture, _sr["{0} - User Management"], selectedSite.SiteName);
            }
            else
            {
                ViewData["Title"] = _sr["User Management"];
            }

            var itemsPerPage = _uiOptions.DefaultPageSize_UserList;

            if (pageSize > 0)
            {
                itemsPerPage = pageSize;
            }

            var siteMembers = await _userManager.GetPage(
                selectedSite.Id,
                pageNumber,
                itemsPerPage,
                query,
                sortMode);

            var model = new UserListViewModel
            {
                SiteId     = selectedSite.Id,
                UserList   = siteMembers,
                SortMode   = sortMode,
                AlphaQuery = query,
                TimeZoneId = await _timeZoneIdResolver.GetUserTimeZoneId()
            };

            return(View(model));
        }
Example #4
0
        public async Task <IActionResult> Index(
            string logLevel = "",
            int pageNumber  = 1,
            int pageSize    = -1,
            string sort     = "desc")
        {
            ViewData["Title"]   = "System Log";
            ViewData["Heading"] = "System Log";

            int itemsPerPage = logManager.LogPageSize;

            if (pageSize > 0)
            {
                itemsPerPage = pageSize;
            }

            var model = new LogListViewModel
            {
                LogLevel = logLevel
            };
            PagedQueryResult result;

            if (sort == "desc")
            {
                result = await logManager.GetLogsDescending(pageNumber, itemsPerPage, logLevel);
            }
            else
            {
                result = await logManager.GetLogsAscending(pageNumber, itemsPerPage, logLevel);
            }

            model.TimeZoneId = await timeZoneIdResolver.GetUserTimeZoneId();

            model.LogPage = result.Items;

            model.Paging.CurrentPage  = pageNumber;
            model.Paging.ItemsPerPage = itemsPerPage;
            model.Paging.TotalItems   = result.TotalItems;

            return(View(model));
        }
        public async Task <CommandResult <IPage> > Handle(UpdateTemplatedPageRequest request, CancellationToken cancellationToken = default(CancellationToken))
        {
            var errors             = new List <string>();
            var customModelIsValid = true;

            try
            {
                var page    = request.Page;
                var history = page.CreateHistory(request.UserName);
                var project = await _projectService.GetProjectSettings(request.ProjectId);

                var serializer = GetSerializer(request.Template.SerializerName);
                var parser     = GetFormParser(request.Template.FormParserName);
                var validator  = GetValidator(request.Template.ValidatorName);
                var type       = Type.GetType(request.Template.ModelType);
                var model      = parser.ParseModel(request.Template.ModelType, request.Form);
                if (model == null)
                {
                    errors.Add(_localizer["Failed to parse custom template model from form."]);
                    customModelIsValid = false;
                    //failed to parse model from form
                    // at least return the original model before changes
                    string pageModelString;
                    if (!string.IsNullOrWhiteSpace(page.DraftSerializedModel))
                    {
                        pageModelString = page.DraftSerializedModel;
                    }
                    else
                    {
                        pageModelString = page.SerializedModel;
                    }
                    if (!string.IsNullOrWhiteSpace(pageModelString))
                    {
                        request.ViewModel.TemplateModel = serializer.Deserialize(request.Template.ModelType, pageModelString);
                    }
                }

                if (customModelIsValid)
                {
                    // we are going to return the parsed model either way
                    request.ViewModel.TemplateModel = model;

                    var validationContext = new ValidationContext(model, serviceProvider: null, items: null);
                    var validationResults = new List <ValidationResult>();

                    customModelIsValid = validator.IsValid(model, validationContext, validationResults);
                    if (!customModelIsValid)
                    {
                        foreach (var item in validationResults)
                        {
                            foreach (var memberName in item.MemberNames)
                            {
                                request.ModelState.AddModelError(memberName, item.ErrorMessage);
                            }
                        }
                    }
                }

                if (!string.IsNullOrEmpty(request.ViewModel.Slug))
                {
                    // remove any bad characters
                    request.ViewModel.Slug = ContentUtils.CreateSlug(request.ViewModel.Slug);
                    if (request.ViewModel.Slug != page.Slug)
                    {
                        var slugIsAvailable = await _pageService.SlugIsAvailable(request.ViewModel.Slug);

                        if (!slugIsAvailable)
                        {
                            errors.Add(_localizer["The page slug was not changed because the requested slug is already in use."]);
                            request.ModelState.AddModelError("Slug", _localizer["The page slug was not changed because the requested slug is already in use."]);
                        }
                    }
                }

                if (request.ModelState.IsValid)
                {
                    var modelString   = serializer.Serialize(request.Template.ModelType, model);
                    var renderedModel = await _viewRenderer.RenderViewAsString(request.Template.RenderView, model).ConfigureAwait(false);

                    page.Title              = request.ViewModel.Title;
                    page.CorrelationKey     = request.ViewModel.CorrelationKey;
                    page.LastModified       = DateTime.UtcNow;
                    page.LastModifiedByUser = request.UserName;
                    page.MenuFilters        = request.ViewModel.MenuFilters;
                    page.MetaDescription    = request.ViewModel.MetaDescription;
                    page.PageOrder          = request.ViewModel.PageOrder;

                    page.ShowHeading  = request.ViewModel.ShowHeading;
                    page.ShowMenu     = request.ViewModel.ShowMenu;
                    page.ShowComments = request.ViewModel.ShowComments;
                    page.MenuFilters  = request.ViewModel.MenuFilters;

                    page.ViewRoles = request.ViewModel.ViewRoles;

                    if (!string.IsNullOrEmpty(request.ViewModel.Slug))
                    {
                        page.Slug = request.ViewModel.Slug;
                    }

                    page.ViewRoles = request.ViewModel.ViewRoles;

                    if (!string.IsNullOrEmpty(request.ViewModel.ParentSlug))
                    {
                        var parentPage = await _pageService.GetPageBySlug(request.ViewModel.ParentSlug);

                        if (parentPage != null)
                        {
                            if (parentPage.Id != page.ParentId)
                            {
                                page.ParentId   = parentPage.Id;
                                page.ParentSlug = parentPage.Slug;
                            }
                        }
                    }
                    else
                    {
                        // empty means root level
                        page.ParentSlug = string.Empty;
                        page.ParentId   = "0";
                    }

                    if (page.ParentSlug == project.DefaultPageSlug)
                    {
                        _log.LogWarning($"{request.UserName} tried to explicitely set the default page slug as the parent slug which is not allowed since all root pages are already children of the default page");
                        page.ParentSlug = string.Empty;
                        page.ParentId   = "0";
                    }

                    var shouldFirePublishEvent = false;
                    switch (request.ViewModel.SaveMode)
                    {
                    case SaveMode.SaveDraft:

                        page.DraftSerializedModel = modelString;
                        page.DraftContent         = renderedModel;
                        page.DraftAuthor          = request.ViewModel.Author;
                        if (!page.PubDate.HasValue)
                        {
                            page.IsPublished = false;
                        }

                        break;

                    case SaveMode.PublishLater:
                        page.DraftSerializedModel = modelString;
                        page.DraftContent         = renderedModel;
                        page.DraftAuthor          = request.ViewModel.Author;
                        if (request.ViewModel.NewPubDate.HasValue)
                        {
                            var tzId = await _timeZoneIdResolver.GetUserTimeZoneId(CancellationToken.None);

                            page.DraftPubDate = _timeZoneHelper.ConvertToUtc(request.ViewModel.NewPubDate.Value, tzId);
                        }
                        if (!page.PubDate.HasValue)
                        {
                            page.IsPublished = false;
                        }

                        break;

                    case SaveMode.PublishNow:

                        page.Author          = request.ViewModel.Author;
                        page.Content         = renderedModel;
                        page.SerializedModel = modelString;

                        page.PubDate           = DateTime.UtcNow;
                        page.IsPublished       = true;
                        shouldFirePublishEvent = true;

                        page.DraftAuthor          = null;
                        page.DraftContent         = null;
                        page.DraftPubDate         = null;
                        page.DraftSerializedModel = null;

                        break;
                    }

                    await _historyCommands.Create(request.ProjectId, history).ConfigureAwait(false);

                    await _pageService.Update(page);

                    if (shouldFirePublishEvent)
                    {
                        await _pageService.FirePublishEvent(page).ConfigureAwait(false);

                        await _historyCommands.DeleteDraftHistory(project.Id, page.Id).ConfigureAwait(false);
                    }

                    await _navigationCache.ClearTreeCache();
                }

                return(new CommandResult <IPage>(page, customModelIsValid && request.ModelState.IsValid, errors));
            }
            catch (Exception ex)
            {
                _log.LogError($"{ex.Message}:{ex.StackTrace}");

                errors.Add(_localizer["Updating a page from a content template failed. An error has been logged."]);

                return(new CommandResult <IPage>(null, false, errors));
            }
        }
Example #6
0
        public async Task <CommandResult <IPost> > Handle(CreateOrUpdatePostRequest request, CancellationToken cancellationToken = default(CancellationToken))
        {
            var errors = new List <string>();

            try
            {
                bool isNew   = false;
                var  project = await _projectService.GetProjectSettings(request.ProjectId);

                var            post    = request.Post;
                ContentHistory history = null;
                if (post == null)
                {
                    isNew = true;
                    post  = new Post()
                    {
                        BlogId          = request.ProjectId,
                        Title           = request.ViewModel.Title,
                        MetaDescription = request.ViewModel.MetaDescription,
                        Slug            = ContentUtils.CreateSlug(request.ViewModel.Title),
                        CreatedByUser   = request.UserName
                    };
                }
                else
                {
                    history = post.CreateHistory(request.UserName);
                }

                if (!string.IsNullOrEmpty(request.ViewModel.Slug))
                {
                    // remove any bad characters
                    request.ViewModel.Slug = ContentUtils.CreateSlug(request.ViewModel.Slug);
                    if (request.ViewModel.Slug != post.Slug)
                    {
                        var slugIsAvailable = await _blogService.SlugIsAvailable(request.ViewModel.Slug);

                        if (!slugIsAvailable)
                        {
                            request.ModelState.AddModelError("Slug", _localizer["The page slug was not changed because the requested slug is already in use."]);
                        }
                    }
                }

                if (request.ModelState.IsValid)
                {
                    post.Title              = request.ViewModel.Title;
                    post.CorrelationKey     = request.ViewModel.CorrelationKey;
                    post.ImageUrl           = request.ViewModel.ImageUrl;
                    post.ThumbnailUrl       = request.ViewModel.ThumbnailUrl;
                    post.IsFeatured         = request.ViewModel.IsFeatured;
                    post.ContentType        = request.ViewModel.ContentType;
                    post.TeaserOverride     = request.ViewModel.TeaserOverride;
                    post.SuppressTeaser     = request.ViewModel.SuppressTeaser;
                    post.LastModified       = DateTime.UtcNow;
                    post.LastModifiedByUser = request.UserName;

                    if (!string.IsNullOrEmpty(request.ViewModel.Slug))
                    {
                        post.Slug = request.ViewModel.Slug;
                    }


                    var categories = new List <string>();

                    if (!string.IsNullOrEmpty(request.ViewModel.Categories))
                    {
                        if (_editOptions.ForceLowerCaseCategories)
                        {
                            categories = request.ViewModel.Categories.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim().ToLower())
                                         .Where(x =>
                                                !string.IsNullOrWhiteSpace(x) &&
                                                x != ","
                                                )
                                         .Distinct()
                                         .ToList();
                        }
                        else
                        {
                            categories = request.ViewModel.Categories.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim())
                                         .Where(x =>
                                                !string.IsNullOrWhiteSpace(x) &&
                                                x != ","
                                                )
                                         .Distinct()
                                         .ToList();
                        }
                    }
                    post.Categories = categories;


                    var shouldFirePublishEvent = false;
                    switch (request.ViewModel.SaveMode)
                    {
                    case SaveMode.SaveDraft:

                        post.DraftContent = request.ViewModel.Content;
                        post.DraftAuthor  = request.ViewModel.Author;

                        break;

                    case SaveMode.PublishLater:

                        post.DraftContent = request.ViewModel.Content;
                        post.DraftAuthor  = request.ViewModel.Author;
                        if (request.ViewModel.NewPubDate.HasValue)
                        {
                            var tzId = await _timeZoneIdResolver.GetUserTimeZoneId(CancellationToken.None);

                            post.DraftPubDate = _timeZoneHelper.ConvertToUtc(request.ViewModel.NewPubDate.Value, tzId);
                        }
                        if (!post.PubDate.HasValue)
                        {
                            post.IsPublished = false;
                        }

                        break;

                    case SaveMode.PublishNow:

                        post.Content = request.ViewModel.Content;
                        post.Author  = request.ViewModel.Author;
                        if (!post.PubDate.HasValue)
                        {
                            post.PubDate = DateTime.UtcNow;
                        }
                        else if (post.PubDate > DateTime.UtcNow)
                        {
                            post.PubDate = DateTime.UtcNow;
                        }

                        post.IsPublished       = true;
                        shouldFirePublishEvent = true;

                        post.DraftAuthor  = null;
                        post.DraftContent = null;
                        post.DraftPubDate = null;

                        break;
                    }

                    if (project.TeaserMode != TeaserMode.Off)
                    {
                        // need to generate the teaser on save
                        string html = null;
                        if (post.ContentType == "markdown")
                        {
                            var mdPipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
                            html = Markdown.ToHtml(post.Content, mdPipeline);
                        }
                        else
                        {
                            html = post.Content;
                        }
                        var teaserResult = _teaserService.GenerateTeaser(
                            project.TeaserTruncationMode,
                            project.TeaserTruncationLength,
                            html,
                            Guid.NewGuid().ToString(),//cache key
                            post.Slug,
                            project.LanguageCode,
                            false //logWarnings
                            );
                        post.AutoTeaser = teaserResult.Content;
                    }

                    if (history != null)
                    {
                        await _historyCommands.Create(request.ProjectId, history).ConfigureAwait(false);
                    }

                    if (isNew)
                    {
                        await _blogService.Create(post);
                    }
                    else
                    {
                        await _blogService.Update(post);
                    }

                    if (shouldFirePublishEvent)
                    {
                        await _blogService.FirePublishEvent(post);

                        await _historyCommands.DeleteDraftHistory(request.ProjectId, post.Id).ConfigureAwait(false);
                    }
                }

                return(new CommandResult <IPost>(post, request.ModelState.IsValid, errors));
            }
            catch (Exception ex)
            {
                _log.LogError($"{ex.Message}:{ex.StackTrace}");

                errors.Add(_localizer["Updating a page failed. An error has been logged."]);

                return(new CommandResult <IPost>(null, false, errors));
            }
        }
Example #7
0
        public async Task <CommandResult <IPage> > Handle(CreateOrUpdatePageRequest request, CancellationToken cancellationToken = default(CancellationToken))
        {
            var errors = new List <string>();

            try
            {
                bool isNew   = false;
                var  project = await _projectService.GetProjectSettings(request.ProjectId);

                var            page    = request.Page;
                ContentHistory history = null;
                if (page == null)
                {
                    isNew = true;
                    page  = new Page()
                    {
                        ProjectId     = request.ProjectId,
                        ParentId      = "0",
                        CreatedByUser = request.UserName,
                        Slug          = ContentUtils.CreateSlug(request.ViewModel.Title),
                        ContentType   = request.ViewModel.ContentType
                    };
                }
                else
                {
                    history = page.CreateHistory(request.UserName);
                }


                if (!string.IsNullOrEmpty(request.ViewModel.Slug))
                {
                    // remove any bad characters
                    request.ViewModel.Slug = ContentUtils.CreateSlug(request.ViewModel.Slug);
                    if (request.ViewModel.Slug != page.Slug)
                    {
                        var slugIsAvailable = await _pageService.SlugIsAvailable(request.ViewModel.Slug);

                        if (!slugIsAvailable)
                        {
                            errors.Add(_localizer["The page slug was invalid because the requested slug is already in use."]);
                            request.ModelState.AddModelError("Slug", _localizer["The page slug was not changed because the requested slug is already in use."]);
                        }
                    }
                }

                if (request.ModelState.IsValid)
                {
                    page.Title              = request.ViewModel.Title;
                    page.CorrelationKey     = request.ViewModel.CorrelationKey;
                    page.LastModified       = DateTime.UtcNow;
                    page.LastModifiedByUser = request.UserName;
                    page.MenuFilters        = request.ViewModel.MenuFilters;
                    page.MetaDescription    = request.ViewModel.MetaDescription;
                    page.PageOrder          = request.ViewModel.PageOrder;

                    page.ShowHeading   = request.ViewModel.ShowHeading;
                    page.ShowMenu      = request.ViewModel.ShowMenu;
                    page.MenuOnly      = request.ViewModel.MenuOnly;
                    page.DisableEditor = request.ViewModel.DisableEditor;
                    page.ShowComments  = request.ViewModel.ShowComments;
                    page.MenuFilters   = request.ViewModel.MenuFilters;
                    page.ExternalUrl   = request.ViewModel.ExternalUrl;
                    page.ViewRoles     = request.ViewModel.ViewRoles;


                    if (!string.IsNullOrEmpty(request.ViewModel.Slug))
                    {
                        page.Slug = request.ViewModel.Slug;
                    }

                    if (!string.IsNullOrEmpty(request.ViewModel.ParentSlug))
                    {
                        var parentPage = await _pageService.GetPageBySlug(request.ViewModel.ParentSlug);

                        if (parentPage != null)
                        {
                            if (parentPage.Id != page.ParentId)
                            {
                                page.ParentId   = parentPage.Id;
                                page.ParentSlug = parentPage.Slug;
                            }
                        }
                    }
                    else
                    {
                        // empty means root level
                        page.ParentSlug = string.Empty;
                        page.ParentId   = "0";
                    }

                    if (page.ParentSlug == project.DefaultPageSlug)
                    {
                        _log.LogWarning($"{request.UserName} tried to explicitely set the default page slug as the parent slug which is not allowed since all root pages are already children of the default page");
                        page.ParentSlug = string.Empty;
                        page.ParentId   = "0";
                    }


                    var shouldFirePublishEvent = false;
                    //var shouldFireUnPublishEvent = false;
                    switch (request.ViewModel.SaveMode)
                    {
                    //case SaveMode.UnPublish:

                    //    page.DraftContent = request.ViewModel.Content;
                    //    page.DraftAuthor = request.ViewModel.Author;
                    //    page.DraftPubDate = null;
                    //    page.IsPublished = false;
                    //    page.PubDate = null;

                    //    shouldFireUnPublishEvent = true;

                    //    break;

                    case SaveMode.SaveDraft:

                        page.DraftContent = request.ViewModel.Content;
                        page.DraftAuthor  = request.ViewModel.Author;
                        // should we clear the draft pub date if save draft clicked?
                        //page.DraftPubDate = null;
                        if (!page.PubDate.HasValue)
                        {
                            page.IsPublished = false;
                        }

                        break;

                    case SaveMode.PublishLater:

                        page.DraftContent = request.ViewModel.Content;
                        page.DraftAuthor  = request.ViewModel.Author;
                        if (request.ViewModel.NewPubDate.HasValue)
                        {
                            var tzId = await _timeZoneIdResolver.GetUserTimeZoneId(CancellationToken.None);

                            page.DraftPubDate = _timeZoneHelper.ConvertToUtc(request.ViewModel.NewPubDate.Value, tzId);
                        }
                        if (!page.PubDate.HasValue)
                        {
                            page.IsPublished = false;
                        }

                        break;

                    case SaveMode.PublishNow:

                        page.Content           = request.ViewModel.Content;
                        page.Author            = request.ViewModel.Author;
                        page.PubDate           = DateTime.UtcNow;
                        page.IsPublished       = true;
                        shouldFirePublishEvent = true;

                        page.DraftAuthor  = null;
                        page.DraftContent = null;
                        page.DraftPubDate = null;

                        break;
                    }

                    if (history != null)
                    {
                        await _historyCommands.Create(request.ProjectId, history).ConfigureAwait(false);
                    }

                    if (isNew)
                    {
                        await _pageService.Create(page);
                    }
                    else
                    {
                        await _pageService.Update(page);
                    }

                    if (shouldFirePublishEvent)
                    {
                        await _pageService.FirePublishEvent(page).ConfigureAwait(false);

                        await _historyCommands.DeleteDraftHistory(project.Id, page.Id).ConfigureAwait(false);
                    }

                    //if (shouldFireUnPublishEvent)
                    //{
                    //    await _pageService.FireUnPublishEvent(page).ConfigureAwait(false);
                    //}

                    _pageService.ClearNavigationCache();
                }

                return(new CommandResult <IPage>(page, request.ModelState.IsValid, errors));
            }
            catch (Exception ex)
            {
                _log.LogError($"{ex.Message}:{ex.StackTrace}");

                errors.Add(_localizer["Updating a page failed. An error has been logged."]);

                return(new CommandResult <IPage>(null, false, errors));
            }
        }
Example #8
0
        public async Task <CommandResult <IPost> > Handle(UpdateTemplatedPostRequest request, CancellationToken cancellationToken = default(CancellationToken))
        {
            var errors             = new List <string>();
            var customModelIsValid = true;

            try
            {
                var post    = request.Post;
                var history = post.CreateHistory(request.UserName);
                var project = await _projectService.GetCurrentProjectSettings();

                var serializer = GetSerializer(request.Template.SerializerName);
                var parser     = GetFormParser(request.Template.FormParserName);
                var validator  = GetValidator(request.Template.ValidatorName);
                var type       = Type.GetType(request.Template.ModelType);
                var model      = parser.ParseModel(request.Template.ModelType, request.Form);
                if (model == null)
                {
                    errors.Add(_localizer["Failed to parse custom template model from form."]);
                    customModelIsValid = false;
                    //failed to parse model from form
                    // at least return the original model before changes
                    string pageModelString;
                    if (!string.IsNullOrWhiteSpace(post.DraftSerializedModel))
                    {
                        pageModelString = post.DraftSerializedModel;
                    }
                    else
                    {
                        pageModelString = post.SerializedModel;
                    }
                    if (!string.IsNullOrWhiteSpace(pageModelString))
                    {
                        request.ViewModel.TemplateModel = serializer.Deserialize(request.Template.ModelType, pageModelString);
                    }
                }

                if (customModelIsValid)
                {
                    // we are going to return the parsed model either way
                    request.ViewModel.TemplateModel = model;

                    var validationContext = new ValidationContext(model, serviceProvider: null, items: null);
                    var validationResults = new List <ValidationResult>();

                    customModelIsValid = validator.IsValid(model, validationContext, validationResults);
                    if (!customModelIsValid)
                    {
                        foreach (var item in validationResults)
                        {
                            foreach (var memberName in item.MemberNames)
                            {
                                request.ModelState.AddModelError(memberName, item.ErrorMessage);
                            }
                        }
                    }
                }

                if (!string.IsNullOrEmpty(request.ViewModel.Slug))
                {
                    // remove any bad characters
                    request.ViewModel.Slug = ContentUtils.CreateSlug(request.ViewModel.Slug);
                    if (request.ViewModel.Slug != post.Slug)
                    {
                        var slug            = request.ViewModel.Slug;
                        var slugIsAvailable = await _blogService.SlugIsAvailable(slug);

                        while (!slugIsAvailable)
                        {
                            slug           += "-";
                            slugIsAvailable = await _blogService.SlugIsAvailable(slug);
                        }

                        if (slugIsAvailable)
                        {
                            post.Slug = slug;
                        }
                    }
                }

                if (request.ModelState.IsValid)
                {
                    var modelString   = serializer.Serialize(request.Template.ModelType, model);
                    var renderedModel = await _viewRenderer.RenderViewAsString(request.Template.RenderView, model).ConfigureAwait(false);

                    post.Title              = request.ViewModel.Title;
                    post.CorrelationKey     = request.ViewModel.CorrelationKey;
                    post.ImageUrl           = request.ViewModel.ImageUrl;
                    post.ThumbnailUrl       = request.ViewModel.ThumbnailUrl;
                    post.IsFeatured         = request.ViewModel.IsFeatured;
                    post.TeaserOverride     = request.ViewModel.TeaserOverride;
                    post.SuppressTeaser     = request.ViewModel.SuppressTeaser;
                    post.ShowComments       = request.ViewModel.ShowComments;
                    post.LastModified       = DateTime.UtcNow;
                    post.LastModifiedByUser = request.UserName;
                    post.MetaDescription    = request.ViewModel.MetaDescription;

                    var categories = new List <string>();
                    if (!string.IsNullOrEmpty(request.ViewModel.Categories))
                    {
                        if (_editOptions.ForceLowerCaseCategories)
                        {
                            categories = request.ViewModel.Categories.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim().ToLower())
                                         .Where(x =>
                                                !string.IsNullOrWhiteSpace(x) &&
                                                x != ","
                                                )
                                         .Distinct()
                                         .ToList();
                        }
                        else
                        {
                            categories = request.ViewModel.Categories.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim())
                                         .Where(x =>
                                                !string.IsNullOrWhiteSpace(x) &&
                                                x != ","
                                                )
                                         .Distinct()
                                         .ToList();
                        }
                    }
                    post.Categories = categories;

                    var tzId = await _timeZoneIdResolver.GetUserTimeZoneId(CancellationToken.None);

                    var shouldFirePublishEvent = false;
                    var saveMode = request.ViewModel.SaveMode;
                    if (saveMode == SaveMode.PublishLater)
                    {
                        if (request.ViewModel.NewPubDate.HasValue)
                        {
                            var newPubDate = _timeZoneHelper.ConvertToUtc(request.ViewModel.NewPubDate.Value, tzId);
                            if (newPubDate < DateTime.UtcNow)
                            {
                                saveMode     = SaveMode.PublishNow;
                                post.PubDate = newPubDate;
                            }
                        }
                    }

                    switch (saveMode)
                    {
                    case SaveMode.SaveDraft:

                        post.DraftSerializedModel = modelString;
                        post.DraftContent         = renderedModel;
                        post.DraftAuthor          = request.ViewModel.Author;
                        if (!post.PubDate.HasValue)
                        {
                            post.IsPublished = false;
                        }

                        break;

                    case SaveMode.PublishLater:
                        post.DraftSerializedModel = modelString;
                        post.DraftContent         = renderedModel;
                        post.DraftAuthor          = request.ViewModel.Author;
                        if (request.ViewModel.NewPubDate.HasValue)
                        {
                            post.DraftPubDate = _timeZoneHelper.ConvertToUtc(request.ViewModel.NewPubDate.Value, tzId);
                        }
                        if (!post.PubDate.HasValue)
                        {
                            post.IsPublished = false;
                        }

                        break;

                    case SaveMode.PublishNow:

                        post.Author          = request.ViewModel.Author;
                        post.Content         = renderedModel;
                        post.SerializedModel = modelString;

                        if (!post.PubDate.HasValue)
                        {
                            post.PubDate = DateTime.UtcNow;
                        }

                        post.IsPublished       = true;
                        shouldFirePublishEvent = true;

                        post.DraftAuthor          = null;
                        post.DraftContent         = null;
                        post.DraftPubDate         = null;
                        post.DraftSerializedModel = null;

                        break;
                    }

                    if (project.TeaserMode != TeaserMode.Off)
                    {
                        // need to generate the teaser on save
                        var teaserResult = _teaserService.GenerateTeaser(
                            project.TeaserTruncationMode,
                            project.TeaserTruncationLength,
                            post.Content,
                            Guid.NewGuid().ToString(),//cache key
                            post.Slug,
                            project.LanguageCode,
                            false //logWarnings
                            );
                        post.AutoTeaser = teaserResult.Content;
                    }

                    await _historyCommands.Create(request.ProjectId, history).ConfigureAwait(false);

                    await _blogService.Update(post);

                    if (shouldFirePublishEvent)
                    {
                        await _blogService.FirePublishEvent(post).ConfigureAwait(false);

                        await _historyCommands.DeleteDraftHistory(project.Id, post.Id).ConfigureAwait(false);
                    }
                }

                return(new CommandResult <IPost>(post, customModelIsValid && request.ModelState.IsValid, errors));
            }
            catch (Exception ex)
            {
                _log.LogError($"{ex.Message}:{ex.StackTrace}");

                errors.Add(_localizer["Updating a post from a content template failed. An error has been logged."]);

                return(new CommandResult <IPost>(null, false, errors));
            }
        }