update_test.go (10154B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package account_test 19 20 import ( 21 "context" 22 "testing" 23 24 "github.com/stretchr/testify/suite" 25 "github.com/superseriousbusiness/gotosocial/internal/ap" 26 apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" 27 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 28 ) 29 30 type AccountUpdateTestSuite struct { 31 AccountStandardTestSuite 32 } 33 34 func (suite *AccountStandardTestSuite) checkClientAPIChan(accountID string) { 35 msg := <-suite.fromClientAPIChan 36 37 // Profile update. 38 suite.Equal(ap.ActivityUpdate, msg.APActivityType) 39 suite.Equal(ap.ObjectProfile, msg.APObjectType) 40 41 // Correct account updated. 42 if msg.OriginAccount == nil { 43 suite.FailNow("expected msg.OriginAccount not to be nil") 44 } 45 suite.Equal(accountID, msg.OriginAccount.ID) 46 } 47 48 func (suite *AccountUpdateTestSuite) TestAccountUpdateSimple() { 49 testAccount := >smodel.Account{} 50 *testAccount = *suite.testAccounts["local_account_1"] 51 52 var ( 53 ctx = context.Background() 54 locked = true 55 displayName = "new display name" 56 note = "#hello here i am!" 57 noteExpected = `<p><a href="http://localhost:8080/tags/hello" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>hello</span></a> here i am!</p>` 58 ) 59 60 // Call update function. 61 apiAccount, errWithCode := suite.accountProcessor.Update(ctx, testAccount, &apimodel.UpdateCredentialsRequest{ 62 DisplayName: &displayName, 63 Locked: &locked, 64 Note: ¬e, 65 }) 66 if errWithCode != nil { 67 suite.FailNow(errWithCode.Error()) 68 } 69 70 // Returned profile should be updated. 71 suite.True(apiAccount.Locked) 72 suite.Equal(displayName, apiAccount.DisplayName) 73 suite.Equal(noteExpected, apiAccount.Note) 74 75 // We should have an update in the client api channel. 76 suite.checkClientAPIChan(testAccount.ID) 77 78 // Check database model of account as well. 79 dbAccount, err := suite.db.GetAccountByID(ctx, testAccount.ID) 80 if err != nil { 81 suite.FailNow(err.Error()) 82 } 83 suite.True(*dbAccount.Locked) 84 suite.Equal(displayName, dbAccount.DisplayName) 85 suite.Equal(noteExpected, dbAccount.Note) 86 } 87 88 func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMention() { 89 testAccount := >smodel.Account{} 90 *testAccount = *suite.testAccounts["local_account_1"] 91 92 var ( 93 ctx = context.Background() 94 locked = true 95 displayName = "new display name" 96 note = "#hello here i am!\n\ngo check out @1happyturtle, they have a cool account!" 97 noteExpected = "<p><a href=\"http://localhost:8080/tags/hello\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>hello</span></a> here i am!<br><br>go check out <span class=\"h-card\"><a href=\"http://localhost:8080/@1happyturtle\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">@<span>1happyturtle</span></a></span>, they have a cool account!</p>" 98 ) 99 100 // Call update function. 101 apiAccount, errWithCode := suite.accountProcessor.Update(ctx, testAccount, &apimodel.UpdateCredentialsRequest{ 102 DisplayName: &displayName, 103 Locked: &locked, 104 Note: ¬e, 105 }) 106 if errWithCode != nil { 107 suite.FailNow(errWithCode.Error()) 108 } 109 110 // Returned profile should be updated. 111 suite.True(apiAccount.Locked) 112 suite.Equal(displayName, apiAccount.DisplayName) 113 suite.Equal(noteExpected, apiAccount.Note) 114 115 // We should have an update in the client api channel. 116 suite.checkClientAPIChan(testAccount.ID) 117 118 // Check database model of account as well. 119 dbAccount, err := suite.db.GetAccountByID(ctx, testAccount.ID) 120 if err != nil { 121 suite.FailNow(err.Error()) 122 } 123 suite.True(*dbAccount.Locked) 124 suite.Equal(displayName, dbAccount.DisplayName) 125 suite.Equal(noteExpected, dbAccount.Note) 126 } 127 128 func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMarkdownNote() { 129 testAccount := >smodel.Account{} 130 *testAccount = *suite.testAccounts["local_account_1"] 131 132 var ( 133 ctx = context.Background() 134 note = "*hello* ~~here~~ i am!" 135 noteExpected = `<p><em>hello</em> <del>here</del> i am!</p>` 136 ) 137 138 // Set status content type of account 1 to markdown for this test. 139 testAccount.StatusContentType = "text/markdown" 140 if err := suite.db.UpdateAccount(ctx, testAccount, "status_content_type"); err != nil { 141 suite.FailNow(err.Error()) 142 } 143 144 // Call update function. 145 apiAccount, errWithCode := suite.accountProcessor.Update(ctx, testAccount, &apimodel.UpdateCredentialsRequest{ 146 Note: ¬e, 147 }) 148 if errWithCode != nil { 149 suite.FailNow(errWithCode.Error()) 150 } 151 152 // Returned profile should be updated. 153 suite.Equal(noteExpected, apiAccount.Note) 154 155 // We should have an update in the client api channel. 156 suite.checkClientAPIChan(testAccount.ID) 157 158 // Check database model of account as well. 159 dbAccount, err := suite.db.GetAccountByID(ctx, testAccount.ID) 160 if err != nil { 161 suite.FailNow(err.Error()) 162 } 163 suite.NoError(err) 164 suite.Equal(noteExpected, dbAccount.Note) 165 } 166 167 func (suite *AccountUpdateTestSuite) TestAccountUpdateWithFields() { 168 testAccount := >smodel.Account{} 169 *testAccount = *suite.testAccounts["local_account_1"] 170 171 var ( 172 ctx = context.Background() 173 updateFields = []apimodel.UpdateField{ 174 { 175 Name: func() *string { s := "favourite emoji"; return &s }(), 176 Value: func() *string { s := ":rainbow:"; return &s }(), 177 }, 178 { 179 Name: func() *string { s := "my website"; return &s }(), 180 Value: func() *string { s := "https://example.org"; return &s }(), 181 }, 182 } 183 fieldsExpectedRaw = []apimodel.Field{ 184 { 185 Name: "favourite emoji", 186 Value: ":rainbow:", 187 VerifiedAt: (*string)(nil), 188 }, 189 { 190 Name: "my website", 191 Value: "https://example.org", 192 VerifiedAt: (*string)(nil), 193 }, 194 } 195 fieldsExpectedParsed = []apimodel.Field{ 196 { 197 Name: "favourite emoji", 198 Value: ":rainbow:", 199 VerifiedAt: (*string)(nil), 200 }, 201 { 202 Name: "my website", 203 Value: "<a href=\"https://example.org\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">https://example.org</a>", 204 VerifiedAt: (*string)(nil), 205 }, 206 } 207 emojisExpected = []apimodel.Emoji{ 208 { 209 Shortcode: "rainbow", 210 URL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", 211 StaticURL: "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png", 212 VisibleInPicker: true, 213 Category: "reactions", 214 }, 215 } 216 ) 217 218 apiAccount, errWithCode := suite.accountProcessor.Update(ctx, testAccount, &apimodel.UpdateCredentialsRequest{ 219 FieldsAttributes: &updateFields, 220 }) 221 if errWithCode != nil { 222 suite.FailNow(errWithCode.Error()) 223 } 224 225 // Returned profile should be updated. 226 suite.EqualValues(fieldsExpectedRaw, apiAccount.Source.Fields) 227 suite.EqualValues(fieldsExpectedParsed, apiAccount.Fields) 228 suite.EqualValues(emojisExpected, apiAccount.Emojis) 229 230 // We should have an update in the client api channel. 231 suite.checkClientAPIChan(testAccount.ID) 232 233 // Check database model of account as well. 234 dbAccount, err := suite.db.GetAccountByID(ctx, testAccount.ID) 235 if err != nil { 236 suite.FailNow(err.Error()) 237 } 238 suite.Equal(fieldsExpectedParsed[0].Name, dbAccount.Fields[0].Name) 239 suite.Equal(fieldsExpectedParsed[0].Value, dbAccount.Fields[0].Value) 240 suite.Equal(fieldsExpectedParsed[1].Name, dbAccount.Fields[1].Name) 241 suite.Equal(fieldsExpectedParsed[1].Value, dbAccount.Fields[1].Value) 242 suite.Equal(fieldsExpectedRaw[0].Name, dbAccount.FieldsRaw[0].Name) 243 suite.Equal(fieldsExpectedRaw[0].Value, dbAccount.FieldsRaw[0].Value) 244 suite.Equal(fieldsExpectedRaw[1].Name, dbAccount.FieldsRaw[1].Name) 245 suite.Equal(fieldsExpectedRaw[1].Value, dbAccount.FieldsRaw[1].Value) 246 } 247 248 func (suite *AccountUpdateTestSuite) TestAccountUpdateNoteNotFields() { 249 // local_account_2 already has some fields set. 250 // We want to ensure that the fields don't change 251 // even if the account note is updated. 252 testAccount := >smodel.Account{} 253 *testAccount = *suite.testAccounts["local_account_2"] 254 255 var ( 256 ctx = context.Background() 257 fieldsRawBefore = len(testAccount.FieldsRaw) 258 fieldsBefore = len(testAccount.Fields) 259 note = "#hello here i am!" 260 noteExpected = `<p><a href="http://localhost:8080/tags/hello" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>hello</span></a> here i am!</p>` 261 ) 262 263 // Call update function. 264 apiAccount, errWithCode := suite.accountProcessor.Update(ctx, testAccount, &apimodel.UpdateCredentialsRequest{ 265 Note: ¬e, 266 }) 267 if errWithCode != nil { 268 suite.FailNow(errWithCode.Error()) 269 } 270 271 // Returned profile should be updated. 272 suite.True(apiAccount.Locked) 273 suite.Equal(noteExpected, apiAccount.Note) 274 suite.Equal(fieldsRawBefore, len(apiAccount.Source.Fields)) 275 suite.Equal(fieldsBefore, len(apiAccount.Fields)) 276 277 // We should have an update in the client api channel. 278 suite.checkClientAPIChan(testAccount.ID) 279 280 // Check database model of account as well. 281 dbAccount, err := suite.db.GetAccountByID(ctx, testAccount.ID) 282 if err != nil { 283 suite.FailNow(err.Error()) 284 } 285 suite.True(*dbAccount.Locked) 286 suite.Equal(noteExpected, dbAccount.Note) 287 suite.Equal(fieldsRawBefore, len(dbAccount.FieldsRaw)) 288 suite.Equal(fieldsBefore, len(dbAccount.Fields)) 289 } 290 291 func TestAccountUpdateTestSuite(t *testing.T) { 292 suite.Run(t, new(AccountUpdateTestSuite)) 293 }