// 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
this is a brand new status! #helloworld
", "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) } // 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": "this is a brand new status! #helloworld
", "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) } 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": "this is a brand new status! #helloworld
", "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) } 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 // message telling us how we screwed up. suite.Equal(`{ "error": "Bad Request: error converting followers_only.can_reply.always: policyURI public is not feasible for visibility followers_only" }`, out) } func (suite *StatusCreateTestSuite) TestPostNewScheduledStatus() { 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)}, "scheduled_at": {"2080-10-04T15:32:02.018Z"}, }, "") // We should have 501 from // our call to the function. suite.Equal(http.StatusNotImplemented, recorder.Code) // We should have a helpful error message. suite.Equal(`{ "error": "Not Implemented: scheduled_at is not yet implemented" }`, out) } 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": "This is a post written in markdown
", "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", "uri": "http://localhost:8080/some/determinate/url", "url": "http://localhost:8080/some/determinate/url", "visibility": "public" }`, out) } // 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()) } 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": "hello @brand_new_person
", "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) } 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": "#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)
here is a rainbow emoji a few times! :rainbow: :rainbow: :rainbow:
here's an emoji that isn't in the db: :test_emoji:
hello @1happyturtle this reply should work!
", "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) } // Take a media file which is currently not associated // with a status, and attach it to a new status. func (suite *StatusCreateTestSuite) TestAttachNewMediaSuccess() { attachment := suite.testAttachments["local_account_1_unattached_1"] out, recorder := suite.postStatus(map[string][]string{ "status": {"here's an image attachment"}, "media_ids[]": {attachment.ID}, }, "") // 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": "here's an image attachment
", "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) } // Post a new status with a language // tag that is not in canonical format. func (suite *StatusCreateTestSuite) TestPostNewStatusWithNoncanonicalLanguageTag() { out, recorder := suite.postStatus(map[string][]string{ "status": {"English? what's English? i speak American"}, "language": {"en-us"}, }, "") // 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": "English? what's English? i speak American
", "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) } func (suite *StatusCreateTestSuite) TestPostNewStatusWithPollForm() { 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": "this is a status with a poll!
", "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) } func (suite *StatusCreateTestSuite) TestPostNewStatusWithPollJSON() { 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": "this is a status with a poll!
", "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) } func TestStatusCreateTestSuite(t *testing.T) { suite.Run(t, new(StatusCreateTestSuite)) }