[feature] Let accounts set default status format, and use this when processing new statuses (#739)

* add post_format to acct & use it when making post

* update swagger docs

* add status_format updating to frontend

* fix up tests

* post_format => status_format

* add status_format to account validation
This commit is contained in:
tobi 2022-08-06 12:09:21 +02:00 committed by GitHub
commit f5689a9e5f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 259 additions and 21 deletions

View file

@ -88,6 +88,10 @@ import (
// in: formData
// description: Default language to use for authored statuses (ISO 6391).
// type: string
// - name: source[status_format]
// in: formData
// description: Default format to use for authored statuses (plain or markdown).
// type: string
//
// security:
// - OAuth2 Bearer:
@ -163,6 +167,10 @@ func parseUpdateAccountForm(c *gin.Context) (*model.UpdateCredentialsRequest, er
form.Source.Language = &language
}
if statusFormat, ok := sourceMap["status_format"]; ok {
form.Source.StatusFormat = &statusFormat
}
if form == nil ||
(form.Discoverable == nil &&
form.Bot == nil &&
@ -174,6 +182,7 @@ func parseUpdateAccountForm(c *gin.Context) (*model.UpdateCredentialsRequest, er
form.Source.Privacy == nil &&
form.Source.Sensitive == nil &&
form.Source.Language == nil &&
form.Source.StatusFormat == nil &&
form.FieldsAttributes == nil) {
return nil, errors.New("empty form submitted")
}

View file

@ -362,6 +362,81 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpd
suite.True(apimodelAccount.Locked)
}
func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpdateStatusFormatOK() {
// set up the request
// we're updating the language of zork
requestBody, w, err := testrig.CreateMultipartFormData(
"", "",
map[string]string{
"source[status_format]": "markdown",
})
if err != nil {
panic(err)
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
// 1. we should have OK because our request was valid
suite.Equal(http.StatusOK, recorder.Code)
// 2. we should have no error message in the result body
result := recorder.Result()
defer result.Body.Close()
// check the response
b, err := ioutil.ReadAll(result.Body)
suite.NoError(err)
// unmarshal the returned account
apimodelAccount := &apimodel.Account{}
err = json.Unmarshal(b, apimodelAccount)
suite.NoError(err)
// check the returned api model account
// fields should be updated
suite.Equal("markdown", apimodelAccount.Source.StatusFormat)
dbAccount, err := suite.db.GetAccountByID(context.Background(), suite.testAccounts["local_account_1"].ID)
if err != nil {
suite.FailNow(err.Error())
}
suite.Equal(dbAccount.StatusFormat, "markdown")
}
func (suite *AccountUpdateTestSuite) TestAccountUpdateCredentialsPATCHHandlerUpdateStatusFormatBad() {
// set up the request
// we're updating the language of zork
requestBody, w, err := testrig.CreateMultipartFormData(
"", "",
map[string]string{
"source[status_format]": "peepeepoopoo",
})
if err != nil {
panic(err)
}
bodyBytes := requestBody.Bytes()
recorder := httptest.NewRecorder()
ctx := suite.newContext(recorder, http.MethodPatch, bodyBytes, account.UpdateCredentialsPath, w.FormDataContentType())
// call the handler
suite.accountModule.AccountUpdateCredentialsPATCHHandler(ctx)
suite.Equal(http.StatusBadRequest, recorder.Code)
result := recorder.Result()
defer result.Body.Close()
// check the response
b, err := ioutil.ReadAll(result.Body)
suite.NoError(err)
suite.Equal(`{"error":"Bad Request: status format 'peepeepoopoo' was not recognized, valid options are 'plain', 'markdown'"}`, string(b))
}
func TestAccountUpdateTestSuite(t *testing.T) {
suite.Run(t, new(AccountUpdateTestSuite))
}

View file

@ -41,13 +41,11 @@ type StatusCreateTestSuite struct {
StatusStandardTestSuite
}
var statusWithLinksAndTags = `#test alright, should be able to post #links with fragments in them now, let's see........
https://docs.gotosocial.org/en/latest/user_guide/posts/#links
#gotosocial
(tobi remember to pull the docker image challenge)`
const (
statusWithLinksAndTags = "#test alright, should be able to post #links with fragments in them now, let's see........\n\nhttps://docs.gotosocial.org/en/latest/user_guide/posts/#links\n\n#gotosocial\n\n(tobi remember to pull the docker image challenge)"
statusMarkdown = "# Title\n\n## Smaller title\n\nThis is a post written in [markdown](https://www.markdownguide.org/)\n\n<img src=\"https://d33wubrfki0l68.cloudfront.net/f1f475a6fda1c2c4be4cac04033db5c3293032b4/513a4/assets/images/markdown-mark-white.svg\"/>"
statusMarkdownExpected = "<h1>Title</h1>\n\n<h2>Smaller title</h2>\n\n<p>This is a post written in <a href=\"https://www.markdownguide.org/\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">markdown</a></p>\n\n<p><img src=\"https://d33wubrfki0l68.cloudfront.net/f1f475a6fda1c2c4be4cac04033db5c3293032b4/513a4/assets/images/markdown-mark-white.svg\" crossorigin=\"anonymous\"/></p>\n"
)
// Post a new status with some custom visibility settings
func (suite *StatusCreateTestSuite) TestPostNewStatus() {
@ -104,6 +102,49 @@ func (suite *StatusCreateTestSuite) TestPostNewStatus() {
suite.Equal(statusReply.Account.ID, gtsTag.FirstSeenFromAccountID)
}
func (suite *StatusCreateTestSuite) TestPostNewStatusMarkdown() {
// set default post language of account 1 to markdown
testAccount := suite.testAccounts["local_account_1"]
testAccount.StatusFormat = "markdown"
a, err := suite.db.UpdateAccount(context.Background(), testAccount)
if err != nil {
suite.FailNow(err.Error())
}
suite.Equal(a.StatusFormat, "markdown")
t := suite.testTokens["local_account_1"]
oauthToken := oauth.DBTokenToToken(t)
recorder := httptest.NewRecorder()
ctx, _ := testrig.CreateGinTestContext(recorder, nil)
ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"])
ctx.Set(oauth.SessionAuthorizedToken, oauthToken)
ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"])
ctx.Set(oauth.SessionAuthorizedAccount, a)
ctx.Request = httptest.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:8080/%s", status.BasePath), nil)
ctx.Request.Header.Set("accept", "application/json")
ctx.Request.Form = url.Values{
"status": {statusMarkdown},
"visibility": {string(model.VisibilityPublic)},
}
suite.statusModule.StatusCreatePOSTHandler(ctx)
suite.EqualValues(http.StatusOK, recorder.Code)
result := recorder.Result()
defer result.Body.Close()
b, err := ioutil.ReadAll(result.Body)
suite.NoError(err)
statusReply := &model.Status{}
err = json.Unmarshal(b, statusReply)
suite.NoError(err)
suite.Equal(statusMarkdownExpected, statusReply.Content)
}
// mention an account that is not yet known to the instance -- it should be looked up and put in the db
func (suite *StatusCreateTestSuite) TestMentionUnknownAccount() {
// first remove remote account 1 from the database so it gets looked up again