Compare commits

...

6 commits

Author SHA1 Message Date
Daenney bdd24c5126
Merge 9acf9ddc75 into 8a93300ac4 2024-10-21 09:47:33 -07:00
tobi 8a93300ac4
[feature] Add image descriptions for default avatar + header; don't allow editing default desc (#3473) 2024-10-21 14:04:50 +02:00
dependabot[bot] e9299e1174
[chore]: Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5 (#3469)
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.4 to 1.20.5.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.4...v1.20.5)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 11:40:19 +02:00
dependabot[bot] f301ec65f1
[chore]: Bump github.com/tdewolff/minify/v2 from 2.20.37 to 2.21.0 (#3468)
Bumps [github.com/tdewolff/minify/v2](https://github.com/tdewolff/minify) from 2.20.37 to 2.21.0.
- [Release notes](https://github.com/tdewolff/minify/releases)
- [Commits](https://github.com/tdewolff/minify/compare/v2.20.37...v2.21.0)

---
updated-dependencies:
- dependency-name: github.com/tdewolff/minify/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 11:39:43 +02:00
dependabot[bot] ea1bf5f8a3
[chore]: Bump github.com/yuin/goldmark from 1.7.6 to 1.7.8 (#3470)
Bumps [github.com/yuin/goldmark](https://github.com/yuin/goldmark) from 1.7.6 to 1.7.8.
- [Release notes](https://github.com/yuin/goldmark/releases)
- [Commits](https://github.com/yuin/goldmark/compare/v1.7.6...v1.7.8)

---
updated-dependencies:
- dependency-name: github.com/yuin/goldmark
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 11:37:00 +02:00
Daenney 9acf9ddc75 [docs] Set the right site_url
Though the entry point is docs.gotosocial.org, that's redirected by RTD
to docs.gotosocial.org/en/latest/ which is where the actual site is
served from. However, other URLs like docs.gotosocial.org/admin aren't
redirected to docs.gotosocial.org/en/latest/admin. They just 404.

Without us including the /en/latest/ all the generated og:img URLs as
well as the link rel=canonical result in URLs that all 404.

This means that currently the social cards aren't working well, but
indexing the docs site by search engines is probably also partially
broken, since our sitemap.xml is also pointing at things that don't
exist.
2024-07-02 16:30:18 +02:00
39 changed files with 733 additions and 82 deletions

View file

@ -206,6 +206,13 @@ definitions:
example: A cute drawing of a smiling sloth.
type: string
x-go-name: AvatarDescription
avatar_media_id:
description: |-
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
type: string
x-go-name: AvatarMediaID
avatar_static:
description: |-
Web location of a static version of the account's avatar.
@ -277,6 +284,13 @@ definitions:
example: A sunlit field with purple flowers.
type: string
x-go-name: HeaderDescription
header_media_id:
description: |-
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
type: string
x-go-name: HeaderMediaID
header_static:
description: |-
Web location of a static version of the account's header.
@ -2211,6 +2225,13 @@ definitions:
example: A cute drawing of a smiling sloth.
type: string
x-go-name: AvatarDescription
avatar_media_id:
description: |-
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
type: string
x-go-name: AvatarMediaID
avatar_static:
description: |-
Web location of a static version of the account's avatar.
@ -2282,6 +2303,13 @@ definitions:
example: A sunlit field with purple flowers.
type: string
x-go-name: HeaderDescription
header_media_id:
description: |-
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
type: string
x-go-name: HeaderMediaID
header_static:
description: |-
Web location of a static version of the account's header.

8
go.mod
View file

@ -46,14 +46,14 @@ require (
github.com/mitchellh/mapstructure v1.5.0
github.com/ncruces/go-sqlite3 v0.19.0
github.com/oklog/ulid v1.3.1
github.com/prometheus/client_golang v1.20.4
github.com/prometheus/client_golang v1.20.5
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
github.com/superseriousbusiness/activity v1.9.0-gts
github.com/superseriousbusiness/httpsig v1.2.0-SSB
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8
github.com/tdewolff/minify/v2 v2.20.37
github.com/tdewolff/minify/v2 v2.21.0
github.com/technologize/otel-go-contrib v1.1.1
github.com/tetratelabs/wazero v1.8.1
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
@ -63,7 +63,7 @@ require (
github.com/uptrace/bun/dialect/sqlitedialect v1.2.1
github.com/uptrace/bun/extra/bunotel v1.2.1
github.com/wagslane/go-password-validator v0.3.0
github.com/yuin/goldmark v1.7.6
github.com/yuin/goldmark v1.7.8
go.opentelemetry.io/otel v1.29.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0
@ -197,7 +197,7 @@ require (
github.com/subosito/gotenv v1.6.0 // indirect
github.com/superseriousbusiness/go-jpeg-image-structure/v2 v2.0.0-20220321154430-d89a106fdabe // indirect
github.com/superseriousbusiness/go-png-image-structure/v2 v2.0.1-SSB // indirect
github.com/tdewolff/parse/v2 v2.7.15 // indirect
github.com/tdewolff/parse/v2 v2.7.17 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/toqueteos/webbrowser v1.2.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect

16
go.sum generated
View file

@ -462,8 +462,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
@ -539,10 +539,10 @@ github.com/superseriousbusiness/httpsig v1.2.0-SSB h1:BinBGKbf2LSuVT5+MuH0XynHN9
github.com/superseriousbusiness/httpsig v1.2.0-SSB/go.mod h1:+rxfATjFaDoDIVaJOTSP0gj6UrbicaYPEptvCLC9F28=
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8 h1:nTIhuP157oOFcscuoK1kCme1xTeGIzztSw70lX9NrDQ=
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8/go.mod h1:uYC/W92oVRJ49Vh1GcvTqpeFqHi+Ovrl2sMllQWRAEo=
github.com/tdewolff/minify/v2 v2.20.37 h1:Q97cx4STXCh1dlWDlNHZniE8BJ2EBL0+2b0n92BJQhw=
github.com/tdewolff/minify/v2 v2.20.37/go.mod h1:L1VYef/jwKw6Wwyk5A+T0mBjjn3mMPgmjjA688RNsxU=
github.com/tdewolff/parse/v2 v2.7.15 h1:hysDXtdGZIRF5UZXwpfn3ZWRbm+ru4l53/ajBRGpCTw=
github.com/tdewolff/parse/v2 v2.7.15/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
github.com/tdewolff/minify/v2 v2.21.0 h1:nAPP1UVx0aK1xsQh/JiG3xyEnnqWw+agPstn+V6Pkto=
github.com/tdewolff/minify/v2 v2.21.0/go.mod h1:hGcthJ6Vj51NG+9QRIfN/DpWj5loHnY3bfhThzWWq08=
github.com/tdewolff/parse/v2 v2.7.17 h1:uC10p6DaQQORDy72eaIyD+AvAkaIUOouQ0nWp4uD0D0=
github.com/tdewolff/parse/v2 v2.7.17/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
@ -621,8 +621,8 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.6 h1:cZgJxVh5mL5cu8KOnwxvFJy5TFB0BHUskZZyq7TYbDg=
github.com/yuin/goldmark v1.7.6/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.33.1-concurrency-workaround h1:pFMJnlc1PuH+jcVz4vz53vcpnoZG+NqFBr3qikDmEB4=
gitlab.com/NyaaaWhatsUpDoc/sqlite v1.33.1-concurrency-workaround/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k=
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=

View file

@ -96,6 +96,7 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -154,6 +155,7 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -208,6 +210,7 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,
@ -252,9 +255,11 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -302,6 +307,7 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,
@ -348,6 +354,7 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 1,
@ -393,6 +400,7 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -439,6 +447,7 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"header": "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/original/01PFPMWK2FF0D9WMHEJHR07C3R.jpg",
"header_static": "http://localhost:8080/fileserver/062G5WYKY35KKD12EMSM3F8PJ8/header/small/01PFPMWK2FF0D9WMHEJHR07C3R.webp",
"header_description": "tweet from thoughts of dog: i drank. all the water. in my bowl. earlier. but just now. i returned. to the same bowl. and it was. full again.. the bowl. is haunted",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3R",
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,
@ -484,6 +493,7 @@ func (suite *AccountsGetTestSuite) TestAccountsGetFromTop() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,
@ -568,6 +578,7 @@ func (suite *AccountsGetTestSuite) TestAccountsMinID() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,

View file

@ -183,6 +183,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -228,6 +229,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -286,6 +288,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -340,6 +343,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -407,6 +411,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -465,6 +470,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -512,6 +518,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -657,6 +664,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetCreatedByAccount() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -715,6 +723,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetCreatedByAccount() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -762,6 +771,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetCreatedByAccount() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -907,6 +917,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetTargetAccount() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -965,6 +976,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetTargetAccount() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -1012,6 +1024,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetTargetAccount() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,

View file

@ -97,6 +97,7 @@ func (suite *GetTestSuite) TestGet() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 1,

View file

@ -174,6 +174,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch1() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -314,6 +315,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch2() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -454,6 +456,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch3() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -645,6 +648,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch6() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -811,6 +815,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -988,6 +993,7 @@ func (suite *InstancePatchTestSuite) TestInstancePatch9() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,

View file

@ -148,7 +148,7 @@ func (suite *MutesTestSuite) TestIndefinitelyMutedAccountSerializesMuteExpiratio
// Fetch all muted accounts for the logged-in account.
// The expected body contains `"mute_expires_at":null`.
_, err = suite.getMutedAccounts(http.StatusOK, `[{"id":"01F8MH5ZK5VRH73AKHQM6Y9VNX","username":"foss_satan","acct":"foss_satan@fossbros-anonymous.io","display_name":"big gerald","locked":false,"discoverable":true,"bot":false,"created_at":"2021-09-26T10:52:36.000Z","note":"i post about like, i dunno, stuff, or whatever!!!!","url":"http://fossbros-anonymous.io/@foss_satan","avatar":"","avatar_static":"","header":"http://localhost:8080/assets/default_header.webp","header_static":"http://localhost:8080/assets/default_header.webp","followers_count":0,"following_count":0,"statuses_count":3,"last_status_at":"2021-09-11","emojis":[],"fields":[],"mute_expires_at":null}]`)
_, err = suite.getMutedAccounts(http.StatusOK, `[{"id":"01F8MH5ZK5VRH73AKHQM6Y9VNX","username":"foss_satan","acct":"foss_satan@fossbros-anonymous.io","display_name":"big gerald","locked":false,"discoverable":true,"bot":false,"created_at":"2021-09-26T10:52:36.000Z","note":"i post about like, i dunno, stuff, or whatever!!!!","url":"http://fossbros-anonymous.io/@foss_satan","avatar":"","avatar_static":"","header":"http://localhost:8080/assets/default_header.webp","header_static":"http://localhost:8080/assets/default_header.webp","header_description":"Flat gray background (default header).","followers_count":0,"following_count":0,"statuses_count":3,"last_status_at":"2021-09-11","emojis":[],"fields":[],"mute_expires_at":null}]`)
if err != nil {
suite.FailNow(err.Error())
}

View file

@ -127,6 +127,7 @@ func (suite *ReportGetTestSuite) TestGetReport1() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,

View file

@ -153,6 +153,7 @@ func (suite *ReportsGetTestSuite) TestGetReports() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -243,6 +244,7 @@ func (suite *ReportsGetTestSuite) TestGetReports4() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -317,6 +319,7 @@ func (suite *ReportsGetTestSuite) TestGetReports6() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -375,6 +378,7 @@ func (suite *ReportsGetTestSuite) TestGetReports7() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,

View file

@ -109,9 +109,11 @@ func (suite *StatusHistoryTestSuite) TestGetHistory() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,

View file

@ -127,9 +127,11 @@ func (suite *StatusMuteTestSuite) TestMuteUnmuteStatus() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -212,9 +214,11 @@ func (suite *StatusMuteTestSuite) TestMuteUnmuteStatus() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,

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,6 +82,10 @@ 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.

View file

@ -76,6 +76,7 @@ func (suite *NotificationTestSuite) TestStreamNotification() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,

View file

@ -87,6 +87,7 @@ func (suite *StatusUpdateTestSuite) TestStreamNotification() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,

View file

@ -117,6 +117,9 @@ func (c *Converter) ensureAvatar(account *apimodel.Account) {
account.Avatar = avatar
account.AvatarStatic = avatar
const defaultAviDesc = "Grayed-out line drawing of a cute sloth (default avatar)."
account.AvatarDescription = defaultAviDesc
}
// ensureHeader ensures that the given account has a value set
@ -134,4 +137,7 @@ func (c *Converter) ensureHeader(account *apimodel.Account) {
h := config.GetProtocol() + "://" + config.GetHost() + defaultHeaderPath
account.Header = h
account.HeaderStatic = h
const defaultHeaderDesc = "Flat gray background (default header)."
account.HeaderDescription = defaultHeaderDesc
}

View file

@ -270,21 +270,25 @@ func (c *Converter) accountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
// - Emojis
var (
aviID string
aviURL string
aviURLStatic string
aviDesc string
headerID string
headerURL string
headerURLStatic string
headerDesc string
)
if a.AvatarMediaAttachment != nil {
aviID = a.AvatarMediaAttachmentID
aviURL = a.AvatarMediaAttachment.URL
aviURLStatic = a.AvatarMediaAttachment.Thumbnail.URL
aviDesc = a.AvatarMediaAttachment.Description
}
if a.HeaderMediaAttachment != nil {
headerID = a.HeaderMediaAttachmentID
headerURL = a.HeaderMediaAttachment.URL
headerURLStatic = a.HeaderMediaAttachment.Thumbnail.URL
headerDesc = a.HeaderMediaAttachment.Description
@ -367,9 +371,11 @@ func (c *Converter) accountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
Avatar: aviURL,
AvatarStatic: aviURLStatic,
AvatarDescription: aviDesc,
AvatarMediaID: aviID,
Header: headerURL,
HeaderStatic: headerURLStatic,
HeaderDescription: headerDesc,
HeaderMediaID: headerID,
FollowersCount: followersCount,
FollowingCount: followingCount,
StatusesCount: statusesCount,

View file

@ -60,9 +60,11 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontend() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -110,9 +112,11 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendAliasedAndMoved()
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -155,6 +159,7 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendAliasedAndMoved()
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -205,9 +210,11 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendWithEmojiStruct()
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -252,9 +259,11 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendWithEmojiIDs() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -295,9 +304,11 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendSensitive() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -352,6 +363,7 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendPublicPunycode()
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,
@ -390,6 +402,7 @@ func (suite *InternalToFrontendTestSuite) TestLocalInstanceAccountToFrontendPubl
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,
@ -428,6 +441,7 @@ func (suite *InternalToFrontendTestSuite) TestLocalInstanceAccountToFrontendBloc
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,
@ -486,6 +500,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontend() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -663,6 +678,7 @@ func (suite *InternalToFrontendTestSuite) TestWarnFilteredStatusToFrontend() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -847,9 +863,11 @@ func (suite *InternalToFrontendTestSuite) TestWarnFilteredBoostToFrontend() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -977,6 +995,7 @@ func (suite *InternalToFrontendTestSuite) TestWarnFilteredBoostToFrontend() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -1232,6 +1251,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownAttachments
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 1,
@ -1395,6 +1415,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToWebStatus() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 1,
@ -1527,6 +1548,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownLanguage()
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -1668,9 +1690,11 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendPartialInteraction
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -1777,6 +1801,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToAPIStatusPendingApproval()
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -1987,6 +2012,7 @@ func (suite *InternalToFrontendTestSuite) TestInstanceV1ToFrontend() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -2127,6 +2153,7 @@ func (suite *InternalToFrontendTestSuite) TestInstanceV2ToFrontend() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -2247,6 +2274,7 @@ func (suite *InternalToFrontendTestSuite) TestReportToFrontend1() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -2290,6 +2318,7 @@ func (suite *InternalToFrontendTestSuite) TestReportToFrontend2() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -2366,6 +2395,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend1() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -2411,6 +2441,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend1() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -2469,6 +2500,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend1() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -2523,6 +2555,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend1() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -2600,6 +2633,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend2() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -2658,6 +2692,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend2() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -2705,6 +2740,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend2() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -2863,6 +2899,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontendSuspendedLoca
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 3,
@ -2908,6 +2945,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontendSuspendedLoca
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 0,
"following_count": 0,
"statuses_count": 0,
@ -2955,6 +2993,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontendSuspendedLoca
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -3009,6 +3048,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontendSuspendedLoca
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -3155,6 +3195,7 @@ func (suite *InternalToFrontendTestSuite) TestIntReqToAPI() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -3210,6 +3251,7 @@ func (suite *InternalToFrontendTestSuite) TestIntReqToAPI() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -3302,6 +3344,7 @@ func (suite *InternalToFrontendTestSuite) TestIntReqToAPI() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 4,
@ -3414,9 +3457,11 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPISelfConvo() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -3465,9 +3510,11 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPISelfConvo() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,
@ -3569,6 +3616,7 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPI() {
"avatar_static": "",
"header": "http://localhost:8080/assets/default_header.webp",
"header_static": "http://localhost:8080/assets/default_header.webp",
"header_description": "Flat gray background (default header).",
"followers_count": 1,
"following_count": 1,
"statuses_count": 8,
@ -3628,9 +3676,11 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPI() {
"avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
"avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
"avatar_description": "a green goblin looking nasty",
"avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
"header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
"header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
"header_description": "A very old-school screenshot of the original team fortress mod for quake",
"header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
"followers_count": 2,
"following_count": 2,
"statuses_count": 8,

View file

@ -1,5 +1,5 @@
site_name: GoToSocial Documentation
site_url: https://docs.gotosocial.org
site_url: https://docs.gotosocial.org/en/latest/
theme:
name: material
language: en

View file

@ -199,7 +199,7 @@ func (o *Minifier) Minify(m *minify.M, w io.Writer, r io.Reader, _ map[string]st
} else if next.TokenType == html.TextToken && !parse.IsAllWhitespace(next.Data) {
// stop looking when text encountered
break
} else if next.TokenType == html.StartTagToken || next.TokenType == html.EndTagToken {
} else if next.TokenType == html.StartTagToken || next.TokenType == html.EndTagToken || next.TokenType == html.SvgToken || next.TokenType == html.MathToken {
if o.KeepWhitespace {
break
}
@ -208,7 +208,7 @@ func (o *Minifier) Minify(m *minify.M, w io.Writer, r io.Reader, _ map[string]st
t.Data = t.Data[:len(t.Data)-1]
omitSpace = false
break
} else if next.TokenType == html.StartTagToken {
} else if next.TokenType == html.StartTagToken || next.TokenType == html.SvgToken || next.TokenType == html.MathToken {
break
}
}
@ -309,7 +309,7 @@ func (o *Minifier) Minify(m *minify.M, w io.Writer, r io.Reader, _ map[string]st
// skip text in select and optgroup tags
if t.Hash == Option || t.Hash == Optgroup {
if next := tb.Peek(0); next.TokenType == html.TextToken {
if next := tb.Peek(0); next.TokenType == html.TextToken && !next.HasTemplate {
tb.Shift()
}
}

View file

@ -74,7 +74,7 @@
Input: objectTag,
Ins: keepPTag,
Kbd: normalTag,
Label: normalTag,
Label: normalTag | keepPTag, // experimentally, keepPTag is needed
Legend: blockTag,
Li: blockTag,
Link: normalTag,
@ -125,7 +125,7 @@
Th: blockTag,
Thead: blockTag,
Time: normalTag,
Title: normalTag,
Title: blockTag,
Tr: blockTag,
Track: normalTag,
U: normalTag,

View file

@ -2,12 +2,15 @@
import (
"encoding/binary"
"errors"
"fmt"
"io"
"math"
"os"
)
const PageSize = 4096
// BinaryReader is a binary big endian file format reader.
type BinaryReader struct {
Endianness binary.ByteOrder
@ -330,6 +333,320 @@ func (r *BinaryFileReader) ReadInt64() int64 {
return int64(r.ReadUint64())
}
type IBinaryReader interface {
Close() error
Len() int
Bytes(int, int64) ([]byte, error)
}
type binaryReaderFile struct {
f *os.File
size int64
}
func newBinaryReaderFile(filename string) (*binaryReaderFile, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
fi, err := f.Stat()
if err != nil {
f.Close()
return nil, err
}
return &binaryReaderFile{f, fi.Size()}, nil
}
// Close closes the reader.
func (r *binaryReaderFile) Close() error {
return r.f.Close()
}
// Len returns the length of the underlying memory-mapped file.
func (r *binaryReaderFile) Len() int {
return int(r.size)
}
func (r *binaryReaderFile) Bytes(n int, off int64) ([]byte, error) {
if _, err := r.f.Seek(off, 0); err != nil {
return nil, err
}
b := make([]byte, n)
m, err := r.f.Read(b)
if err != nil {
return nil, err
} else if m != n {
return nil, errors.New("file: could not read all bytes")
}
return b, nil
}
type binaryReaderBytes struct {
data []byte
}
func newBinaryReaderBytes(data []byte) (*binaryReaderBytes, error) {
return &binaryReaderBytes{data}, nil
}
// Close closes the reader.
func (r *binaryReaderBytes) Close() error {
return nil
}
// Len returns the length of the underlying memory-mapped file.
func (r *binaryReaderBytes) Len() int {
return len(r.data)
}
func (r *binaryReaderBytes) Bytes(n int, off int64) ([]byte, error) {
if off < 0 || int64(len(r.data)) < off {
return nil, fmt.Errorf("bytes: invalid offset %d", off)
}
return r.data[off : off+int64(n) : off+int64(n)], nil
}
type binaryReaderReader struct {
r io.Reader
n int64
readerAt bool
seeker bool
}
func newBinaryReaderReader(r io.Reader, n int64) (*binaryReaderReader, error) {
_, readerAt := r.(io.ReaderAt)
_, seeker := r.(io.Seeker)
return &binaryReaderReader{r, n, readerAt, seeker}, nil
}
// Close closes the reader.
func (r *binaryReaderReader) Close() error {
if closer, ok := r.r.(io.Closer); ok {
return closer.Close()
}
return nil
}
// Len returns the length of the underlying memory-mapped file.
func (r *binaryReaderReader) Len() int {
return int(r.n)
}
func (r *binaryReaderReader) Bytes(n int, off int64) ([]byte, error) {
// seeker seems faster than readerAt by 10%
if r.seeker {
if _, err := r.r.(io.Seeker).Seek(off, 0); err != nil {
return nil, err
}
b := make([]byte, n)
m, err := r.r.Read(b)
if err != nil {
return nil, err
} else if m != n {
return nil, errors.New("file: could not read all bytes")
}
return b, nil
} else if r.readerAt {
b := make([]byte, n)
m, err := r.r.(io.ReaderAt).ReadAt(b, off)
if err != nil {
return nil, err
} else if m != n {
return nil, errors.New("file: could not read all bytes")
}
return b, nil
}
return nil, errors.New("io.Seeker and io.ReaderAt not implemented")
}
type BinaryReader2 struct {
f IBinaryReader
pos int64
err error
Endian binary.ByteOrder
}
func NewBinaryReader2(f IBinaryReader) *BinaryReader2 {
return &BinaryReader2{
f: f,
Endian: binary.BigEndian,
}
}
func NewBinaryReader2Reader(r io.Reader, n int64) (*BinaryReader2, error) {
_, isReaderAt := r.(io.ReaderAt)
_, isSeeker := r.(io.Seeker)
var f IBinaryReader
if isReaderAt || isSeeker {
var err error
f, err = newBinaryReaderReader(r, n)
if err != nil {
return nil, err
}
} else {
b := make([]byte, n)
if _, err := io.ReadFull(r, b); err != nil {
return nil, err
}
f, _ = newBinaryReaderBytes(b)
}
return NewBinaryReader2(f), nil
}
func NewBinaryReader2Bytes(data []byte) (*BinaryReader2, error) {
f, _ := newBinaryReaderBytes(data)
return NewBinaryReader2(f), nil
}
func NewBinaryReader2File(filename string) (*BinaryReader2, error) {
f, err := newBinaryReaderFile(filename)
if err != nil {
return nil, err
}
return NewBinaryReader2(f), nil
}
func NewBinaryReader2Mmap(filename string) (*BinaryReader2, error) {
f, err := newBinaryReaderMmap(filename)
if err != nil {
return nil, err
}
return NewBinaryReader2(f), nil
}
func (r *BinaryReader2) Err() error {
return r.err
}
func (r *BinaryReader2) Close() error {
if err := r.f.Close(); err != nil {
return err
}
return r.err
}
// InPageCache returns true if the range is already in the page cache (for mmap).
func (r *BinaryReader2) InPageCache(start, end int64) bool {
index := int64(r.Pos()) / PageSize
return start/PageSize == index && end/PageSize == index
}
// Free frees all previously read bytes, you cannot seek from before this position (for reader).
func (r *BinaryReader2) Free() {
}
// Pos returns the reader's position.
func (r *BinaryReader2) Pos() int64 {
return r.pos
}
// Len returns the remaining length of the buffer.
func (r *BinaryReader2) Len() int {
return int(int64(r.f.Len()) - int64(r.pos))
}
func (r *BinaryReader2) Seek(pos int64) {
r.pos = pos
}
// Read complies with io.Reader.
func (r *BinaryReader2) Read(b []byte) (int, error) {
data, err := r.f.Bytes(len(b), r.pos)
if err != nil && err != io.EOF {
return 0, err
}
n := copy(b, data)
r.pos += int64(len(b))
return n, err
}
// ReadBytes reads n bytes.
func (r *BinaryReader2) ReadBytes(n int) []byte {
data, err := r.f.Bytes(n, r.pos)
if err != nil {
r.err = err
return nil
}
r.pos += int64(n)
return data
}
// ReadString reads a string of length n.
func (r *BinaryReader2) ReadString(n int) string {
return string(r.ReadBytes(n))
}
// ReadByte reads a single byte.
func (r *BinaryReader2) ReadByte() byte {
data := r.ReadBytes(1)
if data == nil {
return 0
}
return data[0]
}
// ReadUint8 reads a uint8.
func (r *BinaryReader2) ReadUint8() uint8 {
return r.ReadByte()
}
// ReadUint16 reads a uint16.
func (r *BinaryReader2) ReadUint16() uint16 {
data := r.ReadBytes(2)
if data == nil {
return 0
} else if r.Endian == binary.LittleEndian {
return uint16(data[1])<<8 | uint16(data[0])
}
return uint16(data[0])<<8 | uint16(data[1])
}
// ReadUint32 reads a uint32.
func (r *BinaryReader2) ReadUint32() uint32 {
data := r.ReadBytes(4)
if data == nil {
return 0
} else if r.Endian == binary.LittleEndian {
return uint32(data[3])<<24 | uint32(data[2])<<16 | uint32(data[1])<<8 | uint32(data[0])
}
return uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
}
// ReadUint64 reads a uint64.
func (r *BinaryReader2) ReadUint64() uint64 {
data := r.ReadBytes(8)
if data == nil {
return 0
} else if r.Endian == binary.LittleEndian {
return uint64(data[7])<<56 | uint64(data[6])<<48 | uint64(data[5])<<40 | uint64(data[4])<<32 | uint64(data[3])<<24 | uint64(data[2])<<16 | uint64(data[1])<<8 | uint64(data[0])
}
return uint64(data[0])<<56 | uint64(data[1])<<48 | uint64(data[2])<<40 | uint64(data[3])<<32 | uint64(data[4])<<24 | uint64(data[5])<<16 | uint64(data[6])<<8 | uint64(data[7])
}
// ReadInt8 reads a int8.
func (r *BinaryReader2) ReadInt8() int8 {
return int8(r.ReadByte())
}
// ReadInt16 reads a int16.
func (r *BinaryReader2) ReadInt16() int16 {
return int16(r.ReadUint16())
}
// ReadInt32 reads a int32.
func (r *BinaryReader2) ReadInt32() int32 {
return int32(r.ReadUint32())
}
// ReadInt64 reads a int64.
func (r *BinaryReader2) ReadInt64() int64 {
return int64(r.ReadUint64())
}
// BinaryWriter is a big endian binary file format writer.
type BinaryWriter struct {
buf []byte

83
vendor/github.com/tdewolff/parse/v2/binary_unix.go generated vendored Normal file
View file

@ -0,0 +1,83 @@
//go:build unix
package parse
import (
"errors"
"fmt"
"io"
"os"
"runtime"
"syscall"
)
type binaryReaderMmap struct {
data []byte
}
func newBinaryReaderMmap(filename string) (*binaryReaderMmap, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
return nil, err
}
size := fi.Size()
if size == 0 {
// Treat (size == 0) as a special case, avoiding the syscall, since
// "man 2 mmap" says "the length... must be greater than 0".
//
// As we do not call syscall.Mmap, there is no need to call
// runtime.SetFinalizer to enforce a balancing syscall.Munmap.
return &binaryReaderMmap{
data: make([]byte, 0),
}, nil
} else if size < 0 {
return nil, fmt.Errorf("mmap: file %q has negative size", filename)
} else if size != int64(int(size)) {
return nil, fmt.Errorf("mmap: file %q is too large", filename)
}
data, err := syscall.Mmap(int(f.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)
if err != nil {
return nil, err
}
r := &binaryReaderMmap{data}
runtime.SetFinalizer(r, (*binaryReaderMmap).Close)
return r, nil
}
// Close closes the reader.
func (r *binaryReaderMmap) Close() error {
if r.data == nil {
return nil
} else if len(r.data) == 0 {
r.data = nil
return nil
}
data := r.data
r.data = nil
runtime.SetFinalizer(r, nil)
return syscall.Munmap(data)
}
// Len returns the length of the underlying memory-mapped file.
func (r *binaryReaderMmap) Len() int {
return len(r.data)
}
func (r *binaryReaderMmap) Bytes(n int, off int64) ([]byte, error) {
if r.data == nil {
return nil, errors.New("mmap: closed")
} else if off < 0 || int64(len(r.data)) < off {
return nil, fmt.Errorf("mmap: invalid offset %d", off)
} else if int64(len(r.data)-n) < off {
return r.data[off:len(r.data):len(r.data)], io.EOF
}
return r.data[off : off+int64(n) : off+int64(n)], nil
}

View file

@ -362,7 +362,7 @@ func (l *Lexer) shiftBogusComment() []byte {
func (l *Lexer) shiftStartTag() (TokenType, []byte) {
for {
if c := l.r.Peek(0); c == ' ' || c == '>' || c == '/' && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == 0 && l.r.Err() != nil {
if c := l.r.Peek(0); (c < 'a' || 'z' < c) && (c < 'A' || 'Z' < c) && (c < '0' || '9' < c) && c != '-' {
break
}
l.r.Move(1)

View file

@ -123,6 +123,12 @@ type Node interface {
Dump(source []byte, level int)
// Text returns text values of this node.
// This method is valid only for some inline nodes.
// If this node is a block node, Text returns a text value as reasonable as possible.
// Notice that there are no 'correct' text values for the block nodes.
// Result for the block nodes may be different from your expectation.
//
// Deprecated: Use other properties of the node to get the text value(i.e. Pragraph.Lines, Text.Value).
Text(source []byte) []byte
// HasBlankPreviousLines returns true if the row before this node is blank,
@ -374,11 +380,18 @@ func (n *BaseNode) OwnerDocument() *Document {
return nil
}
// Text implements Node.Text .
// Text implements Node.Text .
//
// Deprecated: Use other properties of the node to get the text value(i.e. Pragraph.Lines, Text.Value).
func (n *BaseNode) Text(source []byte) []byte {
var buf bytes.Buffer
for c := n.firstChild; c != nil; c = c.NextSibling() {
buf.Write(c.Text(source))
if sb, ok := c.(interface {
SoftLineBreak() bool
}); ok && sb.SoftLineBreak() {
buf.WriteByte('\n')
}
}
return buf.Bytes()
}

View file

@ -1,7 +1,6 @@
package ast
import (
"bytes"
"fmt"
"strings"
@ -48,15 +47,6 @@ func (b *BaseBlock) SetLines(v *textm.Segments) {
b.lines = v
}
// Text implements Node.Text.
func (b *BaseBlock) Text(source []byte) []byte {
var buf bytes.Buffer
for _, line := range b.Lines().Sliced(0, b.Lines().Len()) {
buf.Write(line.Value(source))
}
return buf.Bytes()
}
// A Document struct is a root node of Markdown text.
type Document struct {
BaseBlock
@ -140,6 +130,13 @@ func (n *TextBlock) Kind() NodeKind {
return KindTextBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. TextBlock.Lines).
func (n *TextBlock) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewTextBlock returns a new TextBlock node.
func NewTextBlock() *TextBlock {
return &TextBlock{
@ -165,6 +162,13 @@ func (n *Paragraph) Kind() NodeKind {
return KindParagraph
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. Paragraph.Lines).
func (n *Paragraph) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewParagraph returns a new Paragraph node.
func NewParagraph() *Paragraph {
return &Paragraph{
@ -259,6 +263,13 @@ func (n *CodeBlock) Kind() NodeKind {
return KindCodeBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. CodeBlock.Lines).
func (n *CodeBlock) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewCodeBlock returns a new CodeBlock node.
func NewCodeBlock() *CodeBlock {
return &CodeBlock{
@ -314,6 +325,13 @@ func (n *FencedCodeBlock) Kind() NodeKind {
return KindFencedCodeBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. FencedCodeBlock.Lines).
func (n *FencedCodeBlock) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewFencedCodeBlock return a new FencedCodeBlock node.
func NewFencedCodeBlock(info *Text) *FencedCodeBlock {
return &FencedCodeBlock{
@ -508,6 +526,17 @@ func (n *HTMLBlock) Kind() NodeKind {
return KindHTMLBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. HTMLBlock.Lines).
func (n *HTMLBlock) Text(source []byte) []byte {
ret := n.Lines().Value(source)
if n.HasClosure() {
ret = append(ret, n.ClosureLine.Value(source)...)
}
return ret
}
// NewHTMLBlock returns a new HTMLBlock node.
func NewHTMLBlock(typ HTMLBlockType) *HTMLBlock {
return &HTMLBlock{

View file

@ -143,17 +143,25 @@ func (n *Text) Merge(node Node, source []byte) bool {
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. Text.Value).
func (n *Text) Text(source []byte) []byte {
return n.Segment.Value(source)
}
// Value returns a value of this node.
// SoftLineBreaks are not included in the returned value.
func (n *Text) Value(source []byte) []byte {
return n.Segment.Value(source)
}
// Dump implements Node.Dump.
func (n *Text) Dump(source []byte, level int) {
fs := textFlagsString(n.flags)
if len(fs) != 0 {
fs = "(" + fs + ")"
}
fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Text(source)), "\n"))
fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Value(source)), "\n"))
}
// KindText is a NodeKind of the Text node.
@ -258,6 +266,8 @@ func (n *String) SetCode(v bool) {
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. String.Value).
func (n *String) Text(source []byte) []byte {
return n.Value
}
@ -492,15 +502,22 @@ func (n *AutoLink) URL(source []byte) []byte {
ret := make([]byte, 0, len(n.Protocol)+s.Len()+3)
ret = append(ret, n.Protocol...)
ret = append(ret, ':', '/', '/')
ret = append(ret, n.value.Text(source)...)
ret = append(ret, n.value.Value(source)...)
return ret
}
return n.value.Text(source)
return n.value.Value(source)
}
// Label returns a label of this node.
func (n *AutoLink) Label(source []byte) []byte {
return n.value.Text(source)
return n.value.Value(source)
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. AutoLink.Label).
func (n *AutoLink) Text(source []byte) []byte {
return n.value.Value(source)
}
// NewAutoLink returns a new AutoLink node.
@ -541,6 +558,13 @@ func (n *RawHTML) Kind() NodeKind {
return KindRawHTML
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. RawHTML.Segments).
func (n *RawHTML) Text(source []byte) []byte {
return n.Segments.Value(source)
}
// NewRawHTML returns a new RawHTML node.
func NewRawHTML() *RawHTML {
return &RawHTML{

View file

@ -35,6 +35,7 @@ func (b *codeBlockParser) Open(parent ast.Node, reader text.Reader, pc Context)
if segment.Padding != 0 {
preserveLeadingTabInCodeBlock(&segment, reader, 0)
}
segment.ForceNewline = true
node.Lines().Append(segment)
reader.Advance(segment.Len() - 1)
return node, NoChildren
@ -59,6 +60,7 @@ func (b *codeBlockParser) Continue(node ast.Node, reader text.Reader, pc Context
preserveLeadingTabInCodeBlock(&segment, reader, 0)
}
segment.ForceNewline = true
node.Lines().Append(segment)
reader.Advance(segment.Len() - 1)
return Continue | NoChildren

View file

@ -100,6 +100,7 @@ func (b *fencedCodeBlockParser) Continue(node ast.Node, reader text.Reader, pc C
if padding != 0 {
preserveLeadingTabInCodeBlock(&seg, reader, fdata.indent)
}
seg.ForceNewline = true // EOF as newline
node.Lines().Append(seg)
reader.AdvanceAndSetPadding(segment.Stop-segment.Start-pos-1, padding)
return Continue | NoChildren

View file

@ -878,12 +878,6 @@ func (p *parser) Parse(reader text.Reader, opts ...ParseOption) ast.Node {
blockReader := text.NewBlockReader(reader.Source(), nil)
p.walkBlock(root, func(node ast.Node) {
p.parseBlock(blockReader, node, pc)
lines := node.Lines()
if lines != nil && lines.Len() != 0 {
s := lines.At(lines.Len() - 1)
s.EOB = true
lines.Set(lines.Len()-1, s)
}
})
for _, at := range p.astTransformers {
at.Transform(root, reader, pc)

View file

@ -680,7 +680,7 @@ func (r *Renderer) renderImage(w util.BufWriter, source []byte, node ast.Node, e
_, _ = w.Write(util.EscapeHTML(util.URLEscape(n.Destination, true)))
}
_, _ = w.WriteString(`" alt="`)
r.renderAttribute(w, source, n)
r.renderTexts(w, source, n)
_ = w.WriteByte('"')
if n.Title != nil {
_, _ = w.WriteString(` title="`)
@ -737,7 +737,7 @@ func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, en
if r.EastAsianLineBreaks != EastAsianLineBreaksNone && len(value) != 0 {
sibling := node.NextSibling()
if sibling != nil && sibling.Kind() == ast.KindText {
if siblingText := sibling.(*ast.Text).Text(source); len(siblingText) != 0 {
if siblingText := sibling.(*ast.Text).Value(source); len(siblingText) != 0 {
thisLastRune := util.ToRune(value, len(value)-1)
siblingFirstRune, _ := utf8.DecodeRune(siblingText)
if r.EastAsianLineBreaks.softLineBreak(thisLastRune, siblingFirstRune) {
@ -770,19 +770,14 @@ func (r *Renderer) renderString(w util.BufWriter, source []byte, node ast.Node,
return ast.WalkContinue, nil
}
func (r *Renderer) renderAttribute(w util.BufWriter, source []byte, n ast.Node) {
func (r *Renderer) renderTexts(w util.BufWriter, source []byte, n ast.Node) {
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
if s, ok := c.(*ast.String); ok {
_, _ = r.renderString(w, source, s, true)
} else if t, ok := c.(*ast.String); ok {
} else if t, ok := c.(*ast.Text); ok {
_, _ = r.renderText(w, source, t, true)
} else if !c.HasChildren() {
r.Writer.Write(w, c.Text(source))
if t, ok := c.(*ast.Text); ok && t.SoftLineBreak() {
_ = w.WriteByte('\n')
}
} else {
r.renderAttribute(w, source, c)
r.renderTexts(w, source, c)
}
}
}

View file

@ -20,8 +20,19 @@ type Segment struct {
// Padding is a padding length of the segment.
Padding int
// EOB is true if the segment is end of the block.
EOB bool
// ForceNewline is true if the segment should be ended with a newline.
// Some elements(i.e. CodeBlock, FencedCodeBlock) does not trim trailing
// newlines. Spec defines that EOF is treated as a newline, so we need to
// add a newline to the end of the segment if it is not empty.
//
// i.e.:
//
// ```go
// const test = "test"
//
// This code does not close the code block and ends with EOF. In this case,
// we need to add a newline to the end of the last line like `const test = "test"\n`.
ForceNewline bool
}
// NewSegment return a new Segment.
@ -52,7 +63,7 @@ func (t *Segment) Value(buffer []byte) []byte {
result = append(result, bytes.Repeat(space, t.Padding)...)
result = append(result, buffer[t.Start:t.Stop]...)
}
if t.EOB && len(result) > 0 && result[len(result)-1] != '\n' {
if t.ForceNewline && len(result) > 0 && result[len(result)-1] != '\n' {
result = append(result, '\n')
}
return result
@ -217,3 +228,12 @@ func (s *Segments) Unshift(v Segment) {
s.values = append(s.values[0:1], s.values[0:]...)
s.values[0] = v
}
// Value returns a string value of the collection.
func (s *Segments) Value(buffer []byte) []byte {
var result []byte
for _, v := range s.values {
result = append(result, v.Value(buffer)...)
}
return result
}

8
vendor/modules.txt vendored
View file

@ -556,7 +556,7 @@ github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
## explicit
github.com/pmezard/go-difflib/difflib
# github.com/prometheus/client_golang v1.20.4
# github.com/prometheus/client_golang v1.20.5
## explicit; go 1.20
github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil
github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/header
@ -832,11 +832,11 @@ github.com/superseriousbusiness/oauth2/v4/generates
github.com/superseriousbusiness/oauth2/v4/manage
github.com/superseriousbusiness/oauth2/v4/models
github.com/superseriousbusiness/oauth2/v4/server
# github.com/tdewolff/minify/v2 v2.20.37
# github.com/tdewolff/minify/v2 v2.21.0
## explicit; go 1.18
github.com/tdewolff/minify/v2
github.com/tdewolff/minify/v2/html
# github.com/tdewolff/parse/v2 v2.7.15
# github.com/tdewolff/parse/v2 v2.7.17
## explicit; go 1.13
github.com/tdewolff/parse/v2
github.com/tdewolff/parse/v2/buffer
@ -954,7 +954,7 @@ github.com/vmihailenco/tagparser/v2/internal/parser
# github.com/wagslane/go-password-validator v0.3.0
## explicit; go 1.16
github.com/wagslane/go-password-validator
# github.com/yuin/goldmark v1.7.6
# github.com/yuin/goldmark v1.7.8
## explicit; go 1.19
github.com/yuin/goldmark
github.com/yuin/goldmark/ast

View file

@ -19,6 +19,7 @@
import React from "react";
import Loading from "./loading";
import { Error as ErrorC } from "./error";
import { useVerifyCredentialsQuery, useLogoutMutation } from "../lib/query/oauth";
import { useInstanceV1Query } from "../lib/query/gts-api";
@ -29,16 +30,20 @@ export default function UserLogoutCard() {
if (isLoading) {
return <Loading />;
} else {
return (
<div className="account-card">
<img className="avatar" src={profile.avatar} alt="" />
<h3 className="text-cutoff">{profile.display_name?.length > 0 ? profile.display_name : profile.acct}</h3>
<span className="text-cutoff">@{profile.username}@{instance?.account_domain}</span>
<a onClick={logoutQuery} href="#" aria-label="Log out" title="Log out" className="logout">
<i className="fa fa-fw fa-sign-out" aria-hidden="true" />
</a>
</div>
);
}
if (!profile) {
return <ErrorC error={new Error("account was undefined")} />;
}
return (
<div className="account-card">
<img className="avatar" src={profile.avatar} alt="" />
<h3 className="text-cutoff">{profile.display_name?.length > 0 ? profile.display_name : profile.acct}</h3>
<span className="text-cutoff">@{profile.username}@{instance?.account_domain}</span>
<a onClick={logoutQuery} href="#" aria-label="Log out" title="Log out" className="logout">
<i className="fa fa-fw fa-sign-out" aria-hidden="true" />
</a>
</div>
);
}

View file

@ -26,6 +26,7 @@ import {
authorize as oauthAuthorize,
} from "../../../redux/oauth";
import { RootState } from '../../../redux/store';
import { Account } from '../../types/account';
export interface OauthTokenRequestBody {
client_id: string;
@ -58,7 +59,7 @@ const SETTINGS_URL = (getSettingsURL());
// https://redux-toolkit.js.org/rtk-query/usage/customizing-queries#performing-multiple-requests-with-a-single-query
const extended = gtsApi.injectEndpoints({
endpoints: (build) => ({
verifyCredentials: build.query<any, void>({
verifyCredentials: build.query<Account, void>({
providesTags: (_res, error) =>
error == undefined ? ["Auth"] : [],
async queryFn(_arg, api, _extraOpts, fetchWithBQ) {

View file

@ -53,8 +53,12 @@ export interface Account {
url: string,
avatar: string,
avatar_static: string,
avatar_description?: string,
avatar_media_id?: string,
header: string,
header_static: string,
header_description?: string,
header_media_id?: string,
followers_count: number,
following_count: number,
statuses_count: number,
@ -68,7 +72,7 @@ export interface Account {
}
export interface AccountSource {
fields: any[];
fields: any;
follow_requests_count: number;
language: string;
note: string;

View file

@ -442,6 +442,11 @@ section.with-sidebar > form {
max-width: 42rem;
}
.file-input-with-image-description {
max-width: 100%;
width: 100%;
}
.overview {
display: flex;
flex-direction: column;

View file

@ -20,7 +20,7 @@
import React from "react";
import { useVerifyCredentialsQuery } from "../../../lib/query/oauth";
import Loading from "../../../components/loading";
import { Error } from "../../../components/error";
import { Error as ErrorC } from "../../../components/error";
import BasicSettings from "./basic-settings";
import InteractionPolicySettings from "./interaction-policy-settings";
@ -38,7 +38,11 @@ export default function PostSettings() {
}
if (isError) {
return <Error error={error} />;
return <ErrorC error={error} />;
}
if (!account) {
return <ErrorC error={new Error("account was undefined")} />;
}
return (

View file

@ -45,6 +45,7 @@ import { useAccountThemesQuery } from "../../lib/query/user";
import { useUpdateCredentialsMutation } from "../../lib/query/user";
import { useVerifyCredentialsQuery } from "../../lib/query/oauth";
import { useInstanceV1Query } from "../../lib/query/gts-api";
import { Account } from "../../lib/types/account";
export default function UserProfile() {
return (
@ -55,7 +56,11 @@ export default function UserProfile() {
);
}
function UserProfileForm({ data: profile }) {
interface UserProfileFormProps {
data: Account;
}
function UserProfileForm({ data: profile }: UserProfileFormProps) {
/*
User profile update form keys
- bool bot
@ -132,6 +137,9 @@ function UserProfileForm({ data: profile }) {
}
});
const noAvatarSet = !profile.avatar_media_id;
const noHeaderSet = !profile.header_media_id;
return (
<form className="user-profile" onSubmit={submitForm}>
<h1>Profile</h1>
@ -145,33 +153,37 @@ function UserProfileForm({ data: profile }) {
role={profile.role}
/>
<div className="file-input-with-image-description">
<fieldset className="file-input-with-image-description">
<legend>Header</legend>
<FileInput
label="Header"
label="Upload file"
field={form.header}
accept="image/png, image/jpeg, image/webp, image/gif"
/>
<TextInput
field={form.headerDescription}
label="Header image description"
label="Image description; only settable if not using default header"
placeholder="A green field with pink flowers."
autoCapitalize="sentences"
disabled={noHeaderSet && !form.header.value}
/>
</div>
</fieldset>
<div className="file-input-with-image-description">
<fieldset className="file-input-with-image-description">
<legend>Avatar</legend>
<FileInput
label="Avatar (1:1 images look best)"
label="Upload file (1:1 images look best)"
field={form.avatar}
accept="image/png, image/jpeg, image/webp, image/gif"
/>
<TextInput
field={form.avatarDescription}
label="Avatar image description"
label="Image description; only settable if not using default avatar"
placeholder="A cute drawing of a smiling sloth."
autoCapitalize="sentences"
disabled={noAvatarSet && !form.avatar.value}
/>
</div>
</fieldset>
<div className="theme">
<div>