Merge branch 'main' into instance-custom-css

This commit is contained in:
tobi 2024-12-02 10:55:05 +01:00
commit 7cd9b0eae0
947 changed files with 689490 additions and 178161 deletions

View file

@ -68,6 +68,10 @@ type Account struct {
// Description of this account's avatar, for alt text.
// example: A cute drawing of a smiling sloth.
AvatarDescription string `json:"avatar_description,omitempty"`
// Database ID of the media attachment for this account's avatar image.
// Omitted if no avatar uploaded for this account (ie., default avatar).
// example: 01JAJ3XCD66K3T99JZESCR137W
AvatarMediaID string `json:"avatar_media_id,omitempty"`
// Web location of the account's header image.
// example: https://example.org/media/some_user/header/original/header.jpeg
Header string `json:"header"`
@ -78,14 +82,18 @@ type Account struct {
// Description of this account's header, for alt text.
// example: A sunlit field with purple flowers.
HeaderDescription string `json:"header_description,omitempty"`
// Database ID of the media attachment for this account's header image.
// Omitted if no header uploaded for this account (ie., default header).
// example: 01JAJ3XCD66K3T99JZESCR137W
HeaderMediaID string `json:"header_media_id,omitempty"`
// Number of accounts following this account, according to our instance.
FollowersCount int `json:"followers_count"`
// Number of account's followed by this account, according to our instance.
FollowingCount int `json:"following_count"`
// Number of statuses posted by this account, according to our instance.
StatusesCount int `json:"statuses_count"`
// When the account's most recent status was posted (ISO 8601 Datetime).
// example: 2021-07-30T09:20:25+00:00
// When the account's most recent status was posted (ISO 8601 Date).
// example: 2021-07-30
LastStatusAt *string `json:"last_status_at"`
// Array of custom emojis used in this account's note or display name.
// Empty for blocked accounts.

View file

@ -160,7 +160,7 @@ type MediaDimensions struct {
Duration float32 `json:"duration,omitempty"`
// Bitrate of the media in bits per second.
// example: 1000000
Bitrate int `json:"bitrate,omitempty"`
Bitrate uint64 `json:"bitrate,omitempty"`
// Size of the media, in the format `[width]x[height]`.
// Not set for audio.
// example: 1920x1080

View file

@ -27,6 +27,10 @@ type Conversation struct {
// Is the conversation currently marked as unread?
Unread bool `json:"unread"`
// Participants in the conversation.
//
// If this is a conversation between no accounts (ie., a self-directed DM),
// this will include only the requesting account itself. Otherwise, it will
// include every other account in the conversation *except* the requester.
Accounts []Account `json:"accounts"`
// The last status in the conversation. May be `null`.
LastStatus *Status `json:"last_status"`

View file

@ -61,6 +61,9 @@ type DomainPermission struct {
// Time at which the permission entry was created (ISO 8601 Datetime).
// example: 2021-07-30T09:20:25+00:00
CreatedAt string `json:"created_at,omitempty"`
// Permission type of this entry (block, allow).
// Only set for domain permission drafts.
PermissionType string `json:"permission_type,omitempty"`
}
// DomainPermissionRequest is the form submitted as a POST to create a new domain permission entry (allow/block).
@ -69,22 +72,24 @@ type DomainPermission struct {
type DomainPermissionRequest struct {
// A list of domains for which this permission request should apply.
// Only used if import=true is specified.
Domains *multipart.FileHeader `form:"domains" json:"domains" xml:"domains"`
Domains *multipart.FileHeader `form:"domains" json:"domains"`
// A single domain for which this permission request should apply.
// Only used if import=true is NOT specified or if import=false.
// example: example.org
Domain string `form:"domain" json:"domain" xml:"domain"`
Domain string `form:"domain" json:"domain"`
// Obfuscate the domain name when displaying this permission entry publicly.
// Ie., instead of 'example.org' show something like 'e**mpl*.or*'.
// example: false
Obfuscate bool `form:"obfuscate" json:"obfuscate" xml:"obfuscate"`
Obfuscate bool `form:"obfuscate" json:"obfuscate"`
// Private comment for other admins on why this permission entry was created.
// example: don't like 'em!!!!
PrivateComment string `form:"private_comment" json:"private_comment" xml:"private_comment"`
PrivateComment string `form:"private_comment" json:"private_comment"`
// Public comment on why this permission entry was created.
// Will be visible to requesters at /api/v1/instance/peers if this endpoint is exposed.
// example: foss dorks 😫
PublicComment string `form:"public_comment" json:"public_comment" xml:"public_comment"`
PublicComment string `form:"public_comment" json:"public_comment"`
// Permission type to create (only applies to domain permission drafts, not explicit blocks and allows).
PermissionType string `form:"permission_type" json:"permission_type"`
}
// DomainKeysExpireRequest is the form submitted as a POST to /api/v1/admin/domain_keys_expire to expire a domain's public keys.
@ -92,5 +97,5 @@ type DomainPermissionRequest struct {
// swagger:parameters domainKeysExpire
type DomainKeysExpireRequest struct {
// hostname/domain to expire keys for.
Domain string `form:"domain" json:"domain" xml:"domain"`
Domain string `form:"domain" json:"domain"`
}

View file

@ -95,5 +95,5 @@ type FilterCreateUpdateRequestV1 struct {
// Number of seconds from now that the filter should expire. If omitted, filter never expires.
//
// Example: 86400
ExpiresInI interface{} `json:"expires_in"`
ExpiresInI Nullable[any] `json:"expires_in"`
}

View file

@ -134,7 +134,7 @@ type FilterCreateRequestV2 struct {
// Number of seconds from now that the filter should expire. If omitted, filter never expires.
//
// Example: 86400
ExpiresInI interface{} `json:"expires_in"`
ExpiresInI Nullable[any] `json:"expires_in"`
// Keywords to be added to the newly created filter.
Keywords []FilterKeywordCreateUpdateRequest `form:"-" json:"keywords_attributes" xml:"keywords_attributes"`
@ -199,7 +199,7 @@ type FilterUpdateRequestV2 struct {
// Number of seconds from now that the filter should expire. If omitted, filter never expires.
//
// Example: 86400
ExpiresInI interface{} `json:"expires_in"`
ExpiresInI Nullable[any] `json:"expires_in"`
// Keywords to be added to the filter, modified, or removed.
Keywords []FilterKeywordCreateUpdateDeleteRequest `form:"-" json:"keywords_attributes" xml:"keywords_attributes"`

View file

@ -0,0 +1,107 @@
// 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/>.
package model
import (
"bytes"
"encoding/json"
"errors"
)
// Nullable is a generic type, which implements a field that can be one of three states:
//
// - field is not set in the request
// - field is explicitly set to `null` in the request
// - field is explicitly set to a valid value in the request
//
// Nullable is intended to be used with JSON unmarshalling.
//
// Adapted from https://github.com/oapi-codegen/nullable/blob/main/nullable.go
type Nullable[T any] struct {
state nullableState
value T
}
type nullableState uint8
const (
nullableStateUnspecified nullableState = 0
nullableStateNull nullableState = 1
nullableStateSet nullableState = 2
)
// Get retrieves the underlying value, if present,
// and returns an error if the value was not present.
func (t Nullable[T]) Get() (T, error) {
var empty T
if t.IsNull() {
return empty, errors.New("value is null")
}
if !t.IsSpecified() {
return empty, errors.New("value is not specified")
}
return t.value, nil
}
// IsNull indicates whether the field
// was sent, and had a value of `null`
func (t Nullable[T]) IsNull() bool {
return t.state == nullableStateNull
}
// IsSpecified indicates whether the field
// was sent either as a value or as `null`.
func (t Nullable[T]) IsSpecified() bool {
return t.state != nullableStateUnspecified
}
// If field is unspecified,
// UnmarshalJSON won't be called.
func (t *Nullable[T]) UnmarshalJSON(data []byte) error {
// If field is specified as `null`.
if bytes.Equal(data, []byte("null")) {
t.setNull()
return nil
}
// Otherwise, we have an
// actual value, so parse it.
var v T
if err := json.Unmarshal(data, &v); err != nil {
return err
}
t.set(v)
return nil
}
// setNull indicates that the field
// was sent, and had a value of `null`
func (t *Nullable[T]) setNull() {
*t = Nullable[T]{state: nullableStateNull}
}
// set the underlying value to given value.
func (t *Nullable[T]) set(value T) {
*t = Nullable[T]{
state: nullableStateSet,
value: value,
}
}