[feature] Support markdown format for Account bio/note (#1037)
* [feature] Status format also controls bio format * test
This commit is contained in:
parent
2216f253c1
commit
67106c9dc4
|
@ -106,7 +106,7 @@ When set to `false`, likes/faves of your post will not be accepted by your GoToS
|
||||||
|
|
||||||
## Input Types
|
## Input Types
|
||||||
|
|
||||||
GoToSocial currently accepts two different types of input for posts. These are:
|
GoToSocial currently accepts two different types of input for posts (and user bio). These are:
|
||||||
|
|
||||||
* `plain`
|
* `plain`
|
||||||
* `markdown`
|
* `markdown`
|
||||||
|
|
|
@ -32,6 +32,8 @@ Your bio is a longer text that introduces your account and your self. Your bio i
|
||||||
- Describe your boundaries and preferences when it comes to other people interacting with you
|
- Describe your boundaries and preferences when it comes to other people interacting with you
|
||||||
- Link hashtags that you often use when you post
|
- Link hashtags that you often use when you post
|
||||||
|
|
||||||
|
The bio accepts either `plain` or `markdown` formatting. This is set by the default post format setting described in [Post Settings](#post-settings).
|
||||||
|
|
||||||
After updating your display name and bio, click on the `Save profile info` button at the bottom of the Profile Info section to save your changes.
|
After updating your display name and bio, click on the `Save profile info` button at the bottom of the Profile Info section to save your changes.
|
||||||
|
|
||||||
### Manually Approve Followers / Lock Your Account
|
### Manually Approve Followers / Lock Your Account
|
||||||
|
|
|
@ -66,7 +66,7 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
||||||
account.NoteRaw = *form.Note
|
account.NoteRaw = *form.Note
|
||||||
|
|
||||||
// Process note to generate a valid HTML representation
|
// Process note to generate a valid HTML representation
|
||||||
note, err := p.processNote(ctx, *form.Note, account.ID)
|
note, err := p.processNote(ctx, *form.Note, account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorBadRequest(err)
|
return nil, gtserror.NewErrorBadRequest(err)
|
||||||
}
|
}
|
||||||
|
@ -241,13 +241,13 @@ func (p *processor) UpdateHeader(ctx context.Context, header *multipart.FileHead
|
||||||
return processingMedia.LoadAttachment(ctx)
|
return processingMedia.LoadAttachment(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *processor) processNote(ctx context.Context, note string, accountID string) (string, error) {
|
func (p *processor) processNote(ctx context.Context, note string, account *gtsmodel.Account) (string, error) {
|
||||||
if note == "" {
|
if note == "" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tagStrings := util.DeriveHashtagsFromText(note)
|
tagStrings := util.DeriveHashtagsFromText(note)
|
||||||
tags, err := p.db.TagStringsToTags(ctx, tagStrings, accountID)
|
tags, err := p.db.TagStringsToTags(ctx, tagStrings, account.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -255,7 +255,7 @@ func (p *processor) processNote(ctx context.Context, note string, accountID stri
|
||||||
mentionStrings := util.DeriveMentionNamesFromText(note)
|
mentionStrings := util.DeriveMentionNamesFromText(note)
|
||||||
mentions := []*gtsmodel.Mention{}
|
mentions := []*gtsmodel.Mention{}
|
||||||
for _, mentionString := range mentionStrings {
|
for _, mentionString := range mentionStrings {
|
||||||
mention, err := p.parseMention(ctx, mentionString, accountID, "")
|
mention, err := p.parseMention(ctx, mentionString, account.ID, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -266,5 +266,9 @@ func (p *processor) processNote(ctx context.Context, note string, accountID stri
|
||||||
// emojiStrings := util.DeriveEmojisFromText(note)
|
// emojiStrings := util.DeriveEmojisFromText(note)
|
||||||
// emojis, err := p.db.EmojiStringsToEmojis(ctx, emojiStrings)
|
// emojis, err := p.db.EmojiStringsToEmojis(ctx, emojiStrings)
|
||||||
|
|
||||||
|
if account.StatusFormat == "markdown" {
|
||||||
|
return p.formatter.FromMarkdown(ctx, note, mentions, tags, nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
return p.formatter.FromPlain(ctx, note, mentions, tags), nil
|
return p.formatter.FromPlain(ctx, note, mentions, tags), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,44 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMention() {
|
||||||
suite.Equal(noteExpected, dbAccount.Note)
|
suite.Equal(noteExpected, dbAccount.Note)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMarkdownNote() {
|
||||||
|
testAccount := suite.testAccounts["local_account_1"]
|
||||||
|
|
||||||
|
note := "*hello* ~~here~~ i am!"
|
||||||
|
expectedNote := `<p><em>hello</em> <del>here</del> i am!</p>`
|
||||||
|
|
||||||
|
form := &apimodel.UpdateCredentialsRequest{
|
||||||
|
Note: ¬e,
|
||||||
|
}
|
||||||
|
|
||||||
|
// set default post language of account 1 to markdown
|
||||||
|
testAccount.StatusFormat = "markdown"
|
||||||
|
|
||||||
|
// should get no error from the update function, and an api model account returned
|
||||||
|
apiAccount, errWithCode := suite.accountProcessor.Update(context.Background(), testAccount, form)
|
||||||
|
// reset test account to avoid breaking other tests
|
||||||
|
testAccount.StatusFormat = "plain"
|
||||||
|
suite.NoError(errWithCode)
|
||||||
|
suite.NotNil(apiAccount)
|
||||||
|
|
||||||
|
// fields on the profile should be updated
|
||||||
|
suite.Equal(expectedNote, apiAccount.Note)
|
||||||
|
|
||||||
|
// we should have an update in the client api channel
|
||||||
|
msg := <-suite.fromClientAPIChan
|
||||||
|
suite.Equal(ap.ActivityUpdate, msg.APActivityType)
|
||||||
|
suite.Equal(ap.ObjectProfile, msg.APObjectType)
|
||||||
|
suite.NotNil(msg.OriginAccount)
|
||||||
|
suite.Equal(testAccount.ID, msg.OriginAccount.ID)
|
||||||
|
suite.Nil(msg.TargetAccount)
|
||||||
|
|
||||||
|
// fields should be updated in the database as well
|
||||||
|
dbAccount, err := suite.db.GetAccountByID(context.Background(), testAccount.ID)
|
||||||
|
suite.NoError(err)
|
||||||
|
suite.Equal(expectedNote, dbAccount.Note)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestAccountUpdateTestSuite(t *testing.T) {
|
func TestAccountUpdateTestSuite(t *testing.T) {
|
||||||
suite.Run(t, new(AccountUpdateTestSuite))
|
suite.Run(t, new(AccountUpdateTestSuite))
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ module.exports = function UserSettings() {
|
||||||
}>
|
}>
|
||||||
<a href="https://docs.gotosocial.org/en/latest/user_guide/posts/#privacy-settings" target="_blank" className="moreinfolink" rel="noreferrer">Learn more about post privacy settings (opens in a new tab)</a>
|
<a href="https://docs.gotosocial.org/en/latest/user_guide/posts/#privacy-settings" target="_blank" className="moreinfolink" rel="noreferrer">Learn more about post privacy settings (opens in a new tab)</a>
|
||||||
</Select>
|
</Select>
|
||||||
<Select id="source.status_format" name="Default post format" options={
|
<Select id="source.status_format" name="Default post (and bio) format" options={
|
||||||
<>
|
<>
|
||||||
<option value="plain">Plain (default)</option>
|
<option value="plain">Plain (default)</option>
|
||||||
<option value="markdown">Markdown</option>
|
<option value="markdown">Markdown</option>
|
||||||
|
|
Loading…
Reference in New Issue