mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-12-05 01:52:46 +00:00
Compare commits
6 commits
d800af5ae2
...
366054ebce
Author | SHA1 | Date | |
---|---|---|---|
366054ebce | |||
6f3583559f | |||
497ebd8c4e | |||
c1c8849322 | |||
2f582e2e33 | |||
c8fb4c17f1 |
|
@ -167,3 +167,11 @@ Links to the set contact account and/or email address will appear on the footer
|
||||||
The selected **contact user** must be an active (not suspended) admin and/or moderator on the instance.
|
The selected **contact user** must be an active (not suspended) admin and/or moderator on the instance.
|
||||||
|
|
||||||
If you're on a single-user instance and you give admin privileges to your main account, you can just fill in your own username here; you don't need to make a separate admin account just for this.
|
If you're on a single-user instance and you give admin privileges to your main account, you can just fill in your own username here; you don't need to make a separate admin account just for this.
|
||||||
|
|
||||||
|
### Instance Custom CSS
|
||||||
|
|
||||||
|
custom CSS allows you to further customize the way your instance looks when visited through a browser.
|
||||||
|
|
||||||
|
This custom CSS will be applied to all pages of your instance. Users themes and CSS still take precedence over this customization.
|
||||||
|
|
||||||
|
See the [Custom CSS](./custom_css.md) page for some tips on writing custom CSS for your instance.
|
||||||
|
|
|
@ -1545,6 +1545,10 @@ definitions:
|
||||||
$ref: '#/definitions/instanceV1Configuration'
|
$ref: '#/definitions/instanceV1Configuration'
|
||||||
contact_account:
|
contact_account:
|
||||||
$ref: '#/definitions/account'
|
$ref: '#/definitions/account'
|
||||||
|
custom_css:
|
||||||
|
description: Custom CSS for the instance.
|
||||||
|
type: string
|
||||||
|
x-go-name: CustomCSS
|
||||||
debug:
|
debug:
|
||||||
description: Whether or not instance is running in DEBUG mode. Omitted if false.
|
description: Whether or not instance is running in DEBUG mode. Omitted if false.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
@ -1725,6 +1729,10 @@ definitions:
|
||||||
$ref: '#/definitions/instanceV2Configuration'
|
$ref: '#/definitions/instanceV2Configuration'
|
||||||
contact:
|
contact:
|
||||||
$ref: '#/definitions/instanceV2Contact'
|
$ref: '#/definitions/instanceV2Contact'
|
||||||
|
custom_css:
|
||||||
|
description: Instance Custom Css
|
||||||
|
type: string
|
||||||
|
x-go-name: CustomCSS
|
||||||
debug:
|
debug:
|
||||||
description: Whether or not instance is running in DEBUG mode. Omitted if false.
|
description: Whether or not instance is running in DEBUG mode. Omitted if false.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 200 KiB After Width: | Height: | Size: 229 KiB |
6
go.mod
6
go.mod
|
@ -8,13 +8,13 @@ require (
|
||||||
codeberg.org/gruf/go-bytes v1.0.2
|
codeberg.org/gruf/go-bytes v1.0.2
|
||||||
codeberg.org/gruf/go-bytesize v1.0.3
|
codeberg.org/gruf/go-bytesize v1.0.3
|
||||||
codeberg.org/gruf/go-byteutil v1.3.0
|
codeberg.org/gruf/go-byteutil v1.3.0
|
||||||
codeberg.org/gruf/go-cache/v3 v3.5.7
|
codeberg.org/gruf/go-cache/v3 v3.6.1
|
||||||
codeberg.org/gruf/go-debug v1.3.0
|
codeberg.org/gruf/go-debug v1.3.0
|
||||||
codeberg.org/gruf/go-errors/v2 v2.3.2
|
codeberg.org/gruf/go-errors/v2 v2.3.2
|
||||||
codeberg.org/gruf/go-fastcopy v1.1.3
|
codeberg.org/gruf/go-fastcopy v1.1.3
|
||||||
codeberg.org/gruf/go-ffmpreg v0.2.6
|
codeberg.org/gruf/go-ffmpreg v0.2.6
|
||||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
||||||
codeberg.org/gruf/go-kv v1.6.4
|
codeberg.org/gruf/go-kv v1.6.5
|
||||||
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
|
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
|
||||||
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760
|
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760
|
||||||
codeberg.org/gruf/go-mimetypes v1.2.0
|
codeberg.org/gruf/go-mimetypes v1.2.0
|
||||||
|
@ -87,7 +87,7 @@ require (
|
||||||
require (
|
require (
|
||||||
codeberg.org/gruf/go-fastpath/v2 v2.0.0 // indirect
|
codeberg.org/gruf/go-fastpath/v2 v2.0.0 // indirect
|
||||||
codeberg.org/gruf/go-mangler v1.4.1 // indirect
|
codeberg.org/gruf/go-mangler v1.4.1 // indirect
|
||||||
codeberg.org/gruf/go-maps v1.0.3 // indirect
|
codeberg.org/gruf/go-maps v1.0.4 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||||
|
|
12
go.sum
12
go.sum
|
@ -36,8 +36,8 @@ codeberg.org/gruf/go-bytesize v1.0.3 h1:Tz8tCxhPLeyM5VryuBNjUHgKmLj4Bx9RbPaUSA3q
|
||||||
codeberg.org/gruf/go-bytesize v1.0.3/go.mod h1:n/GU8HzL9f3UNp/mUKyr1qVmTlj7+xacpp0OHfkvLPs=
|
codeberg.org/gruf/go-bytesize v1.0.3/go.mod h1:n/GU8HzL9f3UNp/mUKyr1qVmTlj7+xacpp0OHfkvLPs=
|
||||||
codeberg.org/gruf/go-byteutil v1.3.0 h1:nRqJnCcRQ7xbfU6azw7zOzJrSMDIJHBqX6FL9vEMYmU=
|
codeberg.org/gruf/go-byteutil v1.3.0 h1:nRqJnCcRQ7xbfU6azw7zOzJrSMDIJHBqX6FL9vEMYmU=
|
||||||
codeberg.org/gruf/go-byteutil v1.3.0/go.mod h1:chgnZz1LUcfaObaIFglxF5MRYQkJGjQf4WwVz95ccCM=
|
codeberg.org/gruf/go-byteutil v1.3.0/go.mod h1:chgnZz1LUcfaObaIFglxF5MRYQkJGjQf4WwVz95ccCM=
|
||||||
codeberg.org/gruf/go-cache/v3 v3.5.7 h1:5hut49a8Wp3hdwrCEJYj6pHY2aRR1hyTmkK4+wHVYq4=
|
codeberg.org/gruf/go-cache/v3 v3.6.1 h1:sY1XhYeskjZAuYeMm5R0o4Qymru5taNbzmZPSn1oXLE=
|
||||||
codeberg.org/gruf/go-cache/v3 v3.5.7/go.mod h1:Thahfuf3PgHSv2+1zHpvhRdX97tx1WXurVNGWpZucAM=
|
codeberg.org/gruf/go-cache/v3 v3.6.1/go.mod h1:JUNjc4E8gRccn3t+B99akxURFrU6NTDkvFVcwiZirnw=
|
||||||
codeberg.org/gruf/go-debug v1.3.0 h1:PIRxQiWUFKtGOGZFdZ3Y0pqyfI0Xr87j224IYe2snZs=
|
codeberg.org/gruf/go-debug v1.3.0 h1:PIRxQiWUFKtGOGZFdZ3Y0pqyfI0Xr87j224IYe2snZs=
|
||||||
codeberg.org/gruf/go-debug v1.3.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg=
|
codeberg.org/gruf/go-debug v1.3.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg=
|
||||||
codeberg.org/gruf/go-errors/v2 v2.3.2 h1:8ItWaOMfhDaqrJK1Pw8MO0Nu+o/tVcQtR5cJ58Vc4zo=
|
codeberg.org/gruf/go-errors/v2 v2.3.2 h1:8ItWaOMfhDaqrJK1Pw8MO0Nu+o/tVcQtR5cJ58Vc4zo=
|
||||||
|
@ -50,16 +50,16 @@ codeberg.org/gruf/go-ffmpreg v0.2.6 h1:OHlTOF+62/b+VeM3Svg7praweU/NECRIsuhilZLFa
|
||||||
codeberg.org/gruf/go-ffmpreg v0.2.6/go.mod h1:sViRI0BYK2B8PJw4BrOg7DquPD71mZjDfffRAFcDtvk=
|
codeberg.org/gruf/go-ffmpreg v0.2.6/go.mod h1:sViRI0BYK2B8PJw4BrOg7DquPD71mZjDfffRAFcDtvk=
|
||||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf h1:84s/ii8N6lYlskZjHH+DG6jyia8w2mXMZlRwFn8Gs3A=
|
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf h1:84s/ii8N6lYlskZjHH+DG6jyia8w2mXMZlRwFn8Gs3A=
|
||||||
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk=
|
codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk=
|
||||||
codeberg.org/gruf/go-kv v1.6.4 h1:3NZiW8HVdBM3kpOiLb7XfRiihnzZWMAixdCznguhILk=
|
codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0=
|
||||||
codeberg.org/gruf/go-kv v1.6.4/go.mod h1:O/YkSvKiS9XsRolM3rqCd9YJmND7dAXu9z+PrlYO4bc=
|
codeberg.org/gruf/go-kv v1.6.5/go.mod h1:c4PsGqw05bDScvISpK+d31SiDEpBorweCL50hsiK3dc=
|
||||||
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f h1:Ss6Z+vygy+jOGhj96d/GwsYYDd22QmIcH74zM7/nQkw=
|
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f h1:Ss6Z+vygy+jOGhj96d/GwsYYDd22QmIcH74zM7/nQkw=
|
||||||
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f/go.mod h1:F9pl4h34iuVN7kucKam9fLwsItTc+9mmaKt7pNXRd/4=
|
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f/go.mod h1:F9pl4h34iuVN7kucKam9fLwsItTc+9mmaKt7pNXRd/4=
|
||||||
codeberg.org/gruf/go-loosy v0.0.0-20231007123304-bb910d1ab5c4 h1:IXwfoU7f2whT6+JKIKskNl/hBlmWmnF1vZd84Eb3cyA=
|
codeberg.org/gruf/go-loosy v0.0.0-20231007123304-bb910d1ab5c4 h1:IXwfoU7f2whT6+JKIKskNl/hBlmWmnF1vZd84Eb3cyA=
|
||||||
codeberg.org/gruf/go-loosy v0.0.0-20231007123304-bb910d1ab5c4/go.mod h1:fiO8HE1wjZCephcYmRRsVnNI/i0+mhy44Z5dQalS0rM=
|
codeberg.org/gruf/go-loosy v0.0.0-20231007123304-bb910d1ab5c4/go.mod h1:fiO8HE1wjZCephcYmRRsVnNI/i0+mhy44Z5dQalS0rM=
|
||||||
codeberg.org/gruf/go-mangler v1.4.1 h1:Dv58jFfy9On49L11ji6tpADUknwoJA46iaiZvnNXecs=
|
codeberg.org/gruf/go-mangler v1.4.1 h1:Dv58jFfy9On49L11ji6tpADUknwoJA46iaiZvnNXecs=
|
||||||
codeberg.org/gruf/go-mangler v1.4.1/go.mod h1:mDmW8Ia352RvNFaXoP9K60TgcmCZJtX0j6wm3vjAsJE=
|
codeberg.org/gruf/go-mangler v1.4.1/go.mod h1:mDmW8Ia352RvNFaXoP9K60TgcmCZJtX0j6wm3vjAsJE=
|
||||||
codeberg.org/gruf/go-maps v1.0.3 h1:VDwhnnaVNUIy5O93CvkcE2IZXnMB1+IJjzfop9V12es=
|
codeberg.org/gruf/go-maps v1.0.4 h1:K+Ww4vvR3TZqm5jqrKVirmguZwa3v1VUvmig2SE8uxY=
|
||||||
codeberg.org/gruf/go-maps v1.0.3/go.mod h1:D5LNDxlC9rsDuVQVM6JObaVGAdHB6g2dTdOdkh1aXWA=
|
codeberg.org/gruf/go-maps v1.0.4/go.mod h1:ASX7osM7kFwt5O8GfGflcFjrwYGD8eIuRLl/oMjhEi8=
|
||||||
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760 h1:m2/UCRXhjDwAg4vyji6iKCpomKw6P4PmBOUi5DvAMH4=
|
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760 h1:m2/UCRXhjDwAg4vyji6iKCpomKw6P4PmBOUi5DvAMH4=
|
||||||
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760/go.mod h1:E3RcaCFNq4zXpvaJb8lfpPqdUAmSkP5F1VmMiEUYTEk=
|
codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760/go.mod h1:E3RcaCFNq4zXpvaJb8lfpPqdUAmSkP5F1VmMiEUYTEk=
|
||||||
codeberg.org/gruf/go-mimetypes v1.2.0 h1:3rZGXY/SkNYbamiddWXs2gETXIBkGIeWYnbWpp2OEbc=
|
codeberg.org/gruf/go-mimetypes v1.2.0 h1:3rZGXY/SkNYbamiddWXs2gETXIBkGIeWYnbWpp2OEbc=
|
||||||
|
|
|
@ -175,6 +175,7 @@ func validateInstanceUpdate(form *apimodel.InstanceSettingsUpdateRequest) error
|
||||||
form.ContactEmail == nil &&
|
form.ContactEmail == nil &&
|
||||||
form.ShortDescription == nil &&
|
form.ShortDescription == nil &&
|
||||||
form.Description == nil &&
|
form.Description == nil &&
|
||||||
|
form.CustomCSS == nil &&
|
||||||
form.Terms == nil &&
|
form.Terms == nil &&
|
||||||
form.Avatar == nil &&
|
form.Avatar == nil &&
|
||||||
form.AvatarDescription == nil &&
|
form.AvatarDescription == nil &&
|
||||||
|
|
|
@ -33,6 +33,8 @@ type InstanceSettingsUpdateRequest struct {
|
||||||
ShortDescription *string `form:"short_description" json:"short_description" xml:"short_description"`
|
ShortDescription *string `form:"short_description" json:"short_description" xml:"short_description"`
|
||||||
// Longer description of the instance, max 5,000 chars. HTML formatting accepted.
|
// Longer description of the instance, max 5,000 chars. HTML formatting accepted.
|
||||||
Description *string `form:"description" json:"description" xml:"description"`
|
Description *string `form:"description" json:"description" xml:"description"`
|
||||||
|
// Custom CSS for the instance.
|
||||||
|
CustomCSS *string `form:"custom_css" json:"custom_css,omitempty" xml:"custom_css"`
|
||||||
// Terms and conditions of the instance, max 5,000 chars. HTML formatting accepted.
|
// Terms and conditions of the instance, max 5,000 chars. HTML formatting accepted.
|
||||||
Terms *string `form:"terms" json:"terms" xml:"terms"`
|
Terms *string `form:"terms" json:"terms" xml:"terms"`
|
||||||
// Image to use as the instance thumbnail.
|
// Image to use as the instance thumbnail.
|
||||||
|
|
|
@ -38,6 +38,8 @@ type InstanceV1 struct {
|
||||||
//
|
//
|
||||||
// This should be displayed on the 'about' page for an instance.
|
// This should be displayed on the 'about' page for an instance.
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
// Custom CSS for the instance.
|
||||||
|
CustomCSS string `json:"custom_css,omitempty"`
|
||||||
// Raw (unparsed) version of description.
|
// Raw (unparsed) version of description.
|
||||||
DescriptionText string `json:"description_text,omitempty"`
|
DescriptionText string `json:"description_text,omitempty"`
|
||||||
// A shorter description of the instance.
|
// A shorter description of the instance.
|
||||||
|
|
|
@ -53,6 +53,8 @@ type InstanceV2 struct {
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
// Raw (unparsed) version of description.
|
// Raw (unparsed) version of description.
|
||||||
DescriptionText string `json:"description_text,omitempty"`
|
DescriptionText string `json:"description_text,omitempty"`
|
||||||
|
// Instance Custom Css
|
||||||
|
CustomCSS string `json:"custom_css,omitempty"`
|
||||||
// Basic anonymous usage data for this instance.
|
// Basic anonymous usage data for this instance.
|
||||||
Usage InstanceV2Usage `json:"usage"`
|
Usage InstanceV2Usage `json:"usage"`
|
||||||
// An image used to represent this instance.
|
// An image used to represent this instance.
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
// 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 migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
up := func(ctx context.Context, db *bun.DB) error {
|
||||||
|
_, err := db.ExecContext(ctx, "ALTER TABLE ? ADD COLUMN ? TEXT", bun.Ident("instances"), bun.Ident("custom_css"))
|
||||||
|
if err != nil && !(strings.Contains(err.Error(), "already exists") || strings.Contains(err.Error(), "duplicate column name") || strings.Contains(err.Error(), "SQLSTATE 42701")) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
down := func(ctx context.Context, db *bun.DB) error {
|
||||||
|
_, err := db.ExecContext(ctx, "ALTER TABLE ? DROP COLUMN ?", bun.Ident("instances"), bun.Ident("custom_css"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Migrations.Register(up, down); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,8 +40,22 @@
|
||||||
notRelevantKey
|
notRelevantKey
|
||||||
spamKey
|
spamKey
|
||||||
notPermittedKey
|
notPermittedKey
|
||||||
|
limitReachedKey
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// LimitReached indicates that this error was caused by
|
||||||
|
// some kind of limit being reached, e.g. media upload limit.
|
||||||
|
func LimitReached(err error) bool {
|
||||||
|
_, ok := errors.Value(err, limitReachedKey).(struct{})
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLimitReached will wrap the given error to store a "limit reached"
|
||||||
|
// flag, returning wrapped error. See LimitReached() for example use-cases.
|
||||||
|
func SetLimitReached(err error) error {
|
||||||
|
return errors.WithValue(err, limitReachedKey, struct{}{})
|
||||||
|
}
|
||||||
|
|
||||||
// IsUnretrievable indicates that a call to retrieve a resource
|
// IsUnretrievable indicates that a call to retrieve a resource
|
||||||
// (account, status, attachment, etc) could not be fulfilled, either
|
// (account, status, attachment, etc) could not be fulfilled, either
|
||||||
// because it was not found locally, or because some prerequisite
|
// because it was not found locally, or because some prerequisite
|
||||||
|
|
|
@ -34,6 +34,7 @@ type Instance struct {
|
||||||
ShortDescriptionText string `bun:""` // Raw text version of short description (before parsing).
|
ShortDescriptionText string `bun:""` // Raw text version of short description (before parsing).
|
||||||
Description string `bun:""` // Longer description of this instance.
|
Description string `bun:""` // Longer description of this instance.
|
||||||
DescriptionText string `bun:""` // Raw text version of long description (before parsing).
|
DescriptionText string `bun:""` // Raw text version of long description (before parsing).
|
||||||
|
CustomCSS string `bun:",nullzero"` // Custom CSS for the instance.
|
||||||
Terms string `bun:""` // Terms and conditions of this instance.
|
Terms string `bun:""` // Terms and conditions of this instance.
|
||||||
TermsText string `bun:""` // Raw text version of terms (before parsing).
|
TermsText string `bun:""` // Raw text version of terms (before parsing).
|
||||||
ContactEmail string `bun:""` // Contact email address for this instance
|
ContactEmail string `bun:""` // Contact email address for this instance
|
||||||
|
|
|
@ -381,11 +381,19 @@ func (res *result) GetFileType() (gtsmodel.FileType, string) {
|
||||||
return gtsmodel.FileTypeAudio, "wma"
|
return gtsmodel.FileTypeAudio, "wma"
|
||||||
}
|
}
|
||||||
case "ogg":
|
case "ogg":
|
||||||
switch {
|
if len(res.video) > 0 {
|
||||||
case len(res.video) > 0:
|
switch res.video[0].codec {
|
||||||
return gtsmodel.FileTypeVideo, "ogv"
|
case "theora", "dirac": // daala, tarkin
|
||||||
case len(res.audio) > 0:
|
return gtsmodel.FileTypeVideo, "ogv"
|
||||||
return gtsmodel.FileTypeAudio, "ogg"
|
}
|
||||||
|
}
|
||||||
|
if len(res.audio) > 0 {
|
||||||
|
switch res.audio[0].codec {
|
||||||
|
case "opus", "libopus":
|
||||||
|
return gtsmodel.FileTypeAudio, "opus"
|
||||||
|
default:
|
||||||
|
return gtsmodel.FileTypeAudio, "ogg"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case "matroska,webm":
|
case "matroska,webm":
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
"codeberg.org/gruf/go-bytesize"
|
"codeberg.org/gruf/go-bytesize"
|
||||||
"codeberg.org/gruf/go-iotools"
|
"codeberg.org/gruf/go-iotools"
|
||||||
"codeberg.org/gruf/go-mimetypes"
|
"codeberg.org/gruf/go-mimetypes"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||||
)
|
)
|
||||||
|
|
||||||
// file represents one file
|
// file represents one file
|
||||||
|
@ -143,8 +144,9 @@ func drainToTmp(rc io.ReadCloser) (string, error) {
|
||||||
|
|
||||||
// Check to see if limit was reached,
|
// Check to see if limit was reached,
|
||||||
// (produces more useful error messages).
|
// (produces more useful error messages).
|
||||||
if lr != nil && !iotools.AtEOF(lr.R) {
|
if lr != nil && lr.N <= 0 {
|
||||||
return path, fmt.Errorf("reached read limit %s", bytesize.Size(limit))
|
err := fmt.Errorf("reached read limit %s", bytesize.Size(limit))
|
||||||
|
return path, gtserror.SetLimitReached(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return path, nil
|
return path, nil
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/media"
|
"github.com/superseriousbusiness/gotosocial/internal/media"
|
||||||
|
@ -51,11 +52,18 @@ func (p *Processor) StoreLocalMedia(
|
||||||
|
|
||||||
// Immediately trigger write to storage.
|
// Immediately trigger write to storage.
|
||||||
attachment, err := processing.Load(ctx)
|
attachment, err := processing.Load(ctx)
|
||||||
if err != nil {
|
switch {
|
||||||
const text = "error processing emoji"
|
case gtserror.LimitReached(err):
|
||||||
|
limit := config.GetMediaLocalMaxSize()
|
||||||
|
text := fmt.Sprintf("local media size limit reached: %s", limit)
|
||||||
|
return nil, gtserror.NewErrorUnprocessableEntity(err, text)
|
||||||
|
|
||||||
|
case err != nil:
|
||||||
|
const text = "error processing media"
|
||||||
err := gtserror.Newf("error processing media: %w", err)
|
err := gtserror.Newf("error processing media: %w", err)
|
||||||
return nil, gtserror.NewErrorUnprocessableEntity(err, text)
|
return nil, gtserror.NewErrorUnprocessableEntity(err, text)
|
||||||
} else if attachment.Type == gtsmodel.FileTypeUnknown {
|
|
||||||
|
case attachment.Type == gtsmodel.FileTypeUnknown:
|
||||||
text := fmt.Sprintf("could not process %s type media", attachment.File.ContentType)
|
text := fmt.Sprintf("could not process %s type media", attachment.File.ContentType)
|
||||||
return nil, gtserror.NewErrorUnprocessableEntity(errors.New(text), text)
|
return nil, gtserror.NewErrorUnprocessableEntity(errors.New(text), text)
|
||||||
}
|
}
|
||||||
|
@ -86,9 +94,15 @@ func (p *Processor) StoreLocalEmoji(
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Immediately write to storage.
|
// Immediately trigger write to storage.
|
||||||
emoji, err := processing.Load(ctx)
|
emoji, err := processing.Load(ctx)
|
||||||
if err != nil {
|
switch {
|
||||||
|
case gtserror.LimitReached(err):
|
||||||
|
limit := config.GetMediaEmojiLocalMaxSize()
|
||||||
|
text := fmt.Sprintf("local emoji size limit reached: %s", limit)
|
||||||
|
return nil, gtserror.NewErrorUnprocessableEntity(err, text)
|
||||||
|
|
||||||
|
case err != nil:
|
||||||
const text = "error processing emoji"
|
const text = "error processing emoji"
|
||||||
err := gtserror.Newf("error processing emoji %s: %w", shortcode, err)
|
err := gtserror.Newf("error processing emoji %s: %w", shortcode, err)
|
||||||
return nil, gtserror.NewErrorUnprocessableEntity(err, text)
|
return nil, gtserror.NewErrorUnprocessableEntity(err, text)
|
||||||
|
|
|
@ -227,6 +227,17 @@ func (p *Processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSe
|
||||||
columns = append(columns, []string{"description", "description_text"}...)
|
columns = append(columns, []string{"description", "description_text"}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate & update site custom css if it's set on the form
|
||||||
|
if form.CustomCSS != nil {
|
||||||
|
customCSS := *form.CustomCSS
|
||||||
|
if err := validate.InstanceCustomCSS(customCSS); err != nil {
|
||||||
|
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.CustomCSS = text.SanitizeToPlaintext(customCSS)
|
||||||
|
columns = append(columns, []string{"custom_css"}...)
|
||||||
|
}
|
||||||
|
|
||||||
// Validate & update site
|
// Validate & update site
|
||||||
// terms if set on the form.
|
// terms if set on the form.
|
||||||
if form.Terms != nil {
|
if form.Terms != nil {
|
||||||
|
|
|
@ -1523,6 +1523,7 @@ func (c *Converter) InstanceToAPIV1Instance(ctx context.Context, i *gtsmodel.Ins
|
||||||
Title: i.Title,
|
Title: i.Title,
|
||||||
Description: i.Description,
|
Description: i.Description,
|
||||||
DescriptionText: i.DescriptionText,
|
DescriptionText: i.DescriptionText,
|
||||||
|
CustomCSS: i.CustomCSS,
|
||||||
ShortDescription: i.ShortDescription,
|
ShortDescription: i.ShortDescription,
|
||||||
ShortDescriptionText: i.ShortDescriptionText,
|
ShortDescriptionText: i.ShortDescriptionText,
|
||||||
Email: i.ContactEmail,
|
Email: i.ContactEmail,
|
||||||
|
@ -1644,6 +1645,7 @@ func (c *Converter) InstanceToAPIV2Instance(ctx context.Context, i *gtsmodel.Ins
|
||||||
SourceURL: instanceSourceURL,
|
SourceURL: instanceSourceURL,
|
||||||
Description: i.Description,
|
Description: i.Description,
|
||||||
DescriptionText: i.DescriptionText,
|
DescriptionText: i.DescriptionText,
|
||||||
|
CustomCSS: i.CustomCSS,
|
||||||
Usage: apimodel.InstanceV2Usage{}, // todo: not implemented
|
Usage: apimodel.InstanceV2Usage{}, // todo: not implemented
|
||||||
Languages: config.GetInstanceLanguages().TagStrs(),
|
Languages: config.GetInstanceLanguages().TagStrs(),
|
||||||
Rules: c.InstanceRulesToAPIRules(i.Rules),
|
Rules: c.InstanceRulesToAPIRules(i.Rules),
|
||||||
|
|
|
@ -189,6 +189,16 @@ func CustomCSS(customCSS string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func InstanceCustomCSS(customCSS string) error {
|
||||||
|
|
||||||
|
maximumCustomCSSLength := config.GetAccountsCustomCSSLength()
|
||||||
|
if length := len([]rune(customCSS)); length > maximumCustomCSSLength {
|
||||||
|
return fmt.Errorf("custom_css must be less than %d characters, but submitted custom_css was %d characters", maximumCustomCSSLength, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// EmojiShortcode just runs the given shortcode through the regular expression
|
// EmojiShortcode just runs the given shortcode through the regular expression
|
||||||
// for emoji shortcodes, to figure out whether it's a valid shortcode, ie., 2-30 characters,
|
// for emoji shortcodes, to figure out whether it's a valid shortcode, ie., 2-30 characters,
|
||||||
// a-zA-Z, numbers, and underscores.
|
// a-zA-Z, numbers, and underscores.
|
||||||
|
|
|
@ -54,7 +54,7 @@ func (m *Module) aboutGETHandler(c *gin.Context) {
|
||||||
Template: "about.tmpl",
|
Template: "about.tmpl",
|
||||||
Instance: instance,
|
Instance: instance,
|
||||||
OGMeta: apiutil.OGBase(instance),
|
OGMeta: apiutil.OGBase(instance),
|
||||||
Stylesheets: []string{cssAbout},
|
Stylesheets: []string{cssAbout, instanceCustomCSSPath},
|
||||||
Extra: map[string]any{
|
Extra: map[string]any{
|
||||||
"showStrap": true,
|
"showStrap": true,
|
||||||
"blocklistExposed": config.GetInstanceExposeSuspendedWeb(),
|
"blocklistExposed": config.GetInstanceExposeSuspendedWeb(),
|
||||||
|
|
|
@ -127,8 +127,9 @@ func (m *Module) confirmEmailPOSTHandler(c *gin.Context) {
|
||||||
// Serve page informing user that their
|
// Serve page informing user that their
|
||||||
// email address is now confirmed.
|
// email address is now confirmed.
|
||||||
page := apiutil.WebPage{
|
page := apiutil.WebPage{
|
||||||
Template: "confirmed_email.tmpl",
|
Template: "confirmed_email.tmpl",
|
||||||
Instance: instance,
|
Instance: instance,
|
||||||
|
Stylesheets: []string{instanceCustomCSSPath},
|
||||||
Extra: map[string]any{
|
Extra: map[string]any{
|
||||||
"email": user.Email,
|
"email": user.Email,
|
||||||
"username": user.Account.Username,
|
"username": user.Account.Username,
|
||||||
|
|
|
@ -55,3 +55,22 @@ func (m *Module) customCSSGETHandler(c *gin.Context) {
|
||||||
c.Header(cacheControlHeader, cacheControlNoCache)
|
c.Header(cacheControlHeader, cacheControlNoCache)
|
||||||
c.Data(http.StatusOK, textCSSUTF8, []byte(customCSS))
|
c.Data(http.StatusOK, textCSSUTF8, []byte(customCSS))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Module) instanceCustomCSSGETHandler(c *gin.Context) {
|
||||||
|
|
||||||
|
if _, err := apiutil.NegotiateAccept(c, apiutil.TextCSS); err != nil {
|
||||||
|
apiutil.WebErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceV1, errWithCode := m.processor.InstanceGetV1(c.Request.Context())
|
||||||
|
if errWithCode != nil {
|
||||||
|
apiutil.WebErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceCustomCSS := instanceV1.CustomCSS
|
||||||
|
|
||||||
|
c.Header(cacheControlHeader, cacheControlNoCache)
|
||||||
|
c.Data(http.StatusOK, textCSSUTF8, []byte(instanceCustomCSS))
|
||||||
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ func (m *Module) domainBlockListGETHandler(c *gin.Context) {
|
||||||
Template: "domain-blocklist.tmpl",
|
Template: "domain-blocklist.tmpl",
|
||||||
Instance: instance,
|
Instance: instance,
|
||||||
OGMeta: apiutil.OGBase(instance),
|
OGMeta: apiutil.OGBase(instance),
|
||||||
Stylesheets: []string{cssFA},
|
Stylesheets: []string{cssFA, instanceCustomCSSPath},
|
||||||
Javascript: []string{jsFrontend},
|
Javascript: []string{jsFrontend},
|
||||||
Extra: map[string]any{"blocklist": domainBlocks},
|
Extra: map[string]any{"blocklist": domainBlocks},
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (m *Module) indexHandler(c *gin.Context) {
|
||||||
Template: "index.tmpl",
|
Template: "index.tmpl",
|
||||||
Instance: instance,
|
Instance: instance,
|
||||||
OGMeta: apiutil.OGBase(instance),
|
OGMeta: apiutil.OGBase(instance),
|
||||||
Stylesheets: []string{cssAbout, cssIndex},
|
Stylesheets: []string{cssAbout, cssIndex, instanceCustomCSSPath},
|
||||||
Extra: map[string]any{"showStrap": true},
|
Extra: map[string]any{"showStrap": true},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ func (m *Module) profileGETHandler(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare stylesheets for profile.
|
// Prepare stylesheets for profile.
|
||||||
stylesheets := make([]string, 0, 6)
|
stylesheets := make([]string, 0, 7)
|
||||||
|
|
||||||
// Basic profile stylesheets.
|
// Basic profile stylesheets.
|
||||||
stylesheets = append(
|
stylesheets = append(
|
||||||
|
@ -142,6 +142,7 @@ func (m *Module) profileGETHandler(c *gin.Context) {
|
||||||
cssStatus,
|
cssStatus,
|
||||||
cssThread,
|
cssThread,
|
||||||
cssProfile,
|
cssProfile,
|
||||||
|
instanceCustomCSSPath,
|
||||||
}...,
|
}...,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ func (m *Module) SettingsPanelHandler(c *gin.Context) {
|
||||||
cssProfile, // Used for rendering stub/fake profiles.
|
cssProfile, // Used for rendering stub/fake profiles.
|
||||||
cssStatus, // Used for rendering stub/fake statuses.
|
cssStatus, // Used for rendering stub/fake statuses.
|
||||||
cssSettings,
|
cssSettings,
|
||||||
|
instanceCustomCSSPath,
|
||||||
},
|
},
|
||||||
Javascript: []string{jsSettings},
|
Javascript: []string{jsSettings},
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,9 +126,10 @@ func (m *Module) signupPOSTHandler(c *gin.Context) {
|
||||||
// Serve a page informing the
|
// Serve a page informing the
|
||||||
// user that they've signed up.
|
// user that they've signed up.
|
||||||
page := apiutil.WebPage{
|
page := apiutil.WebPage{
|
||||||
Template: "signed-up.tmpl",
|
Template: "signed-up.tmpl",
|
||||||
Instance: instance,
|
Instance: instance,
|
||||||
OGMeta: apiutil.OGBase(instance),
|
Stylesheets: []string{instanceCustomCSSPath},
|
||||||
|
OGMeta: apiutil.OGBase(instance),
|
||||||
Extra: map[string]any{
|
Extra: map[string]any{
|
||||||
"email": user.UnconfirmedEmail,
|
"email": user.UnconfirmedEmail,
|
||||||
"username": user.Account.Username,
|
"username": user.Account.Username,
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (m *Module) tagGETHandler(c *gin.Context) {
|
||||||
Template: "tag.tmpl",
|
Template: "tag.tmpl",
|
||||||
Instance: instance,
|
Instance: instance,
|
||||||
OGMeta: apiutil.OGBase(instance),
|
OGMeta: apiutil.OGBase(instance),
|
||||||
Stylesheets: []string{cssFA, cssThread, cssTag},
|
Stylesheets: []string{cssFA, cssThread, cssTag, instanceCustomCSSPath},
|
||||||
Extra: map[string]any{"tagName": tagName},
|
Extra: map[string]any{"tagName": tagName},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ func (m *Module) threadGETHandler(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare stylesheets for thread.
|
// Prepare stylesheets for thread.
|
||||||
stylesheets := make([]string, 0, 5)
|
stylesheets := make([]string, 0, 6)
|
||||||
|
|
||||||
// Basic thread stylesheets.
|
// Basic thread stylesheets.
|
||||||
stylesheets = append(
|
stylesheets = append(
|
||||||
|
@ -131,6 +131,7 @@ func (m *Module) threadGETHandler(c *gin.Context) {
|
||||||
if theme := targetAccount.Theme; theme != "" {
|
if theme := targetAccount.Theme; theme != "" {
|
||||||
stylesheets = append(
|
stylesheets = append(
|
||||||
stylesheets,
|
stylesheets,
|
||||||
|
instanceCustomCSSPath,
|
||||||
themesPathPrefix+"/"+theme,
|
themesPathPrefix+"/"+theme,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,20 +36,21 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
confirmEmailPath = "/" + uris.ConfirmEmailPath
|
confirmEmailPath = "/" + uris.ConfirmEmailPath
|
||||||
profileGroupPath = "/@:username"
|
profileGroupPath = "/@:username"
|
||||||
statusPath = "/statuses/:" + apiutil.WebStatusIDKey // leave out the '/@:username' prefix as this will be served within the profile group
|
statusPath = "/statuses/:" + apiutil.WebStatusIDKey // leave out the '/@:username' prefix as this will be served within the profile group
|
||||||
tagsPath = "/tags/:" + apiutil.TagNameKey
|
tagsPath = "/tags/:" + apiutil.TagNameKey
|
||||||
customCSSPath = profileGroupPath + "/custom.css"
|
customCSSPath = profileGroupPath + "/custom.css"
|
||||||
rssFeedPath = profileGroupPath + "/feed.rss"
|
instanceCustomCSSPath = "/custom.css"
|
||||||
assetsPathPrefix = "/assets"
|
rssFeedPath = profileGroupPath + "/feed.rss"
|
||||||
distPathPrefix = assetsPathPrefix + "/dist"
|
assetsPathPrefix = "/assets"
|
||||||
themesPathPrefix = assetsPathPrefix + "/themes"
|
distPathPrefix = assetsPathPrefix + "/dist"
|
||||||
settingsPathPrefix = "/settings"
|
themesPathPrefix = assetsPathPrefix + "/themes"
|
||||||
settingsPanelGlob = settingsPathPrefix + "/*panel"
|
settingsPathPrefix = "/settings"
|
||||||
userPanelPath = settingsPathPrefix + "/user"
|
settingsPanelGlob = settingsPathPrefix + "/*panel"
|
||||||
adminPanelPath = settingsPathPrefix + "/admin"
|
userPanelPath = settingsPathPrefix + "/user"
|
||||||
signupPath = "/signup"
|
adminPanelPath = settingsPathPrefix + "/admin"
|
||||||
|
signupPath = "/signup"
|
||||||
|
|
||||||
cacheControlHeader = "Cache-Control" // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
|
cacheControlHeader = "Cache-Control" // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
|
||||||
cacheControlNoCache = "no-cache" // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#response_directives
|
cacheControlNoCache = "no-cache" // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#response_directives
|
||||||
|
@ -114,6 +115,7 @@ func (m *Module) Route(r *router.Router, mi ...gin.HandlerFunc) {
|
||||||
r.AttachHandler(http.MethodGet, settingsPathPrefix, m.SettingsPanelHandler)
|
r.AttachHandler(http.MethodGet, settingsPathPrefix, m.SettingsPanelHandler)
|
||||||
r.AttachHandler(http.MethodGet, settingsPanelGlob, m.SettingsPanelHandler)
|
r.AttachHandler(http.MethodGet, settingsPanelGlob, m.SettingsPanelHandler)
|
||||||
r.AttachHandler(http.MethodGet, customCSSPath, m.customCSSGETHandler)
|
r.AttachHandler(http.MethodGet, customCSSPath, m.customCSSGETHandler)
|
||||||
|
r.AttachHandler(http.MethodGet, instanceCustomCSSPath, m.instanceCustomCSSGETHandler)
|
||||||
r.AttachHandler(http.MethodGet, rssFeedPath, m.rssFeedGETHandler)
|
r.AttachHandler(http.MethodGet, rssFeedPath, m.rssFeedGETHandler)
|
||||||
r.AttachHandler(http.MethodGet, confirmEmailPath, m.confirmEmailGETHandler)
|
r.AttachHandler(http.MethodGet, confirmEmailPath, m.confirmEmailGETHandler)
|
||||||
r.AttachHandler(http.MethodPost, confirmEmailPath, m.confirmEmailPOSTHandler)
|
r.AttachHandler(http.MethodPost, confirmEmailPath, m.confirmEmailPOSTHandler)
|
||||||
|
|
6
vendor/codeberg.org/gruf/go-cache/v3/README.md
generated
vendored
6
vendor/codeberg.org/gruf/go-cache/v3/README.md
generated
vendored
|
@ -9,9 +9,3 @@ A `cache.Cache{}` implementation with much more of the inner workings exposed. D
|
||||||
## ttl
|
## ttl
|
||||||
|
|
||||||
A `cache.TTLCache{}` implementation with much more of the inner workings exposed. Designed to be used as a base for your own customizations, or used as-is.
|
A `cache.TTLCache{}` implementation with much more of the inner workings exposed. Designed to be used as a base for your own customizations, or used as-is.
|
||||||
|
|
||||||
## result
|
|
||||||
|
|
||||||
`result.Cache` is an example of a more complex cache implementation using `ttl.Cache{}` as its underpinning.
|
|
||||||
|
|
||||||
It provides caching specifically of loadable struct types, with automatic keying by multiple different field members and caching of negative (error) values. All useful when wrapping, for example, a database.
|
|
6
vendor/codeberg.org/gruf/go-kv/format/format.go
generated
vendored
6
vendor/codeberg.org/gruf/go-kv/format/format.go
generated
vendored
|
@ -197,7 +197,8 @@ func (f format) AppendBytes(b []byte) {
|
||||||
|
|
||||||
// Quoted only if spaces/requires escaping
|
// Quoted only if spaces/requires escaping
|
||||||
case f.Key():
|
case f.Key():
|
||||||
f.AppendStringSafe(b2s(b))
|
s := byteutil.B2S(b)
|
||||||
|
f.AppendStringSafe(s)
|
||||||
|
|
||||||
// Append as separate ASCII quoted bytes in slice
|
// Append as separate ASCII quoted bytes in slice
|
||||||
case f.Verbose():
|
case f.Verbose():
|
||||||
|
@ -214,7 +215,8 @@ func (f format) AppendBytes(b []byte) {
|
||||||
|
|
||||||
// Quoted only if spaces/requires escaping
|
// Quoted only if spaces/requires escaping
|
||||||
case f.Value():
|
case f.Value():
|
||||||
f.AppendStringSafe(b2s(b))
|
s := byteutil.B2S(b)
|
||||||
|
f.AppendStringSafe(s)
|
||||||
|
|
||||||
// Append as raw bytes
|
// Append as raw bytes
|
||||||
default:
|
default:
|
||||||
|
|
5
vendor/codeberg.org/gruf/go-kv/format/util.go
generated
vendored
5
vendor/codeberg.org/gruf/go-kv/format/util.go
generated
vendored
|
@ -98,8 +98,3 @@ func isNil(i interface{}) bool {
|
||||||
type eface struct{ _type, data unsafe.Pointer } //nolint
|
type eface struct{ _type, data unsafe.Pointer } //nolint
|
||||||
return (*(*eface)(unsafe.Pointer(&i))).data == nil //nolint
|
return (*(*eface)(unsafe.Pointer(&i))).data == nil //nolint
|
||||||
}
|
}
|
||||||
|
|
||||||
// b2s converts a byteslice to string without allocation.
|
|
||||||
func b2s(b []byte) string {
|
|
||||||
return *(*string)(unsafe.Pointer(&b))
|
|
||||||
}
|
|
||||||
|
|
20
vendor/codeberg.org/gruf/go-maps/common.go
generated
vendored
20
vendor/codeberg.org/gruf/go-maps/common.go
generated
vendored
|
@ -17,7 +17,7 @@ type ordered[K comparable, V any] struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_check panics if map is not in a safe-state to write to.
|
// write_check panics if map is not in a safe-state to write to.
|
||||||
func (m ordered[K, V]) write_check() {
|
func (m *ordered[K, V]) write_check() {
|
||||||
if m.rnly {
|
if m.rnly {
|
||||||
panic("map write during read loop")
|
panic("map write during read loop")
|
||||||
}
|
}
|
||||||
|
@ -54,15 +54,17 @@ func (m *ordered[K, V]) Delete(key K) bool {
|
||||||
|
|
||||||
// Range passes given function over the requested range of the map.
|
// Range passes given function over the requested range of the map.
|
||||||
func (m *ordered[K, V]) Range(start, length int, fn func(int, K, V)) {
|
func (m *ordered[K, V]) Range(start, length int, fn func(int, K, V)) {
|
||||||
|
// Nil check
|
||||||
|
if fn == nil {
|
||||||
|
panic("nil func")
|
||||||
|
}
|
||||||
|
|
||||||
// Disallow writes
|
// Disallow writes
|
||||||
m.rnly = true
|
m.rnly = true
|
||||||
defer func() {
|
defer func() {
|
||||||
m.rnly = false
|
m.rnly = false
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Nil check
|
|
||||||
_ = fn
|
|
||||||
|
|
||||||
switch end := start + length; {
|
switch end := start + length; {
|
||||||
// No loop to iterate
|
// No loop to iterate
|
||||||
case length == 0:
|
case length == 0:
|
||||||
|
@ -104,15 +106,17 @@ func (m *ordered[K, V]) Range(start, length int, fn func(int, K, V)) {
|
||||||
|
|
||||||
// RangeIf passes given function over the requested range of the map. Returns early on 'fn' -> false.
|
// RangeIf passes given function over the requested range of the map. Returns early on 'fn' -> false.
|
||||||
func (m *ordered[K, V]) RangeIf(start, length int, fn func(int, K, V) bool) {
|
func (m *ordered[K, V]) RangeIf(start, length int, fn func(int, K, V) bool) {
|
||||||
|
// Nil check
|
||||||
|
if fn == nil {
|
||||||
|
panic("nil func")
|
||||||
|
}
|
||||||
|
|
||||||
// Disallow writes
|
// Disallow writes
|
||||||
m.rnly = true
|
m.rnly = true
|
||||||
defer func() {
|
defer func() {
|
||||||
m.rnly = false
|
m.rnly = false
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Nil check
|
|
||||||
_ = fn
|
|
||||||
|
|
||||||
switch end := start + length; {
|
switch end := start + length; {
|
||||||
// No loop to iterate
|
// No loop to iterate
|
||||||
case length == 0:
|
case length == 0:
|
||||||
|
@ -163,8 +167,8 @@ func (m *ordered[K, V]) Truncate(sz int, fn func(K, V)) {
|
||||||
panic("index out of bounds")
|
panic("index out of bounds")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nil check
|
||||||
if fn == nil {
|
if fn == nil {
|
||||||
// move nil check out of loop
|
|
||||||
fn = func(K, V) {}
|
fn = func(K, V) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
vendor/modules.txt
vendored
12
vendor/modules.txt
vendored
|
@ -7,8 +7,8 @@ codeberg.org/gruf/go-bytesize
|
||||||
# codeberg.org/gruf/go-byteutil v1.3.0
|
# codeberg.org/gruf/go-byteutil v1.3.0
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
codeberg.org/gruf/go-byteutil
|
codeberg.org/gruf/go-byteutil
|
||||||
# codeberg.org/gruf/go-cache/v3 v3.5.7
|
# codeberg.org/gruf/go-cache/v3 v3.6.1
|
||||||
## explicit; go 1.19
|
## explicit; go 1.20
|
||||||
codeberg.org/gruf/go-cache/v3
|
codeberg.org/gruf/go-cache/v3
|
||||||
codeberg.org/gruf/go-cache/v3/simple
|
codeberg.org/gruf/go-cache/v3/simple
|
||||||
codeberg.org/gruf/go-cache/v3/ttl
|
codeberg.org/gruf/go-cache/v3/ttl
|
||||||
|
@ -31,8 +31,8 @@ codeberg.org/gruf/go-ffmpreg/embed/ffprobe
|
||||||
# codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
# codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
|
||||||
## explicit; go 1.21
|
## explicit; go 1.21
|
||||||
codeberg.org/gruf/go-iotools
|
codeberg.org/gruf/go-iotools
|
||||||
# codeberg.org/gruf/go-kv v1.6.4
|
# codeberg.org/gruf/go-kv v1.6.5
|
||||||
## explicit; go 1.19
|
## explicit; go 1.20
|
||||||
codeberg.org/gruf/go-kv
|
codeberg.org/gruf/go-kv
|
||||||
codeberg.org/gruf/go-kv/format
|
codeberg.org/gruf/go-kv/format
|
||||||
# codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
|
# codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f
|
||||||
|
@ -41,8 +41,8 @@ codeberg.org/gruf/go-list
|
||||||
# codeberg.org/gruf/go-mangler v1.4.1
|
# codeberg.org/gruf/go-mangler v1.4.1
|
||||||
## explicit; go 1.19
|
## explicit; go 1.19
|
||||||
codeberg.org/gruf/go-mangler
|
codeberg.org/gruf/go-mangler
|
||||||
# codeberg.org/gruf/go-maps v1.0.3
|
# codeberg.org/gruf/go-maps v1.0.4
|
||||||
## explicit; go 1.19
|
## explicit; go 1.20
|
||||||
codeberg.org/gruf/go-maps
|
codeberg.org/gruf/go-maps
|
||||||
# codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760
|
# codeberg.org/gruf/go-mempool v0.0.0-20240507125005-cef10d64a760
|
||||||
## explicit; go 1.22.2
|
## explicit; go 1.22.2
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
theme-title: Solarized (dark)
|
theme-title: Solarized dark
|
||||||
theme-description: Solarized sloth (dark)
|
theme-description: Dark green and grey solarized theme with red trim
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -46,18 +46,14 @@
|
||||||
--blue3: var(--base1);
|
--blue3: var(--base1);
|
||||||
|
|
||||||
/* Basic page styling (background + foreground) */
|
/* Basic page styling (background + foreground) */
|
||||||
--bg: var(--white1);
|
--bg: var(--base03);
|
||||||
--bg-accent: var(--white2);
|
--bg-accent: var(--base02);
|
||||||
--fg-reduced: var(--base0);
|
--fg-reduced: var(--base0);
|
||||||
--fg: var(--base1);
|
--fg: var(--base1);
|
||||||
|
|
||||||
/* Profile page styling */
|
/* Profile page styling */
|
||||||
--profile-bg: var(--white2);
|
--profile-bg: var(--white2);
|
||||||
|
|
||||||
/* Solarize buttons */
|
|
||||||
--button-bg: var(--blue2);
|
|
||||||
--button-fg: var(--white1);
|
|
||||||
|
|
||||||
/* Solarize statuses */
|
/* Solarize statuses */
|
||||||
--status-bg: var(--white1);
|
--status-bg: var(--white1);
|
||||||
--status-focus-bg: var(--white1);
|
--status-focus-bg: var(--white1);
|
||||||
|
@ -65,7 +61,7 @@
|
||||||
--status-focus-info-bg: var(--white2);
|
--status-focus-info-bg: var(--white2);
|
||||||
|
|
||||||
/* Used around statuses + other items */
|
/* Used around statuses + other items */
|
||||||
--boxshadow-border: 0.15rem solid var(--base01);
|
--boxshadow-border: 0.1rem solid var(--base01);
|
||||||
|
|
||||||
--plyr-video-control-color: var(--fg);
|
--plyr-video-control-color: var(--fg);
|
||||||
--plyr-video-control-color-hover: var(--fg-reduced);
|
--plyr-video-control-color-hover: var(--fg-reduced);
|
||||||
|
@ -84,6 +80,32 @@ html, body {
|
||||||
scrollbar-color: var(--orange2) var(--white1) ;
|
scrollbar-color: var(--orange2) var(--white1) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Column headers */
|
||||||
|
.col-header {
|
||||||
|
border: var(--boxshadow-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile .about-user .col-header {
|
||||||
|
border-bottom: none;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header card */
|
||||||
|
.profile .profile-header {
|
||||||
|
border: var(--boxshadow-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fiddle around with borders on about sections */
|
||||||
|
.profile .about-user .fields,
|
||||||
|
.profile .about-user .bio,
|
||||||
|
.profile .about-user .accountstats {
|
||||||
|
border-left: var(--boxshadow-border);
|
||||||
|
border-right: var(--boxshadow-border);
|
||||||
|
}
|
||||||
|
.profile .about-user .accountstats {
|
||||||
|
border-bottom: var(--boxshadow-border);
|
||||||
|
}
|
||||||
|
|
||||||
/* Profile fields */
|
/* Profile fields */
|
||||||
.profile .about-user .fields .field {
|
.profile .about-user .fields .field {
|
||||||
border-bottom: var(--boxshadow-border);
|
border-bottom: var(--boxshadow-border);
|
||||||
|
@ -98,6 +120,7 @@ html, body {
|
||||||
}
|
}
|
||||||
.status .media .media-wrapper details .unknown-attachment .placeholder {
|
.status .media .media-wrapper details .unknown-attachment .placeholder {
|
||||||
color: var(--base01);
|
color: var(--base01);
|
||||||
|
border: 0.2rem dashed var(--base01);
|
||||||
}
|
}
|
||||||
.status .media .media-wrapper details video.plyr-video {
|
.status .media .media-wrapper details video.plyr-video {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
@ -143,10 +166,10 @@ button, .button,
|
||||||
|
|
||||||
/* Ensure role badge readable */
|
/* Ensure role badge readable */
|
||||||
.profile .profile-header .basic-info .namerole .role.admin {
|
.profile .profile-header .basic-info .namerole .role.admin {
|
||||||
color: var(--base03);
|
color: var(--base0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.col-header a {
|
/* Distinguish bot icon from background */
|
||||||
font-size: 1.2rem;
|
.profile .profile-header .basic-info .namerole .bot-username-wrapper .bot-legend-wrapper {
|
||||||
font-weight: bold;
|
border: var(--boxshadow-border);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
theme-title: Solarized (dark)
|
theme-title: Solarized light
|
||||||
theme-description: Solarized sloth (dark)
|
theme-description: Beige and grey solarized theme with orange trim
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -46,18 +46,14 @@
|
||||||
--blue3: var(--base01);
|
--blue3: var(--base01);
|
||||||
|
|
||||||
/* Basic page styling (background + foreground) */
|
/* Basic page styling (background + foreground) */
|
||||||
--bg: var(--white1);
|
--bg: var(--base2);
|
||||||
--bg-accent: var(--white2);
|
--bg-accent: var(--base3);
|
||||||
--fg-reduced: var(--base00);
|
--fg-reduced: var(--base00);
|
||||||
--fg: var(--base01);
|
--fg: var(--base01);
|
||||||
|
|
||||||
/* Profile page styling */
|
/* Profile page styling */
|
||||||
--profile-bg: var(--white2);
|
--profile-bg: var(--white2);
|
||||||
|
|
||||||
/* Solarize buttons */
|
|
||||||
--button-bg: var(--blue2);
|
|
||||||
--button-fg: var(--white1);
|
|
||||||
|
|
||||||
/* Solarize statuses */
|
/* Solarize statuses */
|
||||||
--status-bg: var(--white1);
|
--status-bg: var(--white1);
|
||||||
--status-focus-bg: var(--white1);
|
--status-focus-bg: var(--white1);
|
||||||
|
@ -65,7 +61,7 @@
|
||||||
--status-focus-info-bg: var(--white2);
|
--status-focus-info-bg: var(--white2);
|
||||||
|
|
||||||
/* Used around statuses + other items */
|
/* Used around statuses + other items */
|
||||||
--boxshadow-border: 0.15rem solid var(--base1);
|
--boxshadow-border: 0.1rem solid var(--base1);
|
||||||
|
|
||||||
--plyr-video-control-color: var(--fg);
|
--plyr-video-control-color: var(--fg);
|
||||||
--plyr-video-control-color-hover: var(--fg-reduced);
|
--plyr-video-control-color-hover: var(--fg-reduced);
|
||||||
|
@ -84,6 +80,36 @@ html, body {
|
||||||
scrollbar-color: var(--orange2) var(--white1) ;
|
scrollbar-color: var(--orange2) var(--white1) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Column headers */
|
||||||
|
.col-header {
|
||||||
|
border: var(--boxshadow-border);
|
||||||
|
background: var(--base3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile .about-user .col-header {
|
||||||
|
border-bottom: none;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header card */
|
||||||
|
.profile .profile-header {
|
||||||
|
border: var(--boxshadow-border);
|
||||||
|
background: var(--base3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fiddle around with borders on about sections */
|
||||||
|
.profile .about-user .fields,
|
||||||
|
.profile .about-user .bio,
|
||||||
|
.profile .about-user .accountstats {
|
||||||
|
background: var(--base3);
|
||||||
|
color: var(--base01);
|
||||||
|
border-left: var(--boxshadow-border);
|
||||||
|
border-right: var(--boxshadow-border);
|
||||||
|
}
|
||||||
|
.profile .about-user .accountstats {
|
||||||
|
border-bottom: var(--boxshadow-border);
|
||||||
|
}
|
||||||
|
|
||||||
/* Profile fields */
|
/* Profile fields */
|
||||||
.profile .about-user .fields .field {
|
.profile .about-user .fields .field {
|
||||||
border-bottom: var(--boxshadow-border);
|
border-bottom: var(--boxshadow-border);
|
||||||
|
@ -98,6 +124,7 @@ html, body {
|
||||||
}
|
}
|
||||||
.status .media .media-wrapper details .unknown-attachment .placeholder {
|
.status .media .media-wrapper details .unknown-attachment .placeholder {
|
||||||
color: var(--base1);
|
color: var(--base1);
|
||||||
|
border: 0.2rem dashed var(--base1);
|
||||||
}
|
}
|
||||||
.status .media .media-wrapper details video.plyr-video {
|
.status .media .media-wrapper details video.plyr-video {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
@ -105,10 +132,12 @@ html, body {
|
||||||
|
|
||||||
/* Status polls */
|
/* Status polls */
|
||||||
.status .text .poll {
|
.status .text .poll {
|
||||||
background-color: var(--white2);
|
background-color: var(--base3);
|
||||||
|
border: var(--boxshadow-border);
|
||||||
}
|
}
|
||||||
.status .text .poll .poll-info {
|
.status .text .poll .poll-info {
|
||||||
background-color: var(--white1);
|
background-color: var(--base3);
|
||||||
|
border: var(--boxshadow-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Code snippets */
|
/* Code snippets */
|
||||||
|
@ -121,7 +150,7 @@ code, code[class*="language-"] {
|
||||||
/* Block quotes */
|
/* Block quotes */
|
||||||
blockquote {
|
blockquote {
|
||||||
background-color: var(--base3);
|
background-color: var(--base3);
|
||||||
color: var(--base00);
|
color: var(--base01);
|
||||||
}
|
}
|
||||||
|
|
||||||
button, .button,
|
button, .button,
|
||||||
|
@ -131,22 +160,32 @@ button, .button,
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
color: var(--base01);
|
color: var(--base01);
|
||||||
background: var(--base2);
|
background: var(--base3);
|
||||||
border: var(--boxshadow-border);
|
border: var(--boxshadow-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:hover {
|
.button:hover {
|
||||||
color: var(--base00);
|
color: var(--base01);
|
||||||
background: var(--base3);
|
background: var(--base2);
|
||||||
border: var(--boxshadow-border);
|
border: var(--boxshadow-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure role badge readable */
|
/* Ensure role badge readable */
|
||||||
.profile .profile-header .basic-info .namerole .role.admin {
|
.profile .profile-header .basic-info .namerole .role.admin {
|
||||||
color: var(--base3);
|
background: var(--base3);
|
||||||
|
color: var(--base01);
|
||||||
}
|
}
|
||||||
|
|
||||||
.col-header a {
|
/* Back + next links */
|
||||||
font-size: 1.2rem;
|
.backnextlinks {
|
||||||
font-weight: bold;
|
padding: 0.5rem;
|
||||||
|
background: var(--base3);
|
||||||
|
border: var(--boxshadow-border);
|
||||||
|
border-radius: var(--br);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-footer {
|
||||||
|
margin-top: 2rem;
|
||||||
|
background-color: var(--base3);
|
||||||
|
border-top: var(--boxshadow-border);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ export interface InstanceV1 {
|
||||||
description_text?: string;
|
description_text?: string;
|
||||||
short_description: string;
|
short_description: string;
|
||||||
short_description_text?: string;
|
short_description_text?: string;
|
||||||
|
custom_css: string;
|
||||||
email: string;
|
email: string;
|
||||||
version: string;
|
version: string;
|
||||||
debug?: boolean;
|
debug?: boolean;
|
||||||
|
|
|
@ -46,7 +46,7 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) {
|
||||||
const shortDescLimit = 500;
|
const shortDescLimit = 500;
|
||||||
const descLimit = 5000;
|
const descLimit = 5000;
|
||||||
const termsLimit = 5000;
|
const termsLimit = 5000;
|
||||||
|
|
||||||
const form = {
|
const form = {
|
||||||
title: useTextInput("title", {
|
title: useTextInput("title", {
|
||||||
source: instance,
|
source: instance,
|
||||||
|
@ -66,6 +66,10 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) {
|
||||||
valueSelector: (s: InstanceV1) => s.description_text,
|
valueSelector: (s: InstanceV1) => s.description_text,
|
||||||
validator: (val: string) => val.length <= descLimit ? "" : `Instance description is ${val.length} characters; must be ${descLimit} characters or less`
|
validator: (val: string) => val.length <= descLimit ? "" : `Instance description is ${val.length} characters; must be ${descLimit} characters or less`
|
||||||
}),
|
}),
|
||||||
|
customCSS: useTextInput("custom_css", {
|
||||||
|
source: instance,
|
||||||
|
valueSelector: (s: InstanceV1) => s.custom_css
|
||||||
|
}),
|
||||||
terms: useTextInput("terms", {
|
terms: useTextInput("terms", {
|
||||||
source: instance,
|
source: instance,
|
||||||
// Select "raw" text version of parsed field for editing.
|
// Select "raw" text version of parsed field for editing.
|
||||||
|
@ -191,7 +195,16 @@ function InstanceSettingsForm({ data: instance }: InstanceSettingsFormProps) {
|
||||||
type="email"
|
type="email"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TextArea
|
||||||
|
field={form.customCSS}
|
||||||
|
label={"Custom CSS"}
|
||||||
|
className="monospace"
|
||||||
|
rows={8}
|
||||||
|
autoCapitalize="none"
|
||||||
|
spellCheck="false"
|
||||||
|
/>
|
||||||
|
|
||||||
<MutationButton label="Save" result={result} disabled={false} />
|
<MutationButton label="Save" result={result} disabled={false} />
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue