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-04-19 17:42:19 +00:00
2023-01-02 12:10:50 +00:00
package statuses_test
2021-04-19 17:42:19 +00:00
import (
2024-09-18 16:35:35 +00:00
"bytes"
2021-08-25 13:34:33 +00:00
"context"
2021-04-19 17:42:19 +00:00
"encoding/json"
"fmt"
2024-03-06 17:05:45 +00:00
"io"
2021-04-19 17:42:19 +00:00
"net/http"
"net/http/httptest"
2024-03-06 17:05:45 +00:00
"strings"
2021-04-19 17:42:19 +00:00
"testing"
"github.com/stretchr/testify/suite"
2023-01-02 12:10:50 +00:00
"github.com/superseriousbusiness/gotosocial/internal/api/client/statuses"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
2024-09-18 16:35:35 +00:00
"github.com/superseriousbusiness/gotosocial/internal/id"
2021-04-19 17:42:19 +00:00
"github.com/superseriousbusiness/gotosocial/internal/oauth"
"github.com/superseriousbusiness/gotosocial/testrig"
)
type StatusCreateTestSuite struct {
2021-05-08 12:25:55 +00:00
StatusStandardTestSuite
2021-04-19 17:42:19 +00:00
}
2022-08-06 10:09:21 +00:00
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\"/>"
)
2021-07-29 11:18:22 +00:00
2024-09-18 16:35:35 +00:00
func ( suite * StatusCreateTestSuite ) postStatus (
formData map [ string ] [ ] string ,
jsonData string ,
) ( string , * httptest . ResponseRecorder ) {
2021-04-19 17:42:19 +00:00
recorder := httptest . NewRecorder ( )
2022-07-12 07:32:20 +00:00
ctx , _ := testrig . CreateGinTestContext ( recorder , nil )
2021-04-19 17:42:19 +00:00
ctx . Set ( oauth . SessionAuthorizedApplication , suite . testApplications [ "application_1" ] )
2024-09-18 16:35:35 +00:00
ctx . Set ( oauth . SessionAuthorizedToken , oauth . DBTokenToToken ( suite . testTokens [ "local_account_1" ] ) )
2021-04-19 17:42:19 +00:00
ctx . Set ( oauth . SessionAuthorizedUser , suite . testUsers [ "local_account_1" ] )
ctx . Set ( oauth . SessionAuthorizedAccount , suite . testAccounts [ "local_account_1" ] )
2024-09-18 16:35:35 +00:00
if formData != nil {
buf , w , err := testrig . CreateMultipartFormData ( nil , formData )
if err != nil {
suite . FailNow ( err . Error ( ) )
}
ctx . Request = httptest . NewRequest (
http . MethodPost ,
"http://localhost:8080" + statuses . BasePath ,
bytes . NewReader ( buf . Bytes ( ) ) ,
)
ctx . Request . Header . Set ( "content-type" , w . FormDataContentType ( ) )
} else {
ctx . Request = httptest . NewRequest (
http . MethodPost ,
"http://localhost:8080" + statuses . BasePath ,
bytes . NewReader ( [ ] byte ( jsonData ) ) ,
)
ctx . Request . Header . Set ( "content-type" , "application/json" )
2021-04-19 17:42:19 +00:00
}
2024-09-18 16:35:35 +00:00
ctx . Request . Header . Set ( "accept" , "application/json" )
2021-04-19 17:42:19 +00:00
2024-09-18 16:35:35 +00:00
// Trigger handler.
suite . statusModule . StatusCreatePOSTHandler ( ctx )
2021-04-19 17:42:19 +00:00
result := recorder . Result ( )
defer result . Body . Close ( )
2022-03-29 09:54:56 +00:00
2024-09-18 16:35:35 +00:00
data , err := io . ReadAll ( result . Body )
2022-08-06 10:09:21 +00:00
if err != nil {
suite . FailNow ( err . Error ( ) )
}
2024-09-18 16:35:35 +00:00
rawMap := make ( map [ string ] any )
if err := json . Unmarshal ( data , & rawMap ) ; err != nil {
suite . FailNow ( err . Error ( ) )
2022-08-06 10:09:21 +00:00
}
2024-09-18 16:35:35 +00:00
// Replace any fields from the raw map that
// aren't determinate (date, id, url, etc).
if _ , ok := rawMap [ "id" ] ; ok {
rawMap [ "id" ] = id . Highest
}
2022-08-06 10:09:21 +00:00
2024-09-18 16:35:35 +00:00
if _ , ok := rawMap [ "uri" ] ; ok {
rawMap [ "uri" ] = "http://localhost:8080/some/determinate/url"
}
2022-08-06 10:09:21 +00:00
2024-09-18 16:35:35 +00:00
if _ , ok := rawMap [ "url" ] ; ok {
rawMap [ "url" ] = "http://localhost:8080/some/determinate/url"
}
2022-08-06 10:09:21 +00:00
2024-09-18 16:35:35 +00:00
if _ , ok := rawMap [ "created_at" ] ; ok {
rawMap [ "created_at" ] = "right the hell just now babyee"
}
2022-08-06 10:09:21 +00:00
2024-09-18 16:35:35 +00:00
// Make ID of any mentions determinate.
if menchiesRaw , ok := rawMap [ "mentions" ] ; ok {
menchies , ok := menchiesRaw . ( [ ] any )
if ! ok {
suite . FailNow ( "couldn't coerce menchies" )
}
2022-03-29 09:54:56 +00:00
2024-09-18 16:35:35 +00:00
for _ , menchieRaw := range menchies {
menchie , ok := menchieRaw . ( map [ string ] any )
if ! ok {
suite . FailNow ( "couldn't coerce menchie" )
}
2022-03-29 09:54:56 +00:00
2024-09-18 16:35:35 +00:00
if _ , ok := menchie [ "id" ] ; ok {
menchie [ "id" ] = id . Highest
}
}
2022-03-29 09:54:56 +00:00
}
2024-09-18 16:35:35 +00:00
// Make fields of any poll determinate.
if pollRaw , ok := rawMap [ "poll" ] ; ok && pollRaw != nil {
poll , ok := pollRaw . ( map [ string ] any )
if ! ok {
suite . FailNow ( "couldn't coerce poll" )
}
2022-03-29 09:54:56 +00:00
2024-09-18 16:35:35 +00:00
if _ , ok := poll [ "id" ] ; ok {
poll [ "id" ] = id . Highest
}
2022-03-29 09:54:56 +00:00
2024-09-18 16:35:35 +00:00
if _ , ok := poll [ "expires_at" ] ; ok {
poll [ "expires_at" ] = "ah like you know whatever dude it's chill"
}
}
2022-03-29 09:54:56 +00:00
2024-09-18 16:35:35 +00:00
// Replace account since that's not really
// what we care about for these tests.
if _ , ok := rawMap [ "account" ] ; ok {
rawMap [ "account" ] = "yeah this is my account, what about it punk"
}
2021-04-19 17:42:19 +00:00
2024-09-18 16:35:35 +00:00
// For readability, don't
// escape HTML, and indent json.
out := new ( bytes . Buffer )
enc := json . NewEncoder ( out )
enc . SetEscapeHTML ( false )
enc . SetIndent ( "" , " " )
2021-07-29 11:18:22 +00:00
2024-09-18 16:35:35 +00:00
if err := enc . Encode ( & rawMap ) ; err != nil {
suite . FailNow ( err . Error ( ) )
2021-07-29 11:18:22 +00:00
}
2024-09-18 16:35:35 +00:00
return strings . TrimSpace ( out . String ( ) ) , recorder
}
2021-07-29 11:18:22 +00:00
2024-09-18 16:35:35 +00:00
// Post a new status with some custom visibility settings
func ( suite * StatusCreateTestSuite ) TestPostNewStatus ( ) {
out , recorder := suite . postStatus ( map [ string ] [ ] string {
"status" : { "this is a brand new status! #helloworld" } ,
"spoiler_text" : { "hello hello" } ,
"sensitive" : { "true" } ,
"visibility" : { string ( apimodel . VisibilityMutualsOnly ) } ,
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>this is a brand new status! <a href=\"http://localhost:8080/tags/helloworld\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>helloworld</span></a></p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"author" ,
"followers" ,
"mentioned" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"author" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"author" ,
"followers" ,
"mentioned" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : true ,
"spoiler_text" : "hello hello" ,
"tags" : [
{
"name" : "helloworld" ,
"url" : "http://localhost:8080/tags/helloworld"
}
] ,
"text" : "this is a brand new status! #helloworld" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "private"
} ` , out )
}
2021-07-29 11:18:22 +00:00
2024-09-18 16:35:35 +00:00
// Post a new status with some custom visibility settings
func ( suite * StatusCreateTestSuite ) TestPostNewStatusIntPolicy ( ) {
out , recorder := suite . postStatus ( map [ string ] [ ] string {
"status" : { "this is a brand new status! #helloworld" } ,
"interaction_policy[can_reply][always][0]" : { "author" } ,
"interaction_policy[can_reply][always][1]" : { "followers" } ,
"interaction_policy[can_reply][always][2]" : { "following" } ,
"interaction_policy[can_reply][with_approval][0]" : { "public" } ,
"interaction_policy[can_announce][always][0]" : { "" } ,
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// Custom interaction policies
// should be set on the status.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>this is a brand new status! <a href=\"http://localhost:8080/tags/helloworld\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>helloworld</span></a></p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"author" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"author" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"author" ,
"followers" ,
"following" ,
"mentioned" ,
"me"
] ,
"with_approval" : [
"public"
]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [
{
"name" : "helloworld" ,
"url" : "http://localhost:8080/tags/helloworld"
}
] ,
"text" : "this is a brand new status! #helloworld" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
}
2021-07-29 11:18:22 +00:00
2024-09-18 16:35:35 +00:00
func ( suite * StatusCreateTestSuite ) TestPostNewStatusIntPolicyJSON ( ) {
out , recorder := suite . postStatus ( nil , ` {
"status" : "this is a brand new status! #helloworld" ,
"interaction_policy" : {
"can_reply" : {
"always" : [
"author" ,
"followers" ,
"following"
] ,
"with_approval" : [
"public"
]
} ,
"can_announce" : {
"always" : [ ]
}
}
} ` )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// Custom interaction policies
// should be set on the status.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>this is a brand new status! <a href=\"http://localhost:8080/tags/helloworld\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>helloworld</span></a></p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"author" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"author" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"author" ,
"followers" ,
"following" ,
"mentioned" ,
"me"
] ,
"with_approval" : [
"public"
]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [
{
"name" : "helloworld" ,
"url" : "http://localhost:8080/tags/helloworld"
}
] ,
"text" : "this is a brand new status! #helloworld" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
}
2021-07-29 11:18:22 +00:00
2024-09-18 16:35:35 +00:00
func ( suite * StatusCreateTestSuite ) TestPostNewStatusMessedUpIntPolicy ( ) {
out , recorder := suite . postStatus ( nil , ` {
"status" : "this is a brand new status! #helloworld" ,
"visibility" : "followers_only" ,
"interaction_policy" : {
"can_reply" : {
"always" : [
"public"
]
}
}
} ` )
// We should have 400 from
// our call to the function.
suite . Equal ( http . StatusBadRequest , recorder . Code )
// We should have a helpful error
2024-09-24 19:45:13 +00:00
// message telling us how we screwed up.
2024-09-18 16:35:35 +00:00
suite . Equal ( ` {
"error" : "Bad Request: error converting followers_only.can_reply.always: policyURI public is not feasible for visibility followers_only"
} ` , out )
2021-07-29 11:18:22 +00:00
}
2024-09-18 16:35:35 +00:00
func ( suite * StatusCreateTestSuite ) TestPostNewStatusMarkdown ( ) {
out , recorder := suite . postStatus ( map [ string ] [ ] string {
"status" : { statusMarkdown } ,
"visibility" : { string ( apimodel . VisibilityPublic ) } ,
"content_type" : { "text/markdown" } ,
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// The content field should have
// all the nicely parsed markdown stuff.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<h1>Title</h1><h2>Smaller title</h2><p>This is a post written in <a href=\"https://www.markdownguide.org/\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">markdown</a></p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [ ] ,
"text" : "# 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\"/>" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
}
2021-04-19 17:42:19 +00:00
2024-09-18 16:35:35 +00:00
// 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 when we mention it.
remoteAccount := suite . testAccounts [ "remote_account_1" ]
if err := suite . db . DeleteAccount (
context . Background ( ) ,
remoteAccount . ID ,
) ; err != nil {
suite . FailNow ( err . Error ( ) )
2021-04-19 17:42:19 +00:00
}
2024-09-18 16:35:35 +00:00
out , recorder := suite . postStatus ( map [ string ] [ ] string {
"status" : { "hello @brand_new_person@unknown-instance.com" } ,
"visibility" : { string ( apimodel . VisibilityPublic ) } ,
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// Status should have a mention of
// the now-freshly-looked-up account.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>hello <span class=\"h-card\"><a href=\"https://unknown-instance.com/@brand_new_person\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">@<span>brand_new_person</span></a></span></p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [
{
"acct" : "brand_new_person@unknown-instance.com" ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"url" : "https://unknown-instance.com/@brand_new_person" ,
"username" : "brand_new_person"
}
] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [ ] ,
"text" : "hello @brand_new_person@unknown-instance.com" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
}
2021-04-19 17:42:19 +00:00
2024-09-18 16:35:35 +00:00
func ( suite * StatusCreateTestSuite ) TestPostStatusWithLinksAndTags ( ) {
out , recorder := suite . postStatus ( map [ string ] [ ] string {
"status" : { statusWithLinksAndTags } ,
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// Status should have proper
// tags + formatted links.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p><a href=\"http://localhost:8080/tags/test\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>test</span></a> alright, should be able to post <a href=\"http://localhost:8080/tags/links\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>links</span></a> with fragments in them now, let's see........<br><br><a href=\"https://docs.gotosocial.org/en/latest/user_guide/posts/#links\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">https://docs.gotosocial.org/en/latest/user_guide/posts/#links</a><br><br><a href=\"http://localhost:8080/tags/gotosocial\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>gotosocial</span></a><br><br>(tobi remember to pull the docker image challenge)</p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [
{
"name" : "test" ,
"url" : "http://localhost:8080/tags/test"
} ,
{
"name" : "links" ,
"url" : "http://localhost:8080/tags/links"
} ,
{
"name" : "gotosocial" ,
"url" : "http://localhost:8080/tags/gotosocial"
}
] ,
"text" : "#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)" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
}
2021-04-19 17:42:19 +00:00
2024-09-18 16:35:35 +00:00
func ( suite * StatusCreateTestSuite ) TestPostNewStatusWithEmoji ( ) {
out , recorder := suite . postStatus ( map [ string ] [ ] string {
"status" : { "here is a rainbow emoji a few times! :rainbow: :rainbow: :rainbow: \n here's an emoji that isn't in the db: :test_emoji: " } ,
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// Emojis array should be
// populated on returned status.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>here is a rainbow emoji a few times! :rainbow: :rainbow: :rainbow:<br>here's an emoji that isn't in the db: :test_emoji:</p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [
{
"category" : "reactions" ,
"shortcode" : "rainbow" ,
"static_url" : "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png" ,
"url" : "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png" ,
"visible_in_picker" : true
}
] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [ ] ,
"text" : "here is a rainbow emoji a few times! :rainbow: :rainbow: :rainbow: \n here's an emoji that isn't in the db: :test_emoji: " ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
2021-04-19 17:42:19 +00:00
}
// Try to reply to a status that doesn't exist
func ( suite * StatusCreateTestSuite ) TestReplyToNonexistentStatus ( ) {
2024-09-18 16:35:35 +00:00
out , recorder := suite . postStatus ( map [ string ] [ ] string {
2021-04-19 17:42:19 +00:00
"status" : { "this is a reply to a status that doesn't exist" } ,
"spoiler_text" : { "don't open cuz it won't work" } ,
"in_reply_to_id" : { "3759e7ef-8ee1-4c0c-86f6-8b70b9ad3d50" } ,
2024-09-18 16:35:35 +00:00
} , "" )
// We should have 404 from
// our call to the function.
suite . Equal ( http . StatusNotFound , recorder . Code )
suite . Equal ( ` {
"error" : "Not Found: target status not found"
} ` , out )
2021-04-19 17:42:19 +00:00
}
2024-09-18 16:35:35 +00:00
// Post a reply to the status of
// a local user that allows replies.
2021-04-19 17:42:19 +00:00
func ( suite * StatusCreateTestSuite ) TestReplyToLocalStatus ( ) {
2024-09-18 16:35:35 +00:00
out , recorder := suite . postStatus ( map [ string ] [ ] string {
2021-04-19 17:42:19 +00:00
"status" : { fmt . Sprintf ( "hello @%s this reply should work!" , testrig . NewTestAccounts ( ) [ "local_account_2" ] . Username ) } ,
"in_reply_to_id" : { testrig . NewTestStatuses ( ) [ "local_account_2_status_1" ] . ID } ,
2024-09-18 16:35:35 +00:00
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// in_reply_to_x
// fields should be set.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>hello <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> this reply should work!</p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : "01F8MH5NBDF2MV7CTC4Q5128HF" ,
"in_reply_to_id" : "01F8MHBQCBTDKN6X5VHGMMN4MA" ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [
{
"acct" : "1happyturtle" ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"url" : "http://localhost:8080/@1happyturtle" ,
"username" : "1happyturtle"
}
] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [ ] ,
"text" : "hello @1happyturtle this reply should work!" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
2021-04-19 17:42:19 +00:00
}
2024-09-18 16:35:35 +00:00
// Take a media file which is currently not associated
// with a status, and attach it to a new status.
2021-04-19 17:42:19 +00:00
func ( suite * StatusCreateTestSuite ) TestAttachNewMediaSuccess ( ) {
2021-07-29 11:18:22 +00:00
attachment := suite . testAttachments [ "local_account_1_unattached_1" ]
2024-09-18 16:35:35 +00:00
out , recorder := suite . postStatus ( map [ string ] [ ] string {
2022-07-28 14:43:27 +00:00
"status" : { "here's an image attachment" } ,
2022-07-22 11:43:51 +00:00
"media_ids[]" : { attachment . ID } ,
2024-09-18 16:35:35 +00:00
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// Status should have
// media attached.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>here's an image attachment</p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en" ,
"media_attachments" : [
{
"blurhash" : "LNABP8o#Dge,S6M}axxVEQjYxWbH" ,
"description" : "the oh you meme" ,
"id" : "01F8MH8RMYQ6MSNY3JM2XT1CQ5" ,
"meta" : {
"focus" : {
"x" : 0 ,
"y" : 0
} ,
"original" : {
"aspect" : 1.7777778 ,
"height" : 450 ,
"size" : "800x450" ,
"width" : 800
} ,
"small" : {
"aspect" : 1.7777778 ,
"height" : 288 ,
"size" : "512x288" ,
"width" : 512
}
} ,
"preview_remote_url" : null ,
"preview_url" : "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH8RMYQ6MSNY3JM2XT1CQ5.webp" ,
"remote_url" : null ,
"text_url" : "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg" ,
"type" : "image" ,
"url" : "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/original/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpg"
}
] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [ ] ,
"text" : "here's an image attachment" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
2021-04-19 17:42:19 +00:00
}
2024-09-18 16:35:35 +00:00
// Post a new status with a language
// tag that is not in canonical format.
2023-08-07 08:25:54 +00:00
func ( suite * StatusCreateTestSuite ) TestPostNewStatusWithNoncanonicalLanguageTag ( ) {
2024-09-18 16:35:35 +00:00
out , recorder := suite . postStatus ( map [ string ] [ ] string {
2023-08-07 08:25:54 +00:00
"status" : { "English? what's English? i speak American" } ,
"language" : { "en-us" } ,
2024-09-18 16:35:35 +00:00
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// The returned language tag should
// use its canonicalized version rather
// than the format we submitted.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>English? what's English? i speak American</p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en-US" ,
"media_attachments" : [ ] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : null ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [ ] ,
"text" : "English? what's English? i speak American" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
2024-03-06 17:05:45 +00:00
}
func ( suite * StatusCreateTestSuite ) TestPostNewStatusWithPollForm ( ) {
2024-09-18 16:35:35 +00:00
out , recorder := suite . postStatus ( map [ string ] [ ] string {
"status" : { "this is a status with a poll!" } ,
"visibility" : { "public" } ,
"poll[options][]" : { "first option" , "second option" } ,
"poll[expires_in]" : { "3600" } ,
"poll[multiple]" : { "true" } ,
} , "" )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// Status poll should
// be as expected.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>this is a status with a poll!</p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : {
"emojis" : [ ] ,
"expired" : false ,
"expires_at" : "ah like you know whatever dude it's chill" ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"multiple" : true ,
"options" : [
{
"title" : "first option" ,
"votes_count" : 0
} ,
{
"title" : "second option" ,
"votes_count" : 0
}
] ,
"own_votes" : [ ] ,
"voted" : true ,
"voters_count" : 0 ,
"votes_count" : 0
} ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [ ] ,
"text" : "this is a status with a poll!" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
2024-03-06 17:05:45 +00:00
}
func ( suite * StatusCreateTestSuite ) TestPostNewStatusWithPollJSON ( ) {
2024-09-18 16:35:35 +00:00
out , recorder := suite . postStatus ( nil , ` {
"status" : "this is a status with a poll!" ,
"visibility" : "public" ,
"poll" : {
"options" : [ "first option" , "second option" ] ,
"expires_in" : 3600 ,
"multiple" : true
}
} ` )
// We should have OK from
// our call to the function.
suite . Equal ( http . StatusOK , recorder . Code )
// Status poll should
// be as expected.
suite . Equal ( ` {
"account" : "yeah this is my account, what about it punk" ,
"application" : {
"name" : "really cool gts application" ,
"website" : "https://reallycool.app"
} ,
"bookmarked" : false ,
"card" : null ,
"content" : "<p>this is a status with a poll!</p>" ,
"created_at" : "right the hell just now babyee" ,
"emojis" : [ ] ,
"favourited" : false ,
"favourites_count" : 0 ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"in_reply_to_account_id" : null ,
"in_reply_to_id" : null ,
"interaction_policy" : {
"can_favourite" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reblog" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
} ,
"can_reply" : {
"always" : [
"public" ,
"me"
] ,
"with_approval" : [ ]
}
} ,
"language" : "en" ,
"media_attachments" : [ ] ,
"mentions" : [ ] ,
"muted" : false ,
"pinned" : false ,
"poll" : {
"emojis" : [ ] ,
"expired" : false ,
"expires_at" : "ah like you know whatever dude it's chill" ,
"id" : "ZZZZZZZZZZZZZZZZZZZZZZZZZZ" ,
"multiple" : true ,
"options" : [
{
"title" : "first option" ,
"votes_count" : 0
} ,
{
"title" : "second option" ,
"votes_count" : 0
}
] ,
"own_votes" : [ ] ,
"voted" : true ,
"voters_count" : 0 ,
"votes_count" : 0
} ,
"reblog" : null ,
"reblogged" : false ,
"reblogs_count" : 0 ,
"replies_count" : 0 ,
"sensitive" : false ,
"spoiler_text" : "" ,
"tags" : [ ] ,
"text" : "this is a status with a poll!" ,
"uri" : "http://localhost:8080/some/determinate/url" ,
"url" : "http://localhost:8080/some/determinate/url" ,
"visibility" : "public"
} ` , out )
2024-03-06 17:05:45 +00:00
}
2021-04-19 17:42:19 +00:00
func TestStatusCreateTestSuite ( t * testing . T ) {
suite . Run ( t , new ( StatusCreateTestSuite ) )
}