2023-03-12 15:00:57 +00:00
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2021-05-08 13:25:55 +01:00
2023-01-02 12:10:50 +00:00
package accounts_test
2021-05-08 13:25:55 +01:00
import (
2021-09-11 12:19:06 +01:00
"context"
2021-09-10 13:36:10 +01:00
"encoding/json"
2021-05-08 13:25:55 +01:00
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/suite"
2023-01-02 12:10:50 +00:00
"github.com/superseriousbusiness/gotosocial/internal/api/client/accounts"
2021-09-10 13:36:10 +01:00
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
2021-05-08 13:25:55 +01:00
"github.com/superseriousbusiness/gotosocial/testrig"
)
type AccountUpdateTestSuite struct {
AccountStandardTestSuite
}
2021-09-11 12:19:06 +01:00
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandler ( ) {
// set up the request
2023-03-06 09:30:19 +00:00
// we're updating the note and profile fields of zork
2021-09-11 12:19:06 +01:00
newBio := "this is my new bio read it and weep"
requestBody , w , err := testrig . CreateMultipartFormData (
"" , "" ,
map [ string ] string {
2023-03-06 09:30:19 +00:00
"note" : newBio ,
"fields_attributes[0][name]" : "pronouns" ,
"fields_attributes[0][value]" : "they/them" ,
2021-09-11 12:19:06 +01:00
} )
if err != nil {
panic ( err )
}
bodyBytes := requestBody . Bytes ( )
recorder := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx := suite . newContext ( recorder , http . MethodPatch , bodyBytes , accounts . UpdateCredentialsPath , w . FormDataContentType ( ) )
2021-09-11 12:19:06 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx )
2021-09-11 12:19:06 +01:00
// 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 )
2022-06-08 19:38:03 +01:00
suite . NoError ( err )
2021-09-11 12:19:06 +01:00
// 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 ( "<p>this is my new bio read it and weep</p>" , apimodelAccount . Note )
2023-03-06 09:30:19 +00:00
suite . Equal ( "they/them" , apimodelAccount . Fields [ 0 ] . Value )
2022-05-07 16:55:27 +01:00
suite . Equal ( newBio , apimodelAccount . Source . Note )
2021-09-11 12:19:06 +01:00
}
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandlerUnlockLock ( ) {
// set up the first request
requestBody1 , w1 , err := testrig . CreateMultipartFormData (
"" , "" ,
map [ string ] string {
"locked" : "false" ,
} )
if err != nil {
panic ( err )
}
bodyBytes1 := requestBody1 . Bytes ( )
recorder1 := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx1 := suite . newContext ( recorder1 , http . MethodPatch , bodyBytes1 , accounts . UpdateCredentialsPath , w1 . FormDataContentType ( ) )
2021-09-11 12:19:06 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx1 )
2021-09-11 12:19:06 +01:00
// 1. we should have OK because our request was valid
suite . Equal ( http . StatusOK , recorder1 . Code )
// 2. we should have no error message in the result body
result1 := recorder1 . Result ( )
defer result1 . Body . Close ( )
// check the response
b1 , err := ioutil . ReadAll ( result1 . Body )
2022-06-08 19:38:03 +01:00
suite . NoError ( err )
2021-09-11 12:19:06 +01:00
// unmarshal the returned account
apimodelAccount1 := & apimodel . Account { }
err = json . Unmarshal ( b1 , apimodelAccount1 )
suite . NoError ( err )
// check the returned api model account
// fields should be updated
suite . False ( apimodelAccount1 . Locked )
// set up the first request
requestBody2 , w2 , err := testrig . CreateMultipartFormData (
"" , "" ,
map [ string ] string {
"locked" : "true" ,
} )
if err != nil {
panic ( err )
}
bodyBytes2 := requestBody2 . Bytes ( )
recorder2 := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx2 := suite . newContext ( recorder2 , http . MethodPatch , bodyBytes2 , accounts . UpdateCredentialsPath , w2 . FormDataContentType ( ) )
2021-09-11 12:19:06 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx2 )
2021-09-11 12:19:06 +01:00
// 1. we should have OK because our request was valid
suite . Equal ( http . StatusOK , recorder1 . Code )
// 2. we should have no error message in the result body
result2 := recorder2 . Result ( )
defer result2 . Body . Close ( )
// check the response
b2 , err := ioutil . ReadAll ( result2 . Body )
suite . NoError ( err )
// unmarshal the returned account
apimodelAccount2 := & apimodel . Account { }
err = json . Unmarshal ( b2 , apimodelAccount2 )
suite . NoError ( err )
// check the returned api model account
// fields should be updated
suite . True ( apimodelAccount2 . Locked )
}
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandlerGetAccountFirst ( ) {
// get the account first to make sure it's in the database cache -- when the account is updated via
// the PATCH handler, it should invalidate the cache and not return the old version
_ , err := suite . db . GetAccountByID ( context . Background ( ) , suite . testAccounts [ "local_account_1" ] . ID )
suite . NoError ( err )
// set up the request
// we're updating the note of zork
newBio := "this is my new bio read it and weep"
requestBody , w , err := testrig . CreateMultipartFormData (
"" , "" ,
map [ string ] string {
"note" : newBio ,
} )
if err != nil {
panic ( err )
}
bodyBytes := requestBody . Bytes ( )
recorder := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx := suite . newContext ( recorder , http . MethodPatch , bodyBytes , accounts . UpdateCredentialsPath , w . FormDataContentType ( ) )
2021-09-11 12:19:06 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx )
2021-09-11 12:19:06 +01:00
// 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 )
2022-06-08 19:38:03 +01:00
suite . NoError ( err )
2021-09-11 12:19:06 +01:00
// 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 ( "<p>this is my new bio read it and weep</p>" , apimodelAccount . Note )
2022-05-07 16:55:27 +01:00
suite . Equal ( newBio , apimodelAccount . Source . Note )
2021-09-11 12:19:06 +01:00
}
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandlerTwoFields ( ) {
// set up the request
// we're updating the note of zork, and setting locked to true
2022-09-26 10:56:01 +01:00
newBio := "this is my new bio read it and weep :rainbow:"
2021-09-11 12:19:06 +01:00
requestBody , w , err := testrig . CreateMultipartFormData (
"" , "" ,
map [ string ] string {
"note" : newBio ,
"locked" : "true" ,
} )
if err != nil {
panic ( err )
}
bodyBytes := requestBody . Bytes ( )
recorder := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx := suite . newContext ( recorder , http . MethodPatch , bodyBytes , accounts . UpdateCredentialsPath , w . FormDataContentType ( ) )
2021-09-11 12:19:06 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx )
2021-09-11 12:19:06 +01:00
// 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 )
2022-06-08 19:38:03 +01:00
suite . NoError ( err )
2021-09-11 12:19:06 +01:00
// 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
2022-09-26 10:56:01 +01:00
suite . Equal ( "<p>this is my new bio read it and weep :rainbow:</p>" , apimodelAccount . Note )
2022-05-07 16:55:27 +01:00
suite . Equal ( newBio , apimodelAccount . Source . Note )
2021-09-11 12:19:06 +01:00
suite . True ( apimodelAccount . Locked )
2022-09-26 10:56:01 +01:00
suite . NotEmpty ( apimodelAccount . Emojis )
suite . Equal ( apimodelAccount . Emojis [ 0 ] . Shortcode , "rainbow" )
// check the account in the database
dbZork , err := suite . db . GetAccountByID ( context . Background ( ) , apimodelAccount . ID )
suite . NoError ( err )
suite . Equal ( newBio , dbZork . NoteRaw )
suite . Equal ( "<p>this is my new bio read it and weep :rainbow:</p>" , dbZork . Note )
suite . True ( * dbZork . Locked )
suite . NotEmpty ( dbZork . EmojiIDs )
2021-09-11 12:19:06 +01:00
}
2023-02-16 13:20:23 +00:00
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandlerDiscoverable ( ) {
requestBody , w , err := testrig . CreateMultipartFormData (
"" , "" ,
map [ string ] string {
"discoverable" : "false" ,
} )
if err != nil {
panic ( err )
}
bodyBytes := requestBody . Bytes ( )
recorder := httptest . NewRecorder ( )
ctx := suite . newContext ( recorder , http . MethodPatch , bodyBytes , accounts . UpdateCredentialsPath , w . FormDataContentType ( ) )
// call the handler
suite . accountsModule . 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 . False ( apimodelAccount . Discoverable )
// check the account in the database
dbZork , err := suite . db . GetAccountByID ( context . Background ( ) , apimodelAccount . ID )
suite . NoError ( err )
suite . False ( * dbZork . Discoverable )
}
2021-09-11 12:19:06 +01:00
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandlerWithMedia ( ) {
2021-09-10 13:36:10 +01:00
// set up the request
// we're updating the header image, the display name, and the locked status of zork
// we're removing the note/bio
requestBody , w , err := testrig . CreateMultipartFormData (
"header" , "../../../../testrig/media/test-jpeg.jpg" ,
map [ string ] string {
"display_name" : "updated zork display name!!!" ,
"note" : "" ,
"locked" : "true" ,
} )
2021-05-08 13:25:55 +01:00
if err != nil {
panic ( err )
}
2021-09-11 12:19:06 +01:00
bodyBytes := requestBody . Bytes ( )
2021-05-08 13:25:55 +01:00
recorder := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx := suite . newContext ( recorder , http . MethodPatch , bodyBytes , accounts . UpdateCredentialsPath , w . FormDataContentType ( ) )
2021-05-08 13:25:55 +01:00
2021-09-10 13:36:10 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx )
2021-05-08 13:25:55 +01:00
// 1. we should have OK because our request was valid
2021-09-10 13:36:10 +01:00
suite . Equal ( http . StatusOK , recorder . Code )
2021-05-08 13:25:55 +01:00
// 2. we should have no error message in the result body
result := recorder . Result ( )
defer result . Body . Close ( )
2021-09-10 13:36:10 +01:00
// check the response
2021-05-08 13:25:55 +01:00
b , err := ioutil . ReadAll ( result . Body )
2022-06-08 19:38:03 +01:00
suite . NoError ( err )
2021-05-08 13:25:55 +01:00
2021-09-10 13:36:10 +01:00
// 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 ( "updated zork display name!!!" , apimodelAccount . DisplayName )
suite . True ( apimodelAccount . Locked )
suite . Empty ( apimodelAccount . Note )
2022-05-07 16:55:27 +01:00
suite . Empty ( apimodelAccount . Source . Note )
2021-09-10 13:36:10 +01:00
// header values...
// should be set
suite . NotEmpty ( apimodelAccount . Header )
suite . NotEmpty ( apimodelAccount . HeaderStatic )
// should be different from the values set before
2023-01-11 11:13:13 +00:00
suite . NotEqual ( "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg" , apimodelAccount . Header )
suite . NotEqual ( "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg" , apimodelAccount . HeaderStatic )
2021-05-08 13:25:55 +01:00
}
2021-09-11 12:19:06 +01:00
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandlerEmptyForm ( ) {
// set up the request
bodyBytes := [ ] byte { }
recorder := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx := suite . newContext ( recorder , http . MethodPatch , bodyBytes , accounts . UpdateCredentialsPath , "" )
2021-09-11 12:19:06 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx )
2021-09-11 12:19:06 +01:00
// 1. we should have OK because our request was valid
suite . Equal ( http . StatusBadRequest , 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 )
2022-06-08 19:38:03 +01:00
suite . NoError ( err )
suite . Equal ( ` { "error":"Bad Request: empty form submitted"} ` , string ( b ) )
2021-09-11 12:19:06 +01:00
}
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandlerUpdateSource ( ) {
// set up the request
// we're updating the language of zork
newLanguage := "de"
requestBody , w , err := testrig . CreateMultipartFormData (
"" , "" ,
map [ string ] string {
"source[privacy]" : string ( apimodel . VisibilityPrivate ) ,
"source[language]" : "de" ,
"source[sensitive]" : "true" ,
"locked" : "true" ,
} )
if err != nil {
panic ( err )
}
bodyBytes := requestBody . Bytes ( )
recorder := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx := suite . newContext ( recorder , http . MethodPatch , bodyBytes , accounts . UpdateCredentialsPath , w . FormDataContentType ( ) )
2021-09-11 12:19:06 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx )
2021-09-11 12:19:06 +01:00
// 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 )
2022-06-08 19:38:03 +01:00
suite . NoError ( err )
2021-09-11 12:19:06 +01:00
// 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 ( newLanguage , apimodelAccount . Source . Language )
suite . EqualValues ( apimodel . VisibilityPrivate , apimodelAccount . Source . Privacy )
suite . True ( apimodelAccount . Source . Sensitive )
suite . True ( apimodelAccount . Locked )
}
2023-03-02 11:06:40 +00:00
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandlerUpdateStatusContentTypeOK ( ) {
2022-08-06 11:09:21 +01:00
// set up the request
// we're updating the language of zork
requestBody , w , err := testrig . CreateMultipartFormData (
"" , "" ,
map [ string ] string {
2023-03-02 11:06:40 +00:00
"source[status_content_type]" : "text/markdown" ,
2022-08-06 11:09:21 +01:00
} )
if err != nil {
panic ( err )
}
bodyBytes := requestBody . Bytes ( )
recorder := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx := suite . newContext ( recorder , http . MethodPatch , bodyBytes , accounts . UpdateCredentialsPath , w . FormDataContentType ( ) )
2022-08-06 11:09:21 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx )
2022-08-06 11:09:21 +01:00
// 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
2023-03-02 11:06:40 +00:00
suite . Equal ( "text/markdown" , apimodelAccount . Source . StatusContentType )
2022-08-06 11:09:21 +01:00
dbAccount , err := suite . db . GetAccountByID ( context . Background ( ) , suite . testAccounts [ "local_account_1" ] . ID )
if err != nil {
suite . FailNow ( err . Error ( ) )
}
2023-03-02 11:06:40 +00:00
suite . Equal ( dbAccount . StatusContentType , "text/markdown" )
2022-08-06 11:09:21 +01:00
}
2023-03-02 11:06:40 +00:00
func ( suite * AccountUpdateTestSuite ) TestAccountUpdateCredentialsPATCHHandlerUpdateStatusContentTypeBad ( ) {
2022-08-06 11:09:21 +01:00
// set up the request
// we're updating the language of zork
requestBody , w , err := testrig . CreateMultipartFormData (
"" , "" ,
map [ string ] string {
2023-03-02 11:06:40 +00:00
"source[status_content_type]" : "peepeepoopoo" ,
2022-08-06 11:09:21 +01:00
} )
if err != nil {
panic ( err )
}
bodyBytes := requestBody . Bytes ( )
recorder := httptest . NewRecorder ( )
2023-01-02 12:10:50 +00:00
ctx := suite . newContext ( recorder , http . MethodPatch , bodyBytes , accounts . UpdateCredentialsPath , w . FormDataContentType ( ) )
2022-08-06 11:09:21 +01:00
// call the handler
2023-01-02 12:10:50 +00:00
suite . accountsModule . AccountUpdateCredentialsPATCHHandler ( ctx )
2022-08-06 11:09:21 +01:00
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 )
2023-03-02 11:06:40 +00:00
suite . Equal ( ` { "error":"Bad Request: status content type 'peepeepoopoo' was not recognized, valid options are 'text/plain', 'text/markdown'"} ` , string ( b ) )
2022-08-06 11:09:21 +01:00
}
2021-05-08 13:25:55 +01:00
func TestAccountUpdateTestSuite ( t * testing . T ) {
suite . Run ( t , new ( AccountUpdateTestSuite ) )
}