public void should_convert_markdown_to_html() { var md = "**Hello World**"; var html = MarkdownConverter.ToHtml(md); Assert.Equal("<p><strong>Hello World</strong></p>\n", html); }
public static TopicViewModel CreateFrom(Topic topic, List <Reply> replies) { return(new TopicViewModel(topic) { HtmlContent = MarkdownConverter.ToHtml(topic.Content), Replies = replies }); }
public void Should_Convert_Markdown_To_Html_Correctly() { string markdown = GetStream("BetterCms.Test.Module.Contents.Markdown.markdown.txt"); string html = GetStream("BetterCms.Test.Module.Contents.Markdown.html.txt"); var result = MarkdownConverter.ToHtml(markdown); result = ClearSpaces(result); html = ClearSpaces(html); Assert.AreEqual(html, result); }
public void should_convert_markdown_with_fenced_code_block() { var md = @"**Hello World** ```js console.log('hello js'); ``` text after code block"; var html = MarkdownConverter.ToHtml(md); Assert.Equal("<p><strong>Hello World</strong></p>\n<pre><code class=\"language-js\">console.log('hello js');\n</code></pre>\n\n<p>text after code block</p>\n", html); }
public async Task <IActionResult> Details(string id) { if (string.IsNullOrWhiteSpace(id)) { return(NotFound()); } var note = await _noteService.FindOne(id); if (note == null) { return(NotFound()); } note.Content = _markdown.ToHtml(note.Content); return(View(note)); }
public void should_convert_markdown_with_fenced_code_block_and_unescape_code_content() { var md = @"**Hello World** ```html <html> <title>title text</title> </html> ``` text after code block"; var html = MarkdownConverter.ToHtml(md); Assert.Equal("<p><strong>Hello World</strong></p>\n<pre><code class=\"language-html\"><html>\n<title>title text</title>\n</html>\n</code></pre>\n\n<p>text after code block</p>\n", html); }
public void ToHTml_EmptyMarkdown_Throws() { // Setup the test. string markdown = string.Empty; try { // Run the test. MarkdownConverter target = new MarkdownConverter(); target.ToHtml(markdown); } catch (ArgumentException ex) { // Validate the results. Assert.AreEqual("markdown", ex.ParamName); throw; } }
public void Should_Strip_Widget_Paragraphs_Correctly() { string before = @"<p><widget data-id=""AFA0AFEF-6D71-4962-9EF4-324BB9344F92"" data-assign-id=""FCBD3A46-4A77-4FC9-B9CE-9515C9D6AF77"">Header Logo</widget> </p> # {{CmsPageTitle}} <p> <widget data-id=""AFA0AFEF-6D71-4962-9EF4-324BB9344F92"" data-assign-id=""FCBD3A46-4A77-4FC9-B9CE-9515C9D6AF77"">Header Logo</widget> test </p> <h1>{{CmsPageTitle}}</h1> <p> <widget data-id=""AFA0AFEF-6D71-4962-9EF4-324BB9344F92"" data-assign-id=""FCBD3A46-4A77-4FC9-B9CE-9515C9D6AF77"">Header Logo</widget> </p>"; string shouldBe = @"<widget data-id=""AFA0AFEF-6D71-4962-9EF4-324BB9344F92"" data-assign-id=""FCBD3A46-4A77-4FC9-B9CE-9515C9D6AF77"">Header Logo</widget> <h1>{{CmsPageTitle}}</h1> <p> <widget data-id=""AFA0AFEF-6D71-4962-9EF4-324BB9344F92"" data-assign-id=""FCBD3A46-4A77-4FC9-B9CE-9515C9D6AF77"">Header Logo</widget> test </p> <h1>{{CmsPageTitle}}</h1> <widget data-id=""AFA0AFEF-6D71-4962-9EF4-324BB9344F92"" data-assign-id=""FCBD3A46-4A77-4FC9-B9CE-9515C9D6AF77"">Header Logo</widget>"; var after = MarkdownConverter.ToHtml(before); after = ClearSpaces(after); shouldBe = ClearSpaces(shouldBe); Assert.AreEqual(after, shouldBe); }
public void ToHTml_ValidMarkdown_Success() { //// TODO: Setup the test to cover all markdown syntax features. // Setup the test. string markdown = @"# Heading1 A paragraph with **bold** and *italic* text."; string expectedHtml = @"<h1>Heading1</h1> <p>A paragraph with <strong>bold</strong> and <em>italic</em> text.</p>"; // Run the test. MarkdownConverter target = new MarkdownConverter(); string result = target.ToHtml(markdown); // Validate the results. Assert.AreEqual(expectedHtml, result); }
public IDictionary <string, object> ToDictionary(Config.Config config) { string languagePrefix = config.MultipleLanguages switch { true => Language, false => "" }; // This is the "presentation layer" for this model object. The field names below are what the .hbs // templates will see. return(new Dictionary <string, object> { { "title", Title }, { "date", Date.ToString("MMM d, yyyy") }, { "date_iso", Date.ToString("yyyy-MM-dd") }, { "body", MarkdownConverter.ToHtml(Body, LineBreaks ?? config.LineBreaks) }, { "excerpt", MarkdownConverter.ToHtml(Excerpt, LineBreaks ?? config.LineBreaks) }, { "language", Language }, { "link", Path.Join( "/", languagePrefix, Slugify(Categories.First()), Date.Year.ToString(), Date.Month.ToString(), Date.Day.ToString(), Slugify(Title) ) }, { "categories", Categories.Select(c => new Dictionary <string, string> { { "name", c }, { "slug", Path.Join(languagePrefix, Slugify(c)) } }) } }); }
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.EnabledCustomJs, CustomJs = model.CustomJs, EditInSourceMode = model.EditInSourceMode, ContentTextMode = ContentTextMode.Html }; if (model.ContentTextMode == ContentTextMode.Markdown) { if (!string.IsNullOrWhiteSpace(model.PageContent)) { contentToSave.Html = MarkdownConverter.ToHtml(model.PageContent); } else { contentToSave.Html = string.Empty; } contentToSave.ContentTextMode = ContentTextMode.Markdown; contentToSave.OriginalText = model.PageContent; } if (model.ContentTextMode == ContentTextMode.SimpleText) { if (!string.IsNullOrWhiteSpace(model.PageContent)) { contentToSave.Html = HttpUtility.HtmlEncode(model.PageContent); } else { contentToSave.Html = string.Empty; } contentToSave.ContentTextMode = ContentTextMode.SimpleText; contentToSave.OriginalText = model.PageContent; } // 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> /// Saves the blog post. /// </summary> /// <param name="request">The request.</param> /// <param name="childContentOptionValues">The child content option values.</param> /// <param name="principal">The principal.</param> /// <param name="errorMessages">The error messages.</param> /// <param name="updateActivationIfNotChanged">if set to <c>true</c> update activation time even if it was not changed.</param> /// <returns> /// Saved blog post entity /// </returns> /// <exception cref="System.ComponentModel.DataAnnotations.ValidationException"></exception> /// <exception cref="SecurityException">Forbidden: Access is denied.</exception> public BlogPost SaveBlogPost(BlogPostViewModel request, IList <ContentOptionValuesViewModel> childContentOptionValues, IPrincipal principal, out string[] errorMessages, bool updateActivationIfNotChanged = true) { errorMessages = new string[0]; string[] roles; if (request.DesirableStatus == ContentStatus.Published) { accessControlService.DemandAccess(principal, RootModuleConstants.UserRoles.PublishContent); roles = new[] { RootModuleConstants.UserRoles.PublishContent }; } else { accessControlService.DemandAccess(principal, RootModuleConstants.UserRoles.EditContent); roles = new[] { RootModuleConstants.UserRoles.EditContent }; } var isNew = request.Id.HasDefaultValue(); var userCanEdit = securityService.IsAuthorized(RootModuleConstants.UserRoles.EditContent); ValidateData(isNew, request); BlogPost blogPost; BlogPostContent content; PageContent pageContent; GetBlogPostAndContentEntities(request, principal, roles, ref isNew, out content, out pageContent, out blogPost); var beforeChange = new UpdatingBlogModel(blogPost); // Master page / layout Layout layout; Page masterPage; Region region; LoadDefaultLayoutAndRegion(out layout, out masterPage, out region); if (masterPage != null) { var level = accessControlService.GetAccessLevel(masterPage, principal); if (level < AccessLevel.Read) { var message = BlogGlobalization.SaveBlogPost_FailedToSave_InaccessibleMasterPage; const string logMessage = "Failed to save blog post. Selected template for page layout is inaccessible."; throw new ValidationException(() => message, logMessage); } } if (pageContent.Region == null) { pageContent.Region = region; } // Load master pages for updating page's master path and page's children master path IList <Guid> newMasterIds; IList <Guid> oldMasterIds; IList <Guid> childrenPageIds; IList <MasterPage> existingChildrenMasterPages; PrepareForUpdateChildrenMasterPages(isNew, blogPost, request, out newMasterIds, out oldMasterIds, out childrenPageIds, out existingChildrenMasterPages); // TODO: TEST AND TRY TO FIX IT: TRANSACTION HERE IS REQUIRED! // UnitOfWork.BeginTransaction(); // NOTE: this causes concurrent data exception. Redirect redirectCreated = null; if (!isNew && userCanEdit && !string.Equals(blogPost.PageUrl, request.BlogUrl) && !string.IsNullOrWhiteSpace(request.BlogUrl)) { request.BlogUrl = urlService.FixUrl(request.BlogUrl); pageService.ValidatePageUrl(request.BlogUrl, request.Id); if (request.RedirectFromOldUrl) { var redirect = redirectService.CreateRedirectEntity(blogPost.PageUrl, request.BlogUrl); if (redirect != null) { repository.Save(redirect); redirectCreated = redirect; } } blogPost.PageUrl = urlService.FixUrl(request.BlogUrl); } // Push to change modified data each time. blogPost.ModifiedOn = DateTime.Now; if (userCanEdit) { blogPost.Title = request.Title; blogPost.Description = request.IntroText; blogPost.Author = request.AuthorId.HasValue ? repository.AsProxy <Author>(request.AuthorId.Value) : null; blogPost.Image = (request.Image != null && request.Image.ImageId.HasValue) ? repository.AsProxy <MediaImage>(request.Image.ImageId.Value) : null; if (isNew || request.DesirableStatus == ContentStatus.Published) { if (updateActivationIfNotChanged) { blogPost.ActivationDate = request.LiveFromDate; blogPost.ExpirationDate = TimeHelper.FormatEndDate(request.LiveToDate); } else { blogPost.ActivationDate = TimeHelper.GetFirstIfTheSameDay(blogPost.ActivationDate, request.LiveFromDate); blogPost.ExpirationDate = TimeHelper.GetFirstIfTheSameDay(blogPost.ExpirationDate, TimeHelper.FormatEndDate(request.LiveToDate)); } } } if (isNew) { if (!string.IsNullOrWhiteSpace(request.BlogUrl)) { blogPost.PageUrl = urlService.FixUrl(request.BlogUrl); pageService.ValidatePageUrl(blogPost.PageUrl); } else { blogPost.PageUrl = CreateBlogPermalink(request.Title, null, request.Categories != null ? request.Categories.Select(c => Guid.Parse(c.Key)) : null); } blogPost.MetaTitle = request.MetaTitle ?? request.Title; if (masterPage != null) { blogPost.MasterPage = masterPage; masterPageService.SetPageMasterPages(blogPost, masterPage.Id); } else { blogPost.Layout = layout; } UpdateStatus(blogPost, request.DesirableStatus); AddDefaultAccessRules(blogPost, principal, masterPage); } else if (request.DesirableStatus == ContentStatus.Published || blogPost.Status == PageStatus.Preview) { // Update only if publishing or current status is preview. // Else do not change, because it may change from published to draft status UpdateStatus(blogPost, request.DesirableStatus); } // Create content. var newContent = new BlogPostContent { Id = content != null ? content.Id : Guid.Empty, Name = request.Title, Html = request.Content ?? string.Empty, OriginalText = request.OriginalText, EditInSourceMode = request.EditInSourceMode, ActivationDate = request.LiveFromDate, ExpirationDate = TimeHelper.FormatEndDate(request.LiveToDate), ContentTextMode = request.ContentTextMode, }; if (!updateActivationIfNotChanged && content != null) { newContent.ActivationDate = TimeHelper.GetFirstIfTheSameDay(content.ActivationDate, newContent.ActivationDate); newContent.ExpirationDate = TimeHelper.GetFirstIfTheSameDay(content.ExpirationDate, newContent.ExpirationDate); } if (request.ContentTextMode == ContentTextMode.Markdown && request.Content == null && request.OriginalText != null) { newContent.Html = MarkdownConverter.ToHtml(request.OriginalText); } // 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; newContent.ContentTextMode = contentToPublish.ContentTextMode; newContent.OriginalText = contentToPublish.OriginalText; } content = SaveContentWithStatusUpdate(isNew, newContent, request, principal); pageContent.Content = content; optionService.SaveChildContentOptions(content, childContentOptionValues, request.DesirableStatus); blogPost.PageUrlHash = blogPost.PageUrl.UrlHash(); blogPost.UseCanonicalUrl = request.UseCanonicalUrl; MapExtraProperties(isNew, blogPost, content, pageContent, request, principal); // Notify about page properties changing. var cancelEventArgs = Events.BlogEvents.Instance.OnBlogChanging(beforeChange, new UpdatingBlogModel(blogPost)); if (cancelEventArgs.Cancel) { errorMessages = cancelEventArgs.CancellationErrorMessages.ToArray(); return(null); } if (isNew || userCanEdit) { categoryService.CombineEntityCategories <BlogPost, PageCategory>(blogPost, request.Categories); } var oldLanguageId = blogPost.Language != null ? blogPost.Language.Id : (Guid?)null; var newLanguageId = request.LanguageId; if (oldLanguageId != newLanguageId) { blogPost.Language = request.LanguageId.HasValue ? repository.AsProxy <Language>(request.LanguageId.Value) : null; } repository.Save(blogPost); repository.Save(content); repository.Save(pageContent); masterPageService.UpdateChildrenMasterPages(existingChildrenMasterPages, oldMasterIds, newMasterIds, childrenPageIds); pageContent.Content = content; blogPost.PageContents = new [] { pageContent }; IList <Tag> newTags = null; if (userCanEdit) { newTags = SaveTags(blogPost, request); } if (userCanEdit && ConfigurationHelper.IsFillSeoDataFromArticlePropertiesEnabled(configuration)) { FillMetaInfo(blogPost); } // Commit unitOfWork.Commit(); // Notify about new created tags. Events.RootEvents.Instance.OnTagCreated(newTags); // Notify about new or updated blog post. if (isNew) { Events.BlogEvents.Instance.OnBlogCreated(blogPost); } else { Events.BlogEvents.Instance.OnBlogUpdated(blogPost); } // Notify about redirect creation. if (redirectCreated != null) { Events.PageEvents.Instance.OnRedirectCreated(redirectCreated); } return(blogPost); }
/// <summary> /// Puts the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns> /// <c>PutHtmlContentResponse</c> with html content id. /// </returns> public PutHtmlContentResponse Put(PutHtmlContentRequest request) { var isNew = !request.Id.HasValue || request.Id.Value.HasDefaultValue(); Module.Pages.Models.HtmlContent originalContent = null; if (!isNew) { originalContent = repository.FirstOrDefault <Module.Pages.Models.HtmlContent>(request.Id.Value); isNew = originalContent == null; } var contentToSave = new Module.Pages.Models.HtmlContent { Id = request.Id.GetValueOrDefault(), ActivationDate = request.Data.ActivationDate, ExpirationDate = TimeHelper.FormatEndDate(request.Data.ExpirationDate), Name = request.Data.Name, Html = request.Data.Html ?? string.Empty, OriginalText = request.Data.OriginalText ?? string.Empty, ContentTextMode = (Module.Pages.Models.Enums.ContentTextMode)request.Data.ContentTextMode, UseCustomCss = request.Data.UseCustomCss, CustomCss = request.Data.CustomCss, UseCustomJs = request.Data.UseCustomJavaScript, CustomJs = request.Data.CustomJavaScript }; if (request.Data.ContentTextMode == ContentTextMode.Markdown && request.Data.Html == null && request.Data.OriginalText != null) { contentToSave.Html = MarkdownConverter.ToHtml(request.Data.OriginalText); } if (request.Data.ContentTextMode == ContentTextMode.SimpleText && request.Data.Html == null && request.Data.OriginalText != null) { contentToSave.Html = HttpUtility.HtmlEncode(request.Data.OriginalText); } if (request.Data.IsPublished) { if (isNew) { if (request.Data.PublishedOn.HasValue) { contentToSave.PublishedOn = request.Data.PublishedOn; } if (!string.IsNullOrEmpty(request.Data.PublishedByUser)) { contentToSave.PublishedByUser = request.Data.PublishedByUser; } } else { contentToSave.PublishedOn = originalContent.PublishedOn; contentToSave.PublishedByUser = originalContent.PublishedByUser; } } unitOfWork.BeginTransaction(); Module.Pages.Models.HtmlContent content; var desirableStatus = request.Data.IsPublished ? ContentStatus.Published : ContentStatus.Draft; if (isNew && contentToSave.Id != default(Guid)) { content = contentToSave; contentService.UpdateDynamicContainer(content); content.Status = desirableStatus; content.Id = contentToSave.Id; repository.Save(content); } else { if (request.Data.Version > 0) { contentToSave.Version = request.Data.Version; } content = (Module.Pages.Models.HtmlContent)contentService .SaveContentWithStatusUpdate(contentToSave, desirableStatus); } var childContentOptionValues = request.Data.ChildContentsOptionValues != null?request.Data.ChildContentsOptionValues.ToViewModel() : null; optionService.SaveChildContentOptions(content, childContentOptionValues, desirableStatus); unitOfWork.Commit(); if (isNew) { Events.PageEvents.Instance.OnHtmlContentCreated(content); } else { Events.PageEvents.Instance.OnHtmlContentUpdated(content); } return(new PutHtmlContentResponse { Data = content.Id }); }