summaryrefslogtreecommitdiff
path: root/internal/typeutils
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2023-02-02 14:08:13 +0100
committerLibravatar GitHub <noreply@github.com>2023-02-02 14:08:13 +0100
commit382512a5a6cc3f13576bbde8d607098d019f4063 (patch)
treedc2ccd1d30cd65b3f3d576a8d2a6910bbecc593a /internal/typeutils
parent[chore/performance] use only 1 sqlite db connection regardless of multiplier ... (diff)
downloadgotosocial-382512a5a6cc3f13576bbde8d607098d019f4063.tar.xz
[feature] Implement `/api/v2/instance` endpoint (#1409)
* interim: start adding /api/v2/instance * finish up
Diffstat (limited to 'internal/typeutils')
-rw-r--r--internal/typeutils/converter.go6
-rw-r--r--internal/typeutils/internaltofrontend.go247
-rw-r--r--internal/typeutils/internaltofrontend_test.go257
3 files changed, 352 insertions, 158 deletions
diff --git a/internal/typeutils/converter.go b/internal/typeutils/converter.go
index ec7b09f27..0f741ddb1 100644
--- a/internal/typeutils/converter.go
+++ b/internal/typeutils/converter.go
@@ -79,8 +79,10 @@ type TypeConverter interface {
StatusToAPIStatus(ctx context.Context, s *gtsmodel.Status, requestingAccount *gtsmodel.Account) (*apimodel.Status, error)
// VisToAPIVis converts a gts visibility into its api equivalent
VisToAPIVis(ctx context.Context, m gtsmodel.Visibility) apimodel.Visibility
- // InstanceToAPIInstance converts a gts instance into its api equivalent for serving at /api/v1/instance
- InstanceToAPIInstance(ctx context.Context, i *gtsmodel.Instance) (*apimodel.Instance, error)
+ // InstanceToAPIV1Instance converts a gts instance into its api equivalent for serving at /api/v1/instance
+ InstanceToAPIV1Instance(ctx context.Context, i *gtsmodel.Instance) (*apimodel.InstanceV1, error)
+ // InstanceToAPIV2Instance converts a gts instance into its api equivalent for serving at /api/v2/instance
+ InstanceToAPIV2Instance(ctx context.Context, i *gtsmodel.Instance) (*apimodel.InstanceV2, error)
// RelationshipToAPIRelationship converts a gts relationship into its api equivalent for serving in various places
RelationshipToAPIRelationship(ctx context.Context, r *gtsmodel.Relationship) (*apimodel.Relationship, error)
// NotificationToAPINotification converts a gts notification into a api notification
diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go
index 2483fc5ba..799ccb0c4 100644
--- a/internal/typeutils/internaltofrontend.go
+++ b/internal/typeutils/internaltofrontend.go
@@ -20,7 +20,6 @@ package typeutils
import (
"context"
- "errors"
"fmt"
"math"
"strconv"
@@ -43,6 +42,8 @@ const (
instanceMediaAttachmentsVideoFrameRateLimit = 60
instancePollsMinExpiration = 300 // seconds
instancePollsMaxExpiration = 2629746 // seconds
+ instanceAccountsMaxFeaturedTags = 10
+ instanceSourceURL = "https://github.com/superseriousbusiness/gotosocial"
)
func (c *converter) AccountToAPIAccountSensitive(ctx context.Context, a *gtsmodel.Account) (*apimodel.Account, error) {
@@ -675,113 +676,189 @@ func (c *converter) VisToAPIVis(ctx context.Context, m gtsmodel.Visibility) apim
return ""
}
-func (c *converter) InstanceToAPIInstance(ctx context.Context, i *gtsmodel.Instance) (*apimodel.Instance, error) {
- mi := &apimodel.Instance{
+func (c *converter) InstanceToAPIV1Instance(ctx context.Context, i *gtsmodel.Instance) (*apimodel.InstanceV1, error) {
+ instance := &apimodel.InstanceV1{
URI: i.URI,
+ AccountDomain: config.GetAccountDomain(),
Title: i.Title,
Description: i.Description,
ShortDescription: i.ShortDescription,
Email: i.ContactEmail,
- Version: i.Version,
- Stats: make(map[string]int),
- }
-
- // if the requested instance is *this* instance, we can add some extra information
- if host := config.GetHost(); i.Domain == host {
- mi.AccountDomain = config.GetAccountDomain()
-
- if ia, err := c.db.GetInstanceAccount(ctx, ""); err == nil {
- // assume default logo
- mi.Thumbnail = config.GetProtocol() + "://" + host + "/assets/logo.png"
-
- // take instance account avatar as instance thumbnail if we can
- if ia.AvatarMediaAttachmentID != "" {
- if ia.AvatarMediaAttachment == nil {
- avi, err := c.db.GetAttachmentByID(ctx, ia.AvatarMediaAttachmentID)
- if err == nil {
- ia.AvatarMediaAttachment = avi
- } else if !errors.Is(err, db.ErrNoEntries) {
- log.Errorf("InstanceToAPIInstance: error getting instance avatar attachment with id %s: %s", ia.AvatarMediaAttachmentID, err)
- }
- }
-
- if ia.AvatarMediaAttachment != nil {
- mi.Thumbnail = ia.AvatarMediaAttachment.URL
- mi.ThumbnailType = ia.AvatarMediaAttachment.File.ContentType
- mi.ThumbnailDescription = ia.AvatarMediaAttachment.Description
- }
+ Version: config.GetSoftwareVersion(),
+ Languages: []string{}, // todo: not supported yet
+ Registrations: config.GetAccountsRegistrationOpen(),
+ ApprovalRequired: config.GetAccountsApprovalRequired(),
+ InvitesEnabled: false, // todo: not supported yet
+ MaxTootChars: uint(config.GetStatusesMaxChars()),
+ }
+
+ // configuration
+ instance.Configuration.Statuses.MaxCharacters = config.GetStatusesMaxChars()
+ instance.Configuration.Statuses.MaxMediaAttachments = config.GetStatusesMediaMaxFiles()
+ instance.Configuration.Statuses.CharactersReservedPerURL = instanceStatusesCharactersReservedPerURL
+ instance.Configuration.MediaAttachments.SupportedMimeTypes = media.SupportedMIMETypes
+ instance.Configuration.MediaAttachments.ImageSizeLimit = int(config.GetMediaImageMaxSize())
+ instance.Configuration.MediaAttachments.ImageMatrixLimit = instanceMediaAttachmentsImageMatrixLimit
+ instance.Configuration.MediaAttachments.VideoSizeLimit = int(config.GetMediaVideoMaxSize())
+ instance.Configuration.MediaAttachments.VideoFrameRateLimit = instanceMediaAttachmentsVideoFrameRateLimit
+ instance.Configuration.MediaAttachments.VideoMatrixLimit = instanceMediaAttachmentsVideoMatrixLimit
+ instance.Configuration.Polls.MaxOptions = config.GetStatusesPollMaxOptions()
+ instance.Configuration.Polls.MaxCharactersPerOption = config.GetStatusesPollOptionMaxChars()
+ instance.Configuration.Polls.MinExpiration = instancePollsMinExpiration
+ instance.Configuration.Polls.MaxExpiration = instancePollsMaxExpiration
+ instance.Configuration.Accounts.AllowCustomCSS = config.GetAccountsAllowCustomCSS()
+ instance.Configuration.Accounts.MaxFeaturedTags = instanceAccountsMaxFeaturedTags
+ instance.Configuration.Emojis.EmojiSizeLimit = int(config.GetMediaEmojiLocalMaxSize())
+
+ // URLs
+ instance.URLs.StreamingAPI = "wss://" + i.Domain
+
+ // statistics
+ stats := make(map[string]int, 3)
+ userCount, err := c.db.CountInstanceUsers(ctx, i.Domain)
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV1Instance: db error getting counting instance users: %w", err)
+ }
+ stats["user_count"] = userCount
+
+ statusCount, err := c.db.CountInstanceStatuses(ctx, i.Domain)
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV1Instance: db error getting counting instance statuses: %w", err)
+ }
+ stats["status_count"] = statusCount
+
+ domainCount, err := c.db.CountInstanceDomains(ctx, i.Domain)
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV1Instance: db error getting counting instance domains: %w", err)
+ }
+ stats["domain_count"] = domainCount
+ instance.Stats = stats
+
+ // thumbnail
+ iAccount, err := c.db.GetInstanceAccount(ctx, "")
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV1Instance: db error getting instance account: %w", err)
+ }
+
+ if iAccount.AvatarMediaAttachmentID != "" {
+ if iAccount.AvatarMediaAttachment == nil {
+ avi, err := c.db.GetAttachmentByID(ctx, iAccount.AvatarMediaAttachmentID)
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIInstance: error getting instance avatar attachment with id %s: %w", iAccount.AvatarMediaAttachmentID, err)
}
+ iAccount.AvatarMediaAttachment = avi
}
- userCount, err := c.db.CountInstanceUsers(ctx, host)
- if err == nil {
- mi.Stats["user_count"] = userCount
- }
+ instance.Thumbnail = iAccount.AvatarMediaAttachment.URL
+ instance.ThumbnailType = iAccount.AvatarMediaAttachment.File.ContentType
+ instance.ThumbnailDescription = iAccount.AvatarMediaAttachment.Description
+ } else {
+ instance.Thumbnail = config.GetProtocol() + "://" + i.Domain + "/assets/logo.png" // default thumb
+ }
- statusCount, err := c.db.CountInstanceStatuses(ctx, host)
- if err == nil {
- mi.Stats["status_count"] = statusCount
+ // contact account
+ if i.ContactAccountID != "" {
+ if i.ContactAccount == nil {
+ contactAccount, err := c.db.GetAccountByID(ctx, i.ContactAccountID)
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV1Instance: db error getting instance contact account %s: %w", i.ContactAccountID, err)
+ }
+ i.ContactAccount = contactAccount
}
- domainCount, err := c.db.CountInstanceDomains(ctx, host)
- if err == nil {
- mi.Stats["domain_count"] = domainCount
+ account, err := c.AccountToAPIAccountPublic(ctx, i.ContactAccount)
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV1Instance: error converting instance contact account %s: %w", i.ContactAccountID, err)
}
+ instance.ContactAccount = account
+ }
- mi.Registrations = config.GetAccountsRegistrationOpen()
- mi.ApprovalRequired = config.GetAccountsApprovalRequired()
- mi.InvitesEnabled = false // TODO
- mi.MaxTootChars = uint(config.GetStatusesMaxChars())
- mi.URLS = &apimodel.InstanceURLs{
- StreamingAPI: "wss://" + host,
- }
- mi.Version = config.GetSoftwareVersion()
-
- // todo: remove hardcoded values and put them in config somewhere
- mi.Configuration = &apimodel.InstanceConfiguration{
- Statuses: &apimodel.InstanceConfigurationStatuses{
- MaxCharacters: config.GetStatusesMaxChars(),
- MaxMediaAttachments: config.GetStatusesMediaMaxFiles(),
- CharactersReservedPerURL: instanceStatusesCharactersReservedPerURL,
- },
- MediaAttachments: &apimodel.InstanceConfigurationMediaAttachments{
- SupportedMimeTypes: media.SupportedMIMETypes,
- ImageSizeLimit: int(config.GetMediaImageMaxSize()), // bytes
- ImageMatrixLimit: instanceMediaAttachmentsImageMatrixLimit, // height*width
- VideoSizeLimit: int(config.GetMediaVideoMaxSize()), // bytes
- VideoFrameRateLimit: instanceMediaAttachmentsVideoFrameRateLimit,
- VideoMatrixLimit: instanceMediaAttachmentsVideoMatrixLimit, // height*width
- },
- Polls: &apimodel.InstanceConfigurationPolls{
- MaxOptions: config.GetStatusesPollMaxOptions(),
- MaxCharactersPerOption: config.GetStatusesPollOptionMaxChars(),
- MinExpiration: instancePollsMinExpiration, // seconds
- MaxExpiration: instancePollsMaxExpiration, // seconds
- },
- Accounts: &apimodel.InstanceConfigurationAccounts{
- AllowCustomCSS: config.GetAccountsAllowCustomCSS(),
- },
- Emojis: &apimodel.InstanceConfigurationEmojis{
- EmojiSizeLimit: int(config.GetMediaEmojiLocalMaxSize()), // bytes
- },
- }
+ return instance, nil
+}
+
+func (c *converter) InstanceToAPIV2Instance(ctx context.Context, i *gtsmodel.Instance) (*apimodel.InstanceV2, error) {
+ instance := &apimodel.InstanceV2{
+ Domain: i.Domain,
+ AccountDomain: config.GetAccountDomain(),
+ Title: i.Title,
+ Version: config.GetSoftwareVersion(),
+ SourceURL: instanceSourceURL,
+ Description: i.Description,
+ Usage: apimodel.InstanceV2Usage{}, // todo: not implemented
+ Languages: []string{}, // todo: not implemented
+ Rules: []interface{}{}, // todo: not implemented
+ }
+
+ // thumbnail
+ thumbnail := apimodel.InstanceV2Thumbnail{}
+
+ iAccount, err := c.db.GetInstanceAccount(ctx, "")
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV2Instance: db error getting instance account: %w", err)
}
- // contact account is optional but let's try to get it
+ if iAccount.AvatarMediaAttachmentID != "" {
+ if iAccount.AvatarMediaAttachment == nil {
+ avi, err := c.db.GetAttachmentByID(ctx, iAccount.AvatarMediaAttachmentID)
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV2Instance: error getting instance avatar attachment with id %s: %w", iAccount.AvatarMediaAttachmentID, err)
+ }
+ iAccount.AvatarMediaAttachment = avi
+ }
+
+ thumbnail.URL = iAccount.AvatarMediaAttachment.URL
+ thumbnail.Type = iAccount.AvatarMediaAttachment.File.ContentType
+ thumbnail.Description = iAccount.AvatarMediaAttachment.Description
+ thumbnail.Blurhash = iAccount.AvatarMediaAttachment.Blurhash
+ } else {
+ thumbnail.URL = config.GetProtocol() + "://" + i.Domain + "/assets/logo.png" // default thumb
+ }
+
+ instance.Thumbnail = thumbnail
+
+ // configuration
+ instance.Configuration.URLs.Streaming = "wss://" + i.Domain
+ instance.Configuration.Statuses.MaxCharacters = config.GetStatusesMaxChars()
+ instance.Configuration.Statuses.MaxMediaAttachments = config.GetStatusesMediaMaxFiles()
+ instance.Configuration.Statuses.CharactersReservedPerURL = instanceStatusesCharactersReservedPerURL
+ instance.Configuration.MediaAttachments.SupportedMimeTypes = media.SupportedMIMETypes
+ instance.Configuration.MediaAttachments.ImageSizeLimit = int(config.GetMediaImageMaxSize())
+ instance.Configuration.MediaAttachments.ImageMatrixLimit = instanceMediaAttachmentsImageMatrixLimit
+ instance.Configuration.MediaAttachments.VideoSizeLimit = int(config.GetMediaVideoMaxSize())
+ instance.Configuration.MediaAttachments.VideoFrameRateLimit = instanceMediaAttachmentsVideoFrameRateLimit
+ instance.Configuration.MediaAttachments.VideoMatrixLimit = instanceMediaAttachmentsVideoMatrixLimit
+ instance.Configuration.Polls.MaxOptions = config.GetStatusesPollMaxOptions()
+ instance.Configuration.Polls.MaxCharactersPerOption = config.GetStatusesPollOptionMaxChars()
+ instance.Configuration.Polls.MinExpiration = instancePollsMinExpiration
+ instance.Configuration.Polls.MaxExpiration = instancePollsMaxExpiration
+ instance.Configuration.Accounts.AllowCustomCSS = config.GetAccountsAllowCustomCSS()
+ instance.Configuration.Accounts.MaxFeaturedTags = instanceAccountsMaxFeaturedTags
+ instance.Configuration.Emojis.EmojiSizeLimit = int(config.GetMediaEmojiLocalMaxSize())
+
+ // registrations
+ instance.Registrations.Enabled = config.GetAccountsRegistrationOpen()
+ instance.Registrations.ApprovalRequired = config.GetAccountsApprovalRequired()
+ instance.Registrations.Message = nil // todo: not implemented
+
+ // contact
+ instance.Contact.Email = i.ContactEmail
if i.ContactAccountID != "" {
if i.ContactAccount == nil {
contactAccount, err := c.db.GetAccountByID(ctx, i.ContactAccountID)
- if err == nil {
- i.ContactAccount = contactAccount
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV2Instance: db error getting instance contact account %s: %w", i.ContactAccountID, err)
}
+ i.ContactAccount = contactAccount
}
- ma, err := c.AccountToAPIAccountPublic(ctx, i.ContactAccount)
- if err == nil {
- mi.ContactAccount = ma
+
+ account, err := c.AccountToAPIAccountPublic(ctx, i.ContactAccount)
+ if err != nil {
+ return nil, fmt.Errorf("InstanceToAPIV2Instance: error converting instance contact account %s: %w", i.ContactAccountID, err)
}
+ instance.Contact.Account = account
}
- return mi, nil
+ return instance, nil
}
func (c *converter) RelationshipToAPIRelationship(ctx context.Context, r *gtsmodel.Relationship) (*apimodel.Relationship, error) {
diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go
index 0c888a521..0704fb555 100644
--- a/internal/typeutils/internaltofrontend_test.go
+++ b/internal/typeutils/internaltofrontend_test.go
@@ -24,8 +24,9 @@ import (
"testing"
"github.com/stretchr/testify/suite"
+ "github.com/superseriousbusiness/gotosocial/internal/config"
+ "github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
- "github.com/superseriousbusiness/gotosocial/testrig"
)
type InternalToFrontendTestSuite struct {
@@ -454,93 +455,207 @@ func (suite *InternalToFrontendTestSuite) TestVideoAttachmentToFrontend() {
}`, string(b))
}
-func (suite *InternalToFrontendTestSuite) TestInstanceToFrontend() {
- testInstance := &gtsmodel.Instance{
- CreatedAt: testrig.TimeMustParse("2021-10-20T11:36:45Z"),
- UpdatedAt: testrig.TimeMustParse("2021-10-20T11:36:45Z"),
- Domain: "example.org",
- Title: "example instance",
- URI: "https://example.org",
- ShortDescription: "a little description",
- Description: "a much longer description",
- ContactEmail: "someone@example.org",
- Version: "software-from-hell 0.666",
+func (suite *InternalToFrontendTestSuite) TestInstanceV1ToFrontend() {
+ ctx := context.Background()
+
+ i := &gtsmodel.Instance{}
+ if err := suite.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: config.GetHost()}}, i); err != nil {
+ suite.FailNow(err.Error())
}
- apiInstance, err := suite.typeconverter.InstanceToAPIInstance(context.Background(), testInstance)
- suite.NoError(err)
+ instance, err := suite.typeconverter.InstanceToAPIV1Instance(ctx, i)
+ if err != nil {
+ suite.FailNow(err.Error())
+ }
- b, err := json.MarshalIndent(apiInstance, "", " ")
+ b, err := json.MarshalIndent(instance, "", " ")
suite.NoError(err)
suite.Equal(`{
- "uri": "https://example.org",
- "title": "example instance",
- "description": "a much longer description",
- "short_description": "a little description",
- "email": "someone@example.org",
- "version": "software-from-hell 0.666",
- "registrations": false,
- "approval_required": false,
+ "uri": "http://localhost:8080",
+ "account_domain": "localhost:8080",
+ "title": "GoToSocial Testrig Instance",
+ "description": "\u003cp\u003eThis is the GoToSocial testrig. It doesn't federate or anything.\u003c/p\u003e\u003cp\u003eWhen the testrig is shut down, all data on it will be deleted.\u003c/p\u003e\u003cp\u003eDon't use this in production!\u003c/p\u003e",
+ "short_description": "\u003cp\u003eThis is the GoToSocial testrig. It doesn't federate or anything.\u003c/p\u003e\u003cp\u003eWhen the testrig is shut down, all data on it will be deleted.\u003c/p\u003e\u003cp\u003eDon't use this in production!\u003c/p\u003e",
+ "email": "admin@example.org",
+ "version": "0.0.0-testrig",
+ "registrations": true,
+ "approval_required": true,
"invites_enabled": false,
- "thumbnail": "",
- "max_toot_chars": 0
+ "configuration": {
+ "statuses": {
+ "max_characters": 5000,
+ "max_media_attachments": 6,
+ "characters_reserved_per_url": 25
+ },
+ "media_attachments": {
+ "supported_mime_types": [
+ "image/jpeg",
+ "image/gif",
+ "image/png",
+ "image/webp",
+ "video/mp4"
+ ],
+ "image_size_limit": 10485760,
+ "image_matrix_limit": 16777216,
+ "video_size_limit": 41943040,
+ "video_frame_rate_limit": 60,
+ "video_matrix_limit": 16777216
+ },
+ "polls": {
+ "max_options": 6,
+ "max_characters_per_option": 50,
+ "min_expiration": 300,
+ "max_expiration": 2629746
+ },
+ "accounts": {
+ "allow_custom_css": true,
+ "max_featured_tags": 10
+ },
+ "emojis": {
+ "emoji_size_limit": 51200
+ }
+ },
+ "urls": {
+ "streaming_api": "wss://localhost:8080"
+ },
+ "stats": {
+ "domain_count": 2,
+ "status_count": 16,
+ "user_count": 4
+ },
+ "thumbnail": "http://localhost:8080/assets/logo.png",
+ "contact_account": {
+ "id": "01F8MH17FWEB39HZJ76B6VXSKF",
+ "username": "admin",
+ "acct": "admin",
+ "display_name": "",
+ "locked": false,
+ "bot": false,
+ "created_at": "2022-05-17T13:10:59.000Z",
+ "note": "",
+ "url": "http://localhost:8080/@admin",
+ "avatar": "",
+ "avatar_static": "",
+ "header": "http://localhost:8080/assets/default_header.png",
+ "header_static": "http://localhost:8080/assets/default_header.png",
+ "followers_count": 1,
+ "following_count": 1,
+ "statuses_count": 4,
+ "last_status_at": "2021-10-20T10:41:37.000Z",
+ "emojis": [],
+ "fields": [],
+ "enable_rss": true,
+ "role": "admin"
+ },
+ "max_toot_chars": 5000
}`, string(b))
}
-func (suite *InternalToFrontendTestSuite) TestInstanceToFrontendWithAdminAccount() {
- testInstance := &gtsmodel.Instance{
- CreatedAt: testrig.TimeMustParse("2021-10-20T11:36:45Z"),
- UpdatedAt: testrig.TimeMustParse("2021-10-20T11:36:45Z"),
- Domain: "example.org",
- Title: "example instance",
- URI: "https://example.org",
- ShortDescription: "a little description",
- Description: "a much longer description",
- ContactEmail: "someone@example.org",
- ContactAccountID: suite.testAccounts["remote_account_2"].ID,
- Version: "software-from-hell 0.666",
+func (suite *InternalToFrontendTestSuite) TestInstanceV2ToFrontend() {
+ ctx := context.Background()
+
+ i := &gtsmodel.Instance{}
+ if err := suite.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: config.GetHost()}}, i); err != nil {
+ suite.FailNow(err.Error())
}
- apiInstance, err := suite.typeconverter.InstanceToAPIInstance(context.Background(), testInstance)
- suite.NoError(err)
+ instance, err := suite.typeconverter.InstanceToAPIV2Instance(ctx, i)
+ if err != nil {
+ suite.FailNow(err.Error())
+ }
- b, err := json.MarshalIndent(apiInstance, "", " ")
+ b, err := json.MarshalIndent(instance, "", " ")
suite.NoError(err)
suite.Equal(`{
- "uri": "https://example.org",
- "title": "example instance",
- "description": "a much longer description",
- "short_description": "a little description",
- "email": "someone@example.org",
- "version": "software-from-hell 0.666",
- "registrations": false,
- "approval_required": false,
- "invites_enabled": false,
- "thumbnail": "",
- "contact_account": {
- "id": "01FHMQX3GAABWSM0S2VZEC2SWC",
- "username": "Some_User",
- "acct": "Some_User@example.org",
- "display_name": "some user",
- "locked": true,
- "bot": false,
- "created_at": "2020-08-10T12:13:28.000Z",
- "note": "i'm a real son of a gun",
- "url": "http://example.org/@Some_User",
- "avatar": "",
- "avatar_static": "",
- "header": "http://localhost:8080/assets/default_header.png",
- "header_static": "http://localhost:8080/assets/default_header.png",
- "followers_count": 0,
- "following_count": 0,
- "statuses_count": 0,
- "last_status_at": null,
- "emojis": [],
- "fields": []
+ "domain": "localhost:8080",
+ "account_domain": "localhost:8080",
+ "title": "GoToSocial Testrig Instance",
+ "version": "0.0.0-testrig",
+ "source_url": "https://github.com/superseriousbusiness/gotosocial",
+ "description": "\u003cp\u003eThis is the GoToSocial testrig. It doesn't federate or anything.\u003c/p\u003e\u003cp\u003eWhen the testrig is shut down, all data on it will be deleted.\u003c/p\u003e\u003cp\u003eDon't use this in production!\u003c/p\u003e",
+ "usage": {
+ "users": {
+ "active_month": 0
+ }
+ },
+ "thumbnail": {
+ "url": "http://localhost:8080/assets/logo.png"
+ },
+ "languages": [],
+ "configuration": {
+ "urls": {
+ "streaming": "wss://localhost:8080"
+ },
+ "accounts": {
+ "allow_custom_css": true,
+ "max_featured_tags": 10
+ },
+ "statuses": {
+ "max_characters": 5000,
+ "max_media_attachments": 6,
+ "characters_reserved_per_url": 25
+ },
+ "media_attachments": {
+ "supported_mime_types": [
+ "image/jpeg",
+ "image/gif",
+ "image/png",
+ "image/webp",
+ "video/mp4"
+ ],
+ "image_size_limit": 10485760,
+ "image_matrix_limit": 16777216,
+ "video_size_limit": 41943040,
+ "video_frame_rate_limit": 60,
+ "video_matrix_limit": 16777216
+ },
+ "polls": {
+ "max_options": 6,
+ "max_characters_per_option": 50,
+ "min_expiration": 300,
+ "max_expiration": 2629746
+ },
+ "translation": {
+ "enabled": false
+ },
+ "emojis": {
+ "emoji_size_limit": 51200
+ }
+ },
+ "registrations": {
+ "enabled": true,
+ "approval_required": true,
+ "message": null
+ },
+ "contact": {
+ "email": "admin@example.org",
+ "account": {
+ "id": "01F8MH17FWEB39HZJ76B6VXSKF",
+ "username": "admin",
+ "acct": "admin",
+ "display_name": "",
+ "locked": false,
+ "bot": false,
+ "created_at": "2022-05-17T13:10:59.000Z",
+ "note": "",
+ "url": "http://localhost:8080/@admin",
+ "avatar": "",
+ "avatar_static": "",
+ "header": "http://localhost:8080/assets/default_header.png",
+ "header_static": "http://localhost:8080/assets/default_header.png",
+ "followers_count": 1,
+ "following_count": 1,
+ "statuses_count": 4,
+ "last_status_at": "2021-10-20T10:41:37.000Z",
+ "emojis": [],
+ "fields": [],
+ "enable_rss": true,
+ "role": "admin"
+ }
},
- "max_toot_chars": 0
+ "rules": []
}`, string(b))
}