mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 20:12:26 -05:00 
			
		
		
		
	[bugfix] Use custom blackfriday renderer to only add mention/hashtag links in normal text (#787)
* Use custom blackfriday renderer to only add mention/hashtag links in normal text * Add additional markdown tests
This commit is contained in:
		
					parent
					
						
							
								0245c606d7
							
						
					
				
			
			
				commit
				
					
						f01492ae48
					
				
			
		
					 2 changed files with 60 additions and 7 deletions
				
			
		|  | @ -19,7 +19,9 @@ | |||
| package text | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/russross/blackfriday/v2" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||
|  | @ -33,18 +35,51 @@ var ( | |||
| 	m            *minify.M | ||||
| ) | ||||
| 
 | ||||
| type renderer struct { | ||||
| 	f        *formatter | ||||
| 	ctx      context.Context | ||||
| 	mentions []*gtsmodel.Mention | ||||
| 	tags     []*gtsmodel.Tag | ||||
| 	blackfriday.HTMLRenderer | ||||
| } | ||||
| 
 | ||||
| func (r *renderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { | ||||
| 	if node.Type == blackfriday.Text { | ||||
| 		// call RenderNode to do the html escaping | ||||
| 		var buff bytes.Buffer | ||||
| 		status := r.HTMLRenderer.RenderNode(&buff, node, entering) | ||||
| 
 | ||||
| 		html := buff.String() | ||||
| 		html = r.f.ReplaceTags(r.ctx, html, r.tags) | ||||
| 		html = r.f.ReplaceMentions(r.ctx, html, r.mentions) | ||||
| 
 | ||||
| 		// we don't have much recourse if this fails | ||||
| 		_, err := io.WriteString(w, html) | ||||
| 		if err != nil { | ||||
| 			log.Errorf("error outputting markdown text: %s", err) | ||||
| 		} | ||||
| 		return status | ||||
| 	} | ||||
| 	return r.HTMLRenderer.RenderNode(w, node, entering) | ||||
| } | ||||
| 
 | ||||
| func (f *formatter) FromMarkdown(ctx context.Context, md string, mentions []*gtsmodel.Mention, tags []*gtsmodel.Tag) string { | ||||
| 	// format tags nicely | ||||
| 	content := f.ReplaceTags(ctx, md, tags) | ||||
| 
 | ||||
| 	// format mentions nicely | ||||
| 	content = f.ReplaceMentions(ctx, content, mentions) | ||||
| 	renderer := &renderer{ | ||||
| 		f:        f, | ||||
| 		ctx:      ctx, | ||||
| 		mentions: mentions, | ||||
| 		tags:     tags, | ||||
| 		HTMLRenderer: *blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{ | ||||
| 			Flags: blackfriday.CommonHTMLFlags, | ||||
| 		}), | ||||
| 	} | ||||
| 
 | ||||
| 	// parse markdown | ||||
| 	contentBytes := blackfriday.Run([]byte(content), blackfriday.WithExtensions(bfExtensions)) | ||||
| 	// parse markdown, use custom renderer to add hashtag/mention links | ||||
| 	contentBytes := blackfriday.Run([]byte(md), blackfriday.WithExtensions(bfExtensions), blackfriday.WithRenderer(renderer)) | ||||
| 
 | ||||
| 	// clean anything dangerous out of it | ||||
| 	content = SanitizeHTML(string(contentBytes)) | ||||
| 	content := SanitizeHTML(string(contentBytes)) | ||||
| 
 | ||||
| 	if m == nil { | ||||
| 		m = minify.New() | ||||
|  |  | |||
|  | @ -65,6 +65,10 @@ const ( | |||
| 	mdWithFootnoteExpected          = "<p>fox mulder,fbi.<sup id=\"fnref:1\"><a href=\"#fn:1\" rel=\"nofollow noreferrer\">1</a></sup></p><div><hr><ol><li id=\"fn:1\">federated bureau of investigation<br></li></ol></div>" | ||||
| 	mdWithBlockQuote                = "get ready, there's a block quote coming:\n\n>line1\n>line2\n>\n>line3\n\n" | ||||
| 	mdWithBlockQuoteExpected        = "<p>get ready, there’s a block quote coming:</p><blockquote><p>line1<br>line2</p><p>line3</p></blockquote>" | ||||
| 	mdHashtagAndCodeBlock           = "#Hashtag\n\n```\n#Hashtag\n```" | ||||
| 	mdHashtagAndCodeBlockExpected   = "<p><a href=\"http://localhost:8080/tags/Hashtag\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>Hashtag</span></a></p><pre><code>#Hashtag\n</code></pre>" | ||||
| 	mdMentionAndCodeBlock           = "@the_mighty_zork\n\n```\n@the_mighty_zork\n```" | ||||
| 	mdMentionAndCodeBlockExpected   = "<p><span class=\"h-card\"><a href=\"http://localhost:8080/@the_mighty_zork\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">@<span>the_mighty_zork</span></a></span></p><pre><code>@the_mighty_zork\n</code></pre>" | ||||
| ) | ||||
| 
 | ||||
| type MarkdownTestSuite struct { | ||||
|  | @ -133,6 +137,20 @@ func (suite *MarkdownTestSuite) TestParseWithBlockquote() { | |||
| 	suite.Equal(mdWithBlockQuoteExpected, s) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseHashtagWithCodeBlock() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdHashtagAndCodeBlock, nil, []*gtsmodel.Tag{ | ||||
| 		suite.testTags["Hashtag"], | ||||
| 	}) | ||||
| 	suite.Equal(mdHashtagAndCodeBlockExpected, s) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseMentionWithCodeBlock() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdMentionAndCodeBlock, []*gtsmodel.Mention{ | ||||
| 		suite.testMentions["local_user_2_mention_zork"], | ||||
| 	}, nil) | ||||
| 	suite.Equal(mdMentionAndCodeBlockExpected, s) | ||||
| } | ||||
| 
 | ||||
| func TestMarkdownTestSuite(t *testing.T) { | ||||
| 	suite.Run(t, new(MarkdownTestSuite)) | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue