mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-10-31 22:18:52 +00:00
Merge branch 'main' into chore/bump-go-structr-cache-version
This commit is contained in:
commit
eb5e90e532
45 changed files with 563 additions and 216 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -37,5 +37,6 @@ shell.nix
|
|||
/.idea/
|
||||
/.fleet/
|
||||
|
||||
# ignore cache dir from mkdocs serve
|
||||
/.cache
|
||||
# ignore cached pngs from mkdocs serve,
|
||||
# while preserving cached fonts.
|
||||
/docs/.cache/plugin/social/*.png
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
version: 2
|
||||
|
||||
build:
|
||||
os: "ubuntu-20.04"
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "mambaforge-4.10" # https://docs.readthedocs.io/en/stable/guides/conda.html#making-builds-faster-with-mamba
|
||||
python: "mambaforge-22.9" # https://docs.readthedocs.io/en/stable/guides/conda.html#making-builds-faster-with-mamba
|
||||
|
||||
mkdocs:
|
||||
configuration: "mkdocs.yml"
|
||||
|
|
|
@ -110,7 +110,13 @@ When adding a new page, you need to include it in the [`mkdocs.yml`](mkdocs.yml)
|
|||
|
||||
If you don't use Conda, you can read the `docs/environment.yml` to see which dependencies are required and `pip install` them manually. It's advisable to do this in a virtual environment, which you can create with something like `python3 -m venv /path-to/store-the-venv`. You can then call `/path-to/store-the-venv/bin/pip`, `/path-to/store-the-venv/bin/mkdocs` etc.
|
||||
|
||||
In order to upgrade dependencies, use `conda update --update-all` in the activated environment. You can then update the `environment.yml` with `conda env export --from-history -f ./docs/environment.yml`, though you'll need to fix the `channels`. Beware that `conda env export` will also drop the `pip` dependencies, so make sure to add those back.
|
||||
In order to upgrade dependencies, use `conda update --update-all` in the activated environment. You can then update the `environment.yml` with:
|
||||
|
||||
```sh
|
||||
conda env export -n gotosocial-docs --from-history --override-channels -c conda-forge -c nodefaults -f ./docs/environment.yml
|
||||
```
|
||||
|
||||
Beware that `conda env export` will add a `prefix` entry to the environment.yml file, and drop the `pip` dependencies, so make sure to remove the prefix and add the `pip` dependencies back in.
|
||||
|
||||
## Development
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/validate"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
@ -294,7 +295,43 @@ var Disable action.GTSAction = func(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
user.Disabled = func() *bool { d := true; return &d }()
|
||||
user.Disabled = util.Ptr(true)
|
||||
return state.DB.UpdateUser(
|
||||
ctx, user,
|
||||
"disabled",
|
||||
)
|
||||
}
|
||||
|
||||
// Enable sets Disabled to false on a user.
|
||||
var Enable action.GTSAction = func(ctx context.Context) error {
|
||||
state, err := initState(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Ensure state gets stopped on return.
|
||||
if err := stopState(state); err != nil {
|
||||
log.Error(ctx, err)
|
||||
}
|
||||
}()
|
||||
|
||||
username := config.GetAdminAccountUsername()
|
||||
if err := validate.Username(username); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
account, err := state.DB.GetAccountByUsernameDomain(ctx, username, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user, err := state.DB.GetUserByAccountID(ctx, account.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
user.Disabled = util.Ptr(false)
|
||||
return state.DB.UpdateUser(
|
||||
ctx, user,
|
||||
"disabled",
|
||||
|
|
|
@ -108,7 +108,7 @@ func adminCommands() *cobra.Command {
|
|||
|
||||
adminAccountDisableCmd := &cobra.Command{
|
||||
Use: "disable",
|
||||
Short: "prevent a local account from signing in or posting etc, but don't delete anything",
|
||||
Short: "set 'disabled' to true on a local account to prevent it from signing in or posting etc, but don't delete anything",
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return preRun(preRunArgs{cmd: cmd})
|
||||
},
|
||||
|
@ -119,6 +119,19 @@ func adminCommands() *cobra.Command {
|
|||
config.AddAdminAccount(adminAccountDisableCmd)
|
||||
adminAccountCmd.AddCommand(adminAccountDisableCmd)
|
||||
|
||||
adminAccountEnableCmd := &cobra.Command{
|
||||
Use: "enable",
|
||||
Short: "undo a previous disable command by setting 'disabled' to false on a local account",
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return preRun(preRunArgs{cmd: cmd})
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return run(cmd.Context(), account.Enable)
|
||||
},
|
||||
}
|
||||
config.AddAdminAccount(adminAccountEnableCmd)
|
||||
adminAccountCmd.AddCommand(adminAccountEnableCmd)
|
||||
|
||||
adminAccountPasswordCmd := &cobra.Command{
|
||||
Use: "password",
|
||||
Short: "set a new password for the given local account",
|
||||
|
|
BIN
docs/.cache/plugin/social/Roboto-Black.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-Black.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-BlackItalic.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-BlackItalic.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-Bold.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-Bold.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-BoldItalic.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-Italic.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-Italic.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-Light.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-Light.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-LightItalic.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-LightItalic.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-Medium.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-Medium.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-MediumItalic.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-MediumItalic.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-Regular.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-Regular.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-Thin.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-Thin.ttf
Normal file
Binary file not shown.
BIN
docs/.cache/plugin/social/Roboto-ThinItalic.ttf
Normal file
BIN
docs/.cache/plugin/social/Roboto-ThinItalic.ttf
Normal file
Binary file not shown.
|
@ -20,18 +20,34 @@ Usage:
|
|||
|
||||
Available Commands:
|
||||
admin gotosocial admin-related tasks
|
||||
completion generate the autocompletion script for the specified shell
|
||||
debug gotosocial debug-related tasks
|
||||
help Help about any command
|
||||
server gotosocial server-related tasks
|
||||
testrig gotosocial testrig-related tasks
|
||||
```
|
||||
|
||||
Under `Available Commands`, you can see the standard `server` command. But there are also commands doing admin and testing etc, which will be explained in this document.
|
||||
Under `Available Commands`, you can see the standard `server` command. But there are also commands doing admin and debugging etc, which will be explained in this document.
|
||||
|
||||
**Please note -- for all of these commands, you will still need to set the global options correctly so that the CLI tool knows how eg., how to connect to your database, which database to use, which host and account domain to use etc.**
|
||||
!!! Info "Passing global config to the CLI"
|
||||
|
||||
For all of these commands, you will still need to set the global options correctly so that the CLI tool knows how to connect to your database, which database to use, which host and account domain to use, etc.
|
||||
|
||||
You can set these options using environment variables, passing them as CLI flags (eg., `gotosocial [commands] --host example.org`), or by just pointing the CLI tool towards your config file (eg., `gotosocial --config-path ./config.yaml [commands]`).
|
||||
|
||||
You can set these options using environment variables, passing them as CLI flags (eg., `gotosocial [commands] --host example.org`), or by just pointing the CLI tool towards your config file (eg., `gotosocial --config-path ./config.yaml [commands]`).
|
||||
!!! Info
|
||||
|
||||
When running CLI commands, you'll get a bit of output like the following:
|
||||
|
||||
```text
|
||||
time=XXXX level=info msg=connected to SQLITE database
|
||||
time=XXXX level=info msg=there are no new migrations to run func=doMigration
|
||||
time=XXXX level=info msg=closing db connection
|
||||
```
|
||||
|
||||
This is normal and indicates that the commands ran as expected.
|
||||
|
||||
!!! Warning "Restarting GtS after running admin commands"
|
||||
|
||||
Because of the way internal caching works in GoToSocial, you may need to restart GoToSocial after running some of these commands in order for the effect of the command to "take". We are still looking for a way to make this unnecessary. In the meantime, commands that require a restart after running the command are highlighted below.
|
||||
|
||||
## gotosocial admin
|
||||
|
||||
|
@ -68,7 +84,11 @@ gotosocial admin account create \
|
|||
|
||||
### gotosocial admin account confirm
|
||||
|
||||
This command can be used to confirm a user+account on your instance, allowing them to log in and use the account. Note that if the account was created using `admin account create` this is not necessary.
|
||||
This command can be used to confirm a user+account on your instance, allowing them to log in and use the account.
|
||||
|
||||
!!! Info
|
||||
|
||||
If the account was created using `admin account create` it is not necessary to run `confirm` on the account, it will be confirmed already.
|
||||
|
||||
`gotosocial admin account confirm --help`:
|
||||
|
||||
|
@ -93,6 +113,10 @@ gotosocial admin account confirm --username some_username --config-path config.y
|
|||
|
||||
This command can be used to promote a user to admin.
|
||||
|
||||
!!! Warning "Server restart required"
|
||||
|
||||
In order for the change to "take", this command requires a restart of GoToSocial after running the command.
|
||||
|
||||
`gotosocial admin account promote --help`:
|
||||
|
||||
```text
|
||||
|
@ -116,6 +140,10 @@ gotosocial admin account promote --username some_username --config-path config.y
|
|||
|
||||
This command can be used to demote a user from admin to normal user.
|
||||
|
||||
!!! Warning "Server restart required"
|
||||
|
||||
In order for the change to "take", this command requires a restart of GoToSocial after running the command.
|
||||
|
||||
`gotosocial admin account demote --help`:
|
||||
|
||||
```text
|
||||
|
@ -139,10 +167,14 @@ gotosocial admin account demote --username some_username --config-path config.ya
|
|||
|
||||
This command can be used to disable an account on your instance: prevent it from signing in or doing anything, without deleting data.
|
||||
|
||||
!!! Warning "Server restart required"
|
||||
|
||||
In order for the change to "take", this command requires a restart of GoToSocial after running the command.
|
||||
|
||||
`gotosocial admin account disable --help`:
|
||||
|
||||
```text
|
||||
prevent a local account from signing in or posting etc, but don't delete anything
|
||||
set 'disabled' to true on a local account to prevent it from signing in or posting etc, but don't delete anything
|
||||
|
||||
Usage:
|
||||
gotosocial admin account disable [flags]
|
||||
|
@ -158,10 +190,41 @@ Example:
|
|||
gotosocial admin account disable --username some_username --config-path config.yaml
|
||||
```
|
||||
|
||||
### gotosocial admin account enable
|
||||
|
||||
This command can be used to reenable an account on your instance, undoing a previous `disable` command.
|
||||
|
||||
!!! Warning "Server restart required"
|
||||
|
||||
In order for the change to "take", this command requires a restart of GoToSocial after running the command.
|
||||
|
||||
`gotosocial admin account enable --help`:
|
||||
|
||||
```text
|
||||
undo a previous disable command by setting 'disabled' to false on a local account
|
||||
|
||||
Usage:
|
||||
gotosocial admin account enable [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for enable
|
||||
--username string the username to create/delete/etc
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
gotosocial admin account enable --username some_username --config-path config.yaml
|
||||
```
|
||||
|
||||
### gotosocial admin account password
|
||||
|
||||
This command can be used to set a new password on the given local account.
|
||||
|
||||
!!! Warning "Server restart required"
|
||||
|
||||
In order for the change to "take", this command requires a restart of GoToSocial after running the command.
|
||||
|
||||
`gotosocial admin account password --help`:
|
||||
|
||||
```text
|
||||
|
@ -329,7 +392,11 @@ This command can be used to prune orphaned media from your GoToSocial.
|
|||
|
||||
Orphaned media is defined as media that is in storage under a key that matches the format used by GoToSocial, but which does not have a corresponding database entry. This is useful for excising files that may be remaining from a previous installation, or files that were placed in storage mistakenly.
|
||||
|
||||
**This command only works when GoToSocial is not running, since it acquires an exclusive lock on storage. Stop GoToSocial first before running this command!**
|
||||
!!! Warning "Requires a stopped server"
|
||||
|
||||
This command only works when GoToSocial is not running, since it acquires an exclusive lock on storage.
|
||||
|
||||
Stop GoToSocial first before running this command!
|
||||
|
||||
```text
|
||||
prune orphaned media from storage
|
||||
|
@ -366,7 +433,11 @@ These items will be refetched later on demand, if necessary.
|
|||
|
||||
Unused media means avatars/headers/status attachments which are not currently in use by an account or status.
|
||||
|
||||
**This command only works when GoToSocial is not running, since it acquires an exclusive lock on storage. Stop GoToSocial first before running this command!**
|
||||
!!! Warning "Requires a stopped server"
|
||||
|
||||
This command only works when GoToSocial is not running, since it acquires an exclusive lock on storage.
|
||||
|
||||
Stop GoToSocial first before running this command!
|
||||
|
||||
```text
|
||||
prune unused/stale remote media from storage, older than given number of days
|
||||
|
|
|
@ -225,7 +225,9 @@ definitions:
|
|||
type: array
|
||||
x-go-name: Emojis
|
||||
enable_rss:
|
||||
description: Account has enabled RSS feed.
|
||||
description: |-
|
||||
Account has enabled RSS feed.
|
||||
Key/value omitted if false.
|
||||
type: boolean
|
||||
x-go-name: EnableRSS
|
||||
fields:
|
||||
|
@ -256,6 +258,12 @@ definitions:
|
|||
example: https://example.org/media/some_user/header/static/header.png
|
||||
type: string
|
||||
x-go-name: HeaderStatic
|
||||
hide_collections:
|
||||
description: |-
|
||||
Account has opted to hide their followers/following collections.
|
||||
Key/value omitted if false.
|
||||
type: boolean
|
||||
x-go-name: HideCollections
|
||||
id:
|
||||
description: The account id.
|
||||
example: 01FBVD42CQ3ZEEVMW180SBX03B
|
||||
|
@ -2898,6 +2906,8 @@ paths:
|
|||
```
|
||||
<https://example.org/api/v1/accounts/0657WMDEC3KQDTD6NZ4XJZBK4M/followers?limit=80&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/accounts/0657WMDEC3KQDTD6NZ4XJZBK4M/followers?limit=80&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev"
|
||||
````
|
||||
|
||||
If account `hide_collections` is true, and requesting account != target account, no results will be returned.
|
||||
operationId: accountFollowers
|
||||
parameters:
|
||||
- description: Account ID.
|
||||
|
@ -2962,6 +2972,8 @@ paths:
|
|||
```
|
||||
<https://example.org/api/v1/accounts/0657WMDEC3KQDTD6NZ4XJZBK4M/following?limit=80&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/accounts/0657WMDEC3KQDTD6NZ4XJZBK4M/following?limit=80&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev"
|
||||
````
|
||||
|
||||
If account `hide_collections` is true, and requesting account != target account, no results will be returned.
|
||||
operationId: accountFollowing
|
||||
parameters:
|
||||
- description: Account ID.
|
||||
|
@ -3552,6 +3564,10 @@ paths:
|
|||
in: formData
|
||||
name: source[status_content_type]
|
||||
type: string
|
||||
- description: FileName of the theme to use when rendering this account's profile or statuses. The theme must exist on this server, as indicated by /api/v1/accounts/themes. Empty string unsets theme and returns to the default GoToSocial theme.
|
||||
in: formData
|
||||
name: theme
|
||||
type: string
|
||||
- description: Custom CSS to use when rendering this account's profile or statuses. String must be no more than 5,000 characters (~5kb).
|
||||
in: formData
|
||||
name: custom_css
|
||||
|
@ -3560,6 +3576,10 @@ paths:
|
|||
in: formData
|
||||
name: enable_rss
|
||||
type: boolean
|
||||
- description: Hide the account's following/followers collections.
|
||||
in: formData
|
||||
name: hide_collections
|
||||
type: boolean
|
||||
- description: Name of 1st profile field to be added to this account's profile. (The index may be any string; add more indexes to send more fields.)
|
||||
in: formData
|
||||
name: fields_attributes[0][name]
|
||||
|
|
|
@ -5,10 +5,10 @@ channels:
|
|||
dependencies:
|
||||
- cairosvg==2.7.1
|
||||
- mkdocs-material-extensions==1.3.1
|
||||
- mkdocs-material==9.5.8
|
||||
- mkdocs-material==9.5.15
|
||||
- mkdocs==1.5.3
|
||||
- pillow==10.0.0
|
||||
- pip==23.3.1
|
||||
- python==3.11.3=h2755cc3_0_cpython
|
||||
- pillow==10.2.0
|
||||
- pip==24
|
||||
- python==3.12
|
||||
- pip:
|
||||
- mkdocs-swagger-ui-tag==0.6.8
|
||||
- mkdocs-swagger-ui-tag==0.6.9
|
||||
|
|
|
@ -106,7 +106,9 @@ This ensures that remote servers cannot flood a GoToSocial instance with spuriou
|
|||
|
||||
For more details on request throttling and rate limiting behavior, please see the [throttling](../api/throttling.md) and [rate limiting](../api/ratelimiting.md) documents.
|
||||
|
||||
## Inbox
|
||||
## Actors and Actor Properties
|
||||
|
||||
### Inbox
|
||||
|
||||
GoToSocial implements Inboxes for Actors following the ActivityPub specification [here](https://www.w3.org/TR/activitypub/#inbox).
|
||||
|
||||
|
@ -132,7 +134,7 @@ Invalidly-formed Inbox POST requests will receive a [400 - Bad Request](https://
|
|||
|
||||
Even if GoToSocial returns a `202` status code, it may not continue processing the Activity delivered, depending on the originator(s), target(s) and type of the Activity. ActivityPub is an extensive protocol, and GoToSocial does not cover every combination of Activity and Object.
|
||||
|
||||
## Outbox
|
||||
### Outbox
|
||||
|
||||
GoToSocial implements Outboxes for Actors (ie., instance accounts) following the ActivityPub specification [here](https://www.w3.org/TR/activitypub/#outbox).
|
||||
|
||||
|
@ -142,10 +144,10 @@ The server will return an OrderedCollection of the following structure:
|
|||
|
||||
```json
|
||||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"id": "https://example.org/users/whatever/outbox",
|
||||
"type": "OrderedCollection",
|
||||
"first": "https://example.org/users/whatever/outbox?page=true"
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"id": "https://example.org/users/whatever/outbox",
|
||||
"type": "OrderedCollection",
|
||||
"first": "https://example.org/users/whatever/outbox?page=true"
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -153,26 +155,26 @@ Note that the `OrderedCollection` itself contains no items. Callers must derefer
|
|||
|
||||
```json
|
||||
{
|
||||
"id": "https://example.org/users/whatever/outbox?page=true",
|
||||
"type": "OrderedCollectionPage",
|
||||
"next": "https://example.org/users/whatever/outbox?max_id=01FJC1Q0E3SSQR59TD2M1KP4V8&page=true",
|
||||
"prev": "https://example.org/users/whatever/outbox?min_id=01FJC1Q0E3SSQR59TD2M1KP4V8&page=true",
|
||||
"partOf": "https://example.org/users/whatever/outbox",
|
||||
"orderedItems": [
|
||||
{
|
||||
"id": "https://example.org/users/whatever/statuses/01FJC1MKPVX2VMWP2ST93Q90K7/activity",
|
||||
"type": "Create",
|
||||
"actor": "https://example.org/users/whatever",
|
||||
"published": "2021-10-18T20:06:18Z",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [
|
||||
"https://example.org/users/whatever/followers"
|
||||
],
|
||||
"object": "https://example.org/users/whatever/statuses/01FJC1MKPVX2VMWP2ST93Q90K7"
|
||||
}
|
||||
]
|
||||
"id": "https://example.org/users/whatever/outbox?page=true",
|
||||
"type": "OrderedCollectionPage",
|
||||
"next": "https://example.org/users/whatever/outbox?max_id=01FJC1Q0E3SSQR59TD2M1KP4V8&page=true",
|
||||
"prev": "https://example.org/users/whatever/outbox?min_id=01FJC1Q0E3SSQR59TD2M1KP4V8&page=true",
|
||||
"partOf": "https://example.org/users/whatever/outbox",
|
||||
"orderedItems": [
|
||||
{
|
||||
"id": "https://example.org/users/whatever/statuses/01FJC1MKPVX2VMWP2ST93Q90K7/activity",
|
||||
"type": "Create",
|
||||
"actor": "https://example.org/users/whatever",
|
||||
"published": "2021-10-18T20:06:18Z",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [
|
||||
"https://example.org/users/whatever/followers"
|
||||
],
|
||||
"object": "https://example.org/users/whatever/statuses/01FJC1MKPVX2VMWP2ST93Q90K7"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -180,6 +182,58 @@ The `orderedItems` array will contain up to 30 entries. To get more entries beyo
|
|||
|
||||
Note that in the returned `orderedItems`, all activity types will be `Create`. On each activity, the `object` field will be the AP URI of an original public status created by the Actor who owns the Outbox (ie., a `Note` with `https://www.w3.org/ns/activitystreams#Public` in the `to` field, which is not a reply to another status). Callers can use the returned AP URIs to dereference the content of the notes.
|
||||
|
||||
### Followers / Following Collections
|
||||
|
||||
GoToSocial implements followers and following collections as `OrderedCollection`s. A properly-signed `GET` request to an Actor's Following collection, for example, will return something like:
|
||||
|
||||
```json
|
||||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"first": "https://example.org/users/someone/following?limit=40",
|
||||
"id": "https://example.org/users/someone/following",
|
||||
"totalItems": 397,
|
||||
"type": "OrderedCollection"
|
||||
}
|
||||
```
|
||||
|
||||
From there, you can use the `first` page to start getting items. For example, a `GET` request to `https://example.org/users/someone/following?limit=40` will produce something like:
|
||||
|
||||
```json
|
||||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"id": "https://example.org/users/someone/following?limit=40",
|
||||
"next": "https://example.org/users/someone/following?limit=40&max_id=01V1AY4ZJT4JK1NT271SH2WMGH",
|
||||
"orderedItems": [
|
||||
"https://example.org/users/someone_else",
|
||||
"https://somewhere.else.example.org/users/another_account",
|
||||
[... 38 more entries here ...]
|
||||
],
|
||||
"partOf": "https://example.org/users/someone/following",
|
||||
"prev": "https://example.org/users/someone/following?limit=40&since_id=021HKBY346X7BPFYANPPJN493P",
|
||||
"totalItems": 397,
|
||||
"type": "OrderedCollectionPage"
|
||||
}
|
||||
```
|
||||
|
||||
You can then use the `next` and `prev` endpoints to page down and up through the OrderedCollection.
|
||||
|
||||
!!! Info "Hidden Followers / Following Collections"
|
||||
|
||||
GoToSocial allows users to hide their followers/following collections if they wish.
|
||||
|
||||
If a user has chosen to hide their collections, then only a stub collection with `totalItems` will be returned, and you will not be able to page through the Actor's followers/following collections.
|
||||
|
||||
A `GET` to the following collection of an Actor with hidden collections will look like:
|
||||
|
||||
```json
|
||||
{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"id": "https://example.org/users/someone/following",
|
||||
"type": "OrderedCollection",
|
||||
"totalItems": 397
|
||||
}
|
||||
```
|
||||
|
||||
## Conversation Threads
|
||||
|
||||
Due to the nature of decentralization and federation, it is practically impossible for any one server on the fediverse to be aware of every post in a given conversation thread.
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
Regardless of the installation method, you'll need to create some users. GoToSocial currently doesn't have a way for users to be created through the web UI, or for people to sign-up through the web UI.
|
||||
|
||||
Using the CLI, you can create a user:
|
||||
In the meantime, you can create a user using the CLI:
|
||||
|
||||
```sh
|
||||
$ gotosocial --config-path /path/to/config.yaml \
|
||||
./gotosocial --config-path /path/to/config.yaml \
|
||||
admin account create \
|
||||
--username some_username \
|
||||
--email some_email@whatever.org \
|
||||
|
@ -17,29 +17,28 @@ In the above command, replace `some_username` with your desired username, `some_
|
|||
If you want your user to have admin rights, you can promote them using a similar command:
|
||||
|
||||
```sh
|
||||
$ gotosocial --config-path /path/to/config.yaml \
|
||||
./gotosocial --config-path /path/to/config.yaml \
|
||||
admin account promote --username some_username
|
||||
```
|
||||
|
||||
Replace `some_username` with the username of the account you just created.
|
||||
|
||||
!!! info
|
||||
When running these commands, you'll get a bit of output like the following:
|
||||
!!! warning "Promotion requires server restart"
|
||||
|
||||
Due to the way caching works in GoToSocial, some admin CLI commands require a server restart after running the command in order for the changes to "take".
|
||||
|
||||
For example, after promoting a user to admin, you will need to restart your GoToSocial server so that the new values can be loaded from the database.
|
||||
|
||||
```text
|
||||
time=XXXX level=info msg=connected to SQLITE database
|
||||
time=XXXX level=info msg=there are no new migrations to run func=doMigration
|
||||
time=XXXX level=info msg=closing db connection
|
||||
```
|
||||
|
||||
This is normal and indicates that the commands ran as expected.
|
||||
!!! tip
|
||||
|
||||
Take a look at the other available CLI commands [here](../admin/cli.md).
|
||||
|
||||
## Containers
|
||||
|
||||
When running GoToSocial from a container, you'll need to execute the above command in the conatiner instead. How to do this varies based on your container runtime, but for Docker it should look like:
|
||||
When running GoToSocial from a container, you'll need to execute the above command in the container instead. How to do this varies based on your container runtime, but for Docker it should look like:
|
||||
|
||||
```sh
|
||||
$ docker exec -it CONTAINER_NAME_OR_ID \
|
||||
docker exec -it CONTAINER_NAME_OR_ID \
|
||||
/gotosocial/gotosocial \
|
||||
admin account create \
|
||||
--username some_username \
|
||||
|
|
|
@ -88,15 +88,6 @@ This option is often referred to on the fediverse as "locking" your account.
|
|||
|
||||
After ticking or unticking the checkbox, be sure to click on the `Save profile info` button at the bottom to save your new settings.
|
||||
|
||||
#### Enable RSS Feed of Public Posts
|
||||
|
||||
RSS feeds for users are disabled by default, but can be opted into with this checkbox. For more information see [RSS](./rss.md).
|
||||
|
||||
This feed only includes posts set as 'Public' (see [Privacy Settings](./posts.md#privacy-settings)).
|
||||
|
||||
!!! warning
|
||||
Exposing your RSS feed allows *anyone* to subscribe to updates on your Public posts anonymously, bypassing follows and follow requests.
|
||||
|
||||
#### Mark Account as Discoverable by Search Engines and Directories
|
||||
|
||||
This setting updates the 'discoverable' flag on your account.
|
||||
|
@ -114,6 +105,21 @@ Turning on the discoverable flag may take a week or more to propagate; your acco
|
|||
!!! info
|
||||
The discoverable setting is about **discoverability of your account**, not searchability of your posts. It has nothing to do with indexing of your posts for search by Mastodon instances, or other federated instances that use full text search!
|
||||
|
||||
#### Enable RSS Feed of Public Posts
|
||||
|
||||
RSS feeds for users are disabled by default, but can be opted into with this checkbox. For more information see [RSS](./rss.md).
|
||||
|
||||
This feed only includes posts set as 'Public' (see [Privacy Settings](./posts.md#privacy-settings)).
|
||||
|
||||
!!! warning
|
||||
Exposing your RSS feed allows *anyone* to subscribe to updates on your Public posts anonymously, bypassing follows and follow requests.
|
||||
|
||||
#### Hide Who You Follow / Are Followed By
|
||||
|
||||
By default, GoToSocial shows your following/followers counts on your public web profile, and allows others to see who you follow and are followed by. This can be useful for account discovery purposes. However, for privacy + safety reasons you may wish to hide these counts, and to hide your following/followers lists from other accounts. You can do this by checking this box.
|
||||
|
||||
With the box checked, your following/followers counts will be hidden from your public web profile, and others will not be able to page through your following/followers lists.
|
||||
|
||||
### Advanced
|
||||
|
||||
#### Custom CSS
|
||||
|
|
|
@ -49,6 +49,7 @@ func TestASCollection(t *testing.T) {
|
|||
// Create new collection using builder function.
|
||||
c := ap.NewASCollection(ap.CollectionParams{
|
||||
ID: parseURI(idURI),
|
||||
First: new(paging.Page),
|
||||
Query: url.Values{"limit": []string{"40"}},
|
||||
Total: total,
|
||||
})
|
||||
|
@ -60,6 +61,37 @@ func TestASCollection(t *testing.T) {
|
|||
assert.Equal(t, expect, s)
|
||||
}
|
||||
|
||||
func TestASCollectionTotalOnly(t *testing.T) {
|
||||
const (
|
||||
proto = "https"
|
||||
host = "zorg.flabormagorg.xyz"
|
||||
path = "/users/itsa_me_mario"
|
||||
|
||||
idURI = proto + "://" + host + path
|
||||
total = 10
|
||||
)
|
||||
|
||||
// Create JSON string of expected output.
|
||||
expect := toJSON(map[string]any{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"type": "Collection",
|
||||
"id": idURI,
|
||||
"totalItems": total,
|
||||
})
|
||||
|
||||
// Create new collection using builder function.
|
||||
c := ap.NewASCollection(ap.CollectionParams{
|
||||
ID: parseURI(idURI),
|
||||
Total: total,
|
||||
})
|
||||
|
||||
// Serialize collection.
|
||||
s := toJSON(c)
|
||||
|
||||
// Ensure outputs are equal.
|
||||
assert.Equal(t, expect, s)
|
||||
}
|
||||
|
||||
func TestASCollectionPage(t *testing.T) {
|
||||
const (
|
||||
proto = "https"
|
||||
|
@ -132,6 +164,7 @@ func TestASOrderedCollection(t *testing.T) {
|
|||
// Create new collection using builder function.
|
||||
c := ap.NewASOrderedCollection(ap.CollectionParams{
|
||||
ID: parseURI(idURI),
|
||||
First: new(paging.Page),
|
||||
Query: url.Values{"limit": []string{"40"}},
|
||||
Total: total,
|
||||
})
|
||||
|
@ -143,6 +176,33 @@ func TestASOrderedCollection(t *testing.T) {
|
|||
assert.Equal(t, expect, s)
|
||||
}
|
||||
|
||||
func TestASOrderedCollectionTotalOnly(t *testing.T) {
|
||||
const (
|
||||
idURI = "https://zorg.flabormagorg.xyz/users/itsa_me_mario"
|
||||
total = 10
|
||||
)
|
||||
|
||||
// Create JSON string of expected output.
|
||||
expect := toJSON(map[string]any{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"type": "OrderedCollection",
|
||||
"id": idURI,
|
||||
"totalItems": total,
|
||||
})
|
||||
|
||||
// Create new collection using builder function.
|
||||
c := ap.NewASOrderedCollection(ap.CollectionParams{
|
||||
ID: parseURI(idURI),
|
||||
Total: total,
|
||||
})
|
||||
|
||||
// Serialize collection.
|
||||
s := toJSON(c)
|
||||
|
||||
// Ensure outputs are equal.
|
||||
assert.Equal(t, expect, s)
|
||||
}
|
||||
|
||||
func TestASOrderedCollectionPage(t *testing.T) {
|
||||
const (
|
||||
proto = "https"
|
||||
|
|
|
@ -281,7 +281,7 @@ type CollectionParams struct {
|
|||
ID *url.URL
|
||||
|
||||
// First page details.
|
||||
First paging.Page
|
||||
First *paging.Page
|
||||
Query url.Values
|
||||
|
||||
// Total no. items.
|
||||
|
@ -377,6 +377,11 @@ func buildCollection[C CollectionBuilder](collection C, params CollectionParams)
|
|||
totalItems.Set(params.Total)
|
||||
collection.SetActivityStreamsTotalItems(totalItems)
|
||||
|
||||
// No First page means we're done.
|
||||
if params.First == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Append paging query params
|
||||
// to those already in ID prop.
|
||||
pageQueryParams := appendQuery(
|
||||
|
|
|
@ -108,6 +108,14 @@ import (
|
|||
// description: Default content type to use for authored statuses (text/plain or text/markdown).
|
||||
// type: string
|
||||
// -
|
||||
// name: theme
|
||||
// in: formData
|
||||
// description: >-
|
||||
// FileName of the theme to use when rendering this account's profile or statuses.
|
||||
// The theme must exist on this server, as indicated by /api/v1/accounts/themes.
|
||||
// Empty string unsets theme and returns to the default GoToSocial theme.
|
||||
// type: string
|
||||
// -
|
||||
// name: custom_css
|
||||
// in: formData
|
||||
// description: >-
|
||||
|
@ -120,6 +128,11 @@ import (
|
|||
// description: Enable RSS feed for this account's Public posts at `/[username]/feed.rss`
|
||||
// type: boolean
|
||||
// -
|
||||
// name: hide_collections
|
||||
// in: formData
|
||||
// description: Hide the account's following/followers collections.
|
||||
// type: boolean
|
||||
// -
|
||||
// name: fields_attributes[0][name]
|
||||
// in: formData
|
||||
// description: Name of 1st profile field to be added to this account's profile.
|
||||
|
@ -311,7 +324,8 @@ func parseUpdateAccountForm(c *gin.Context) (*apimodel.UpdateCredentialsRequest,
|
|||
form.FieldsAttributes == nil &&
|
||||
form.Theme == nil &&
|
||||
form.CustomCSS == nil &&
|
||||
form.EnableRSS == nil) {
|
||||
form.EnableRSS == nil &&
|
||||
form.HideCollections == nil) {
|
||||
return nil, errors.New("empty form submitted")
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ import (
|
|||
// <https://example.org/api/v1/accounts/0657WMDEC3KQDTD6NZ4XJZBK4M/followers?limit=80&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/accounts/0657WMDEC3KQDTD6NZ4XJZBK4M/followers?limit=80&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev"
|
||||
// ````
|
||||
//
|
||||
// If account `hide_collections` is true, and requesting account != target account, no results will be returned.
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - accounts
|
||||
|
|
|
@ -39,6 +39,8 @@ import (
|
|||
// <https://example.org/api/v1/accounts/0657WMDEC3KQDTD6NZ4XJZBK4M/following?limit=80&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/accounts/0657WMDEC3KQDTD6NZ4XJZBK4M/following?limit=80&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev"
|
||||
// ````
|
||||
//
|
||||
// If account `hide_collections` is true, and requesting account != target account, no results will be returned.
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - accounts
|
||||
|
|
|
@ -236,6 +236,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
|
|||
"verified_at": null
|
||||
}
|
||||
],
|
||||
"hide_collections": true,
|
||||
"role": {
|
||||
"name": "user"
|
||||
}
|
||||
|
@ -397,6 +398,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() {
|
|||
"verified_at": null
|
||||
}
|
||||
],
|
||||
"hide_collections": true,
|
||||
"role": {
|
||||
"name": "user"
|
||||
}
|
||||
|
@ -618,6 +620,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetCreatedByAccount() {
|
|||
"verified_at": null
|
||||
}
|
||||
],
|
||||
"hide_collections": true,
|
||||
"role": {
|
||||
"name": "user"
|
||||
}
|
||||
|
@ -839,6 +842,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetTargetAccount() {
|
|||
"verified_at": null
|
||||
}
|
||||
],
|
||||
"hide_collections": true,
|
||||
"role": {
|
||||
"name": "user"
|
||||
}
|
||||
|
|
|
@ -94,12 +94,16 @@ type Account struct {
|
|||
// CustomCSS to include when rendering this account's profile or statuses.
|
||||
CustomCSS string `json:"custom_css,omitempty"`
|
||||
// Account has enabled RSS feed.
|
||||
// Key/value omitted if false.
|
||||
EnableRSS bool `json:"enable_rss,omitempty"`
|
||||
// Account has opted to hide their followers/following collections.
|
||||
// Key/value omitted if false.
|
||||
HideCollections bool `json:"hide_collections,omitempty"`
|
||||
// Role of the account on this instance.
|
||||
// Omitted for remote accounts.
|
||||
// Key/value omitted for remote accounts.
|
||||
Role *AccountRole `json:"role,omitempty"`
|
||||
// If set, indicates that this account is currently inactive, and has migrated to the given account.
|
||||
// Omitted for accounts that haven't moved, and for suspended accounts.
|
||||
// Key/value omitted for accounts that haven't moved, and for suspended accounts.
|
||||
Moved *Account `json:"moved,omitempty"`
|
||||
}
|
||||
|
||||
|
@ -172,6 +176,8 @@ type UpdateCredentialsRequest struct {
|
|||
CustomCSS *string `form:"custom_css" json:"custom_css"`
|
||||
// Enable RSS feed of public toots for this account at /@[username]/feed.rss
|
||||
EnableRSS *bool `form:"enable_rss" json:"enable_rss"`
|
||||
// Hide this account's following/followers collections.
|
||||
HideCollections *bool `form:"hide_collections" json:"hide_collections"`
|
||||
}
|
||||
|
||||
// UpdateSource is to be used specifically in an UpdateCredentialsRequest.
|
||||
|
|
|
@ -31,11 +31,25 @@ import (
|
|||
// FollowersGet fetches a list of the target account's followers.
|
||||
func (p *Processor) FollowersGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string, page *paging.Page) (*apimodel.PageableResponse, gtserror.WithCode) {
|
||||
// Fetch target account to check it exists, and visibility of requester->target.
|
||||
_, errWithCode := p.c.GetVisibleTargetAccount(ctx, requestingAccount, targetAccountID)
|
||||
targetAccount, errWithCode := p.c.GetVisibleTargetAccount(ctx, requestingAccount, targetAccountID)
|
||||
if errWithCode != nil {
|
||||
return nil, errWithCode
|
||||
}
|
||||
|
||||
if targetAccount.IsInstance() {
|
||||
// Instance accounts can't follow/be followed.
|
||||
return paging.EmptyResponse(), nil
|
||||
}
|
||||
|
||||
// If account isn't requesting its own followers list,
|
||||
// but instead the list for a local account that has
|
||||
// hide_followers set, just return an empty array.
|
||||
if targetAccountID != requestingAccount.ID &&
|
||||
targetAccount.IsLocal() &&
|
||||
*targetAccount.Settings.HideCollections {
|
||||
return paging.EmptyResponse(), nil
|
||||
}
|
||||
|
||||
follows, err := p.state.DB.GetAccountFollowers(ctx, targetAccountID, page)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err = gtserror.Newf("db error getting followers: %w", err)
|
||||
|
@ -76,11 +90,25 @@ func (p *Processor) FollowersGet(ctx context.Context, requestingAccount *gtsmode
|
|||
// FollowingGet fetches a list of the accounts that target account is following.
|
||||
func (p *Processor) FollowingGet(ctx context.Context, requestingAccount *gtsmodel.Account, targetAccountID string, page *paging.Page) (*apimodel.PageableResponse, gtserror.WithCode) {
|
||||
// Fetch target account to check it exists, and visibility of requester->target.
|
||||
_, errWithCode := p.c.GetVisibleTargetAccount(ctx, requestingAccount, targetAccountID)
|
||||
targetAccount, errWithCode := p.c.GetVisibleTargetAccount(ctx, requestingAccount, targetAccountID)
|
||||
if errWithCode != nil {
|
||||
return nil, errWithCode
|
||||
}
|
||||
|
||||
if targetAccount.IsInstance() {
|
||||
// Instance accounts can't follow/be followed.
|
||||
return paging.EmptyResponse(), nil
|
||||
}
|
||||
|
||||
// If account isn't requesting its own following list,
|
||||
// but instead the list for a local account that has
|
||||
// hide_followers set, just return an empty array.
|
||||
if targetAccountID != requestingAccount.ID &&
|
||||
targetAccount.IsLocal() &&
|
||||
*targetAccount.Settings.HideCollections {
|
||||
return paging.EmptyResponse(), nil
|
||||
}
|
||||
|
||||
// Fetch known accounts that follow given target account ID.
|
||||
follows, err := p.state.DB.GetAccountFollows(ctx, targetAccountID, page)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
|
|
|
@ -284,6 +284,10 @@ func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
account.Settings.EnableRSS = form.EnableRSS
|
||||
}
|
||||
|
||||
if form.HideCollections != nil {
|
||||
account.Settings.HideCollections = form.HideCollections
|
||||
}
|
||||
|
||||
if err := p.state.DB.UpdateAccount(ctx, account); err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(fmt.Errorf("could not update account %s: %s", account.ID, err))
|
||||
}
|
||||
|
|
|
@ -140,15 +140,25 @@ func (p *Processor) FollowersGet(ctx context.Context, requestedUser string, page
|
|||
params.ID = collectionID
|
||||
params.Total = total
|
||||
|
||||
if page == nil {
|
||||
switch {
|
||||
|
||||
case receiver.IsInstance() ||
|
||||
*receiver.Settings.HideCollections:
|
||||
// Instance account (can't follow/be followed),
|
||||
// or an account that hides followers/following.
|
||||
// Respect this by just returning totalItems.
|
||||
obj = ap.NewASOrderedCollection(params)
|
||||
|
||||
case page == nil:
|
||||
// i.e. paging disabled, return collection
|
||||
// that links to first page (i.e. path below).
|
||||
params.First = new(paging.Page)
|
||||
params.Query = make(url.Values, 1)
|
||||
params.Query.Set("limit", "40") // enables paging
|
||||
obj = ap.NewASOrderedCollection(params)
|
||||
} else {
|
||||
// i.e. paging enabled
|
||||
|
||||
default:
|
||||
// i.e. paging enabled
|
||||
// Get the request page of full follower objects with attached accounts.
|
||||
followers, err := p.state.DB.GetAccountFollowers(ctx, receiver.ID, page)
|
||||
if err != nil {
|
||||
|
@ -239,15 +249,24 @@ func (p *Processor) FollowingGet(ctx context.Context, requestedUser string, page
|
|||
params.ID = collectionID
|
||||
params.Total = total
|
||||
|
||||
if page == nil {
|
||||
switch {
|
||||
case receiver.IsInstance() ||
|
||||
*receiver.Settings.HideCollections:
|
||||
// Instance account (can't follow/be followed),
|
||||
// or an account that hides followers/following.
|
||||
// Respect this by just returning totalItems.
|
||||
obj = ap.NewASOrderedCollection(params)
|
||||
|
||||
case page == nil:
|
||||
// i.e. paging disabled, return collection
|
||||
// that links to first page (i.e. path below).
|
||||
params.First = new(paging.Page)
|
||||
params.Query = make(url.Values, 1)
|
||||
params.Query.Set("limit", "40") // enables paging
|
||||
obj = ap.NewASOrderedCollection(params)
|
||||
} else {
|
||||
// i.e. paging enabled
|
||||
|
||||
default:
|
||||
// i.e. paging enabled
|
||||
// Get the request page of full follower objects with attached accounts.
|
||||
follows, err := p.state.DB.GetAccountFollows(ctx, receiver.ID, page)
|
||||
if err != nil {
|
||||
|
@ -279,9 +298,9 @@ func (p *Processor) FollowingGet(ctx context.Context, requestedUser string, page
|
|||
|
||||
// Set the collection item property builder function.
|
||||
pageParams.Append = func(i int, itemsProp ap.ItemsPropertyBuilder) {
|
||||
// Get follower URI at index.
|
||||
// Get followed URI at index.
|
||||
follow := follows[i]
|
||||
accURI := follow.Account.URI
|
||||
accURI := follow.TargetAccount.URI
|
||||
|
||||
// Parse URL object from URI.
|
||||
iri, err := url.Parse(accURI)
|
||||
|
|
|
@ -156,6 +156,7 @@ func (p *Processor) StatusRepliesGet(
|
|||
if page == nil {
|
||||
// i.e. paging disabled, return collection
|
||||
// that links to first page (i.e. path below).
|
||||
params.First = new(paging.Page)
|
||||
params.Query = make(url.Values, 1)
|
||||
params.Query.Set("limit", "20") // enables paging
|
||||
obj = ap.NewASOrderedCollection(params)
|
||||
|
|
|
@ -170,14 +170,15 @@ func (c *Converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
|||
// Bits that vary between remote + local accounts:
|
||||
// - Account (acct) string.
|
||||
// - Role.
|
||||
// - Settings things (enableRSS, theme, customCSS).
|
||||
// - Settings things (enableRSS, theme, customCSS, hideCollections).
|
||||
|
||||
var (
|
||||
acct string
|
||||
role *apimodel.AccountRole
|
||||
enableRSS bool
|
||||
theme string
|
||||
customCSS string
|
||||
acct string
|
||||
role *apimodel.AccountRole
|
||||
enableRSS bool
|
||||
theme string
|
||||
customCSS string
|
||||
hideCollections bool
|
||||
)
|
||||
|
||||
if a.IsRemote() {
|
||||
|
@ -211,6 +212,7 @@ func (c *Converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
|||
enableRSS = *a.Settings.EnableRSS
|
||||
theme = a.Settings.Theme
|
||||
customCSS = a.Settings.CustomCSS
|
||||
hideCollections = *a.Settings.HideCollections
|
||||
}
|
||||
|
||||
acct = a.Username // omit domain
|
||||
|
@ -253,32 +255,33 @@ func (c *Converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
|||
// can be populated directly below.
|
||||
|
||||
accountFrontend := &apimodel.Account{
|
||||
ID: a.ID,
|
||||
Username: a.Username,
|
||||
Acct: acct,
|
||||
DisplayName: a.DisplayName,
|
||||
Locked: locked,
|
||||
Discoverable: discoverable,
|
||||
Bot: bot,
|
||||
CreatedAt: util.FormatISO8601(a.CreatedAt),
|
||||
Note: a.Note,
|
||||
URL: a.URL,
|
||||
Avatar: aviURL,
|
||||
AvatarStatic: aviURLStatic,
|
||||
Header: headerURL,
|
||||
HeaderStatic: headerURLStatic,
|
||||
FollowersCount: followersCount,
|
||||
FollowingCount: followingCount,
|
||||
StatusesCount: statusesCount,
|
||||
LastStatusAt: lastStatusAt,
|
||||
Emojis: apiEmojis,
|
||||
Fields: fields,
|
||||
Suspended: !a.SuspendedAt.IsZero(),
|
||||
Theme: theme,
|
||||
CustomCSS: customCSS,
|
||||
EnableRSS: enableRSS,
|
||||
Role: role,
|
||||
Moved: moved,
|
||||
ID: a.ID,
|
||||
Username: a.Username,
|
||||
Acct: acct,
|
||||
DisplayName: a.DisplayName,
|
||||
Locked: locked,
|
||||
Discoverable: discoverable,
|
||||
Bot: bot,
|
||||
CreatedAt: util.FormatISO8601(a.CreatedAt),
|
||||
Note: a.Note,
|
||||
URL: a.URL,
|
||||
Avatar: aviURL,
|
||||
AvatarStatic: aviURLStatic,
|
||||
Header: headerURL,
|
||||
HeaderStatic: headerURLStatic,
|
||||
FollowersCount: followersCount,
|
||||
FollowingCount: followingCount,
|
||||
StatusesCount: statusesCount,
|
||||
LastStatusAt: lastStatusAt,
|
||||
Emojis: apiEmojis,
|
||||
Fields: fields,
|
||||
Suspended: !a.SuspendedAt.IsZero(),
|
||||
Theme: theme,
|
||||
CustomCSS: customCSS,
|
||||
EnableRSS: enableRSS,
|
||||
HideCollections: hideCollections,
|
||||
Role: role,
|
||||
Moved: moved,
|
||||
}
|
||||
|
||||
// Bodge default avatar + header in,
|
||||
|
|
|
@ -161,6 +161,7 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendAliasedAndMoved()
|
|||
"verified_at": null
|
||||
}
|
||||
],
|
||||
"hide_collections": true,
|
||||
"role": {
|
||||
"name": "user"
|
||||
}
|
||||
|
@ -1313,6 +1314,7 @@ func (suite *InternalToFrontendTestSuite) TestReportToFrontend2() {
|
|||
"verified_at": null
|
||||
}
|
||||
],
|
||||
"hide_collections": true,
|
||||
"role": {
|
||||
"name": "user"
|
||||
}
|
||||
|
@ -1428,6 +1430,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend1() {
|
|||
"verified_at": null
|
||||
}
|
||||
],
|
||||
"hide_collections": true,
|
||||
"role": {
|
||||
"name": "user"
|
||||
}
|
||||
|
@ -1599,6 +1602,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontend2() {
|
|||
"verified_at": null
|
||||
}
|
||||
],
|
||||
"hide_collections": true,
|
||||
"role": {
|
||||
"name": "user"
|
||||
}
|
||||
|
@ -1864,6 +1868,7 @@ func (suite *InternalToFrontendTestSuite) TestAdminReportToFrontendSuspendedLoca
|
|||
"emojis": [],
|
||||
"fields": [],
|
||||
"suspended": true,
|
||||
"hide_collections": true,
|
||||
"role": {
|
||||
"name": "user"
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ plugins:
|
|||
cards_layout_options:
|
||||
background_color: "#fd6a00"
|
||||
color: "#fafaff"
|
||||
cache_dir: "./docs/.cache/plugin/social"
|
||||
- swagger-ui-tag:
|
||||
supportedSubmitMethods: []
|
||||
syntaxHighlightTheme: obsidian
|
||||
|
|
|
@ -702,7 +702,7 @@ func NewTestAccountSettings() map[string]*gtsmodel.AccountSettings {
|
|||
Sensitive: util.Ptr(true),
|
||||
Language: "fr",
|
||||
EnableRSS: util.Ptr(false),
|
||||
HideCollections: util.Ptr(false),
|
||||
HideCollections: util.Ptr(true),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,18 +5,16 @@
|
|||
|
||||
:root {
|
||||
/* Define our nice blurple palette */
|
||||
--blurple1: #ffffff;
|
||||
--blurple2: #ebe6f8;
|
||||
--blurple3: #d6cceb;
|
||||
--blurple4: #c2b3e1;
|
||||
--blurple5: #ad99d7;
|
||||
--blurple6: #9980cd;
|
||||
--blurple7: #8566c2;
|
||||
--blurple8: #704db8;
|
||||
--blurple9: #5c33ae;
|
||||
--blurple10: #471aa4;
|
||||
--blurple11: #33009a;
|
||||
--blurple12: #170044;
|
||||
--blurple1: #ebe6f8;
|
||||
--blurple2: #d6cceb;
|
||||
--blurple3: #c2b3e1;
|
||||
--blurple4: #aa60ff;
|
||||
--blurple5: #783d9f;
|
||||
--blurple6: #2d2b55;
|
||||
--blurple7: #1f1f41;
|
||||
|
||||
/* Override orange trim */
|
||||
--orange2: #fad000;
|
||||
|
||||
/* Restyle basic colors to use blurple */
|
||||
--blue1: var(--blurple1);
|
||||
|
@ -24,23 +22,23 @@
|
|||
--blue3: var(--blurple3);
|
||||
|
||||
/* Basic page styling (background + foreground) */
|
||||
--bg: var(--blurple12);
|
||||
--bg-accent: var(--blurple11);
|
||||
--bg: linear-gradient(var(--blurple7), black);
|
||||
--bg-accent: var(--blurple6);
|
||||
--fg: var(--blurple1);
|
||||
--fg-reduced: var(--blurple3);
|
||||
--fg-reduced: var(--blurple2);
|
||||
|
||||
/* Profile page styling (light) */
|
||||
--profile-bg: var(--blurple11);
|
||||
/* Profile page styling */
|
||||
--profile-bg: var(--blurple6);
|
||||
|
||||
/* Blurpleize buttons */
|
||||
--button-bg: var(--blurple2);
|
||||
--button-fg: var(--blurple11);
|
||||
--button-fg: var(--blurple5);
|
||||
|
||||
/* Blurpleize statuses */
|
||||
--status-bg: var(--blurple11);
|
||||
--status-focus-bg: var(--blurple11);
|
||||
--status-info-bg: var(--blurple9);
|
||||
--status-focus-info-bg: var(--blurple9);
|
||||
--status-bg: var(--blurple6);
|
||||
--status-focus-bg: var(--blurple6);
|
||||
--status-info-bg: var(--blurple5);
|
||||
--status-focus-info-bg: var(--blurple5);
|
||||
|
||||
/* Used around statuses + other items */
|
||||
--boxshadow-border: 0.08rem solid black;
|
||||
|
@ -48,26 +46,26 @@
|
|||
|
||||
/* Scroll bar */
|
||||
html, body {
|
||||
scrollbar-color: var(--blurple8) var(--blurple12);
|
||||
scrollbar-color: var(--blurple4) var(--blurple7);
|
||||
}
|
||||
|
||||
/* Profile fields */
|
||||
.profile .about-user .fields .field {
|
||||
border-bottom: 0.1rem solid var(--blurple8);
|
||||
border-bottom: 0.1rem solid var(--blurple4);
|
||||
}
|
||||
.profile .about-user .fields .field:first-child {
|
||||
border-top: 0.1rem solid var(--blurple8);
|
||||
border-top: 0.1rem solid var(--blurple4);
|
||||
}
|
||||
|
||||
/* Status media */
|
||||
.status .media .media-wrapper {
|
||||
border: 0.08rem solid var(--blurple9);
|
||||
border: 0.08rem solid var(--blurple5);
|
||||
}
|
||||
.status .media .media-wrapper details .unknown-attachment .placeholder {
|
||||
color: var(--blue2);
|
||||
}
|
||||
.status .media .media-wrapper details video.plyr-video {
|
||||
background: var(--blurple11);
|
||||
background: var(--blurple6);
|
||||
}
|
||||
|
||||
/* Status polls */
|
||||
|
@ -75,18 +73,18 @@ html, body {
|
|||
background-color: var(--bg);
|
||||
}
|
||||
.status .text .poll .poll-info {
|
||||
background-color: var(--blurple11);
|
||||
background-color: var(--blurple6);
|
||||
}
|
||||
|
||||
/* Code snippets */
|
||||
pre, pre[class*="language-"],
|
||||
code, code[class*="language-"] {
|
||||
background-color: var(--blurple12);
|
||||
background-color: var(--blurple7);
|
||||
color: var(--fg-reduced);
|
||||
}
|
||||
|
||||
/* Block quotes */
|
||||
blockquote {
|
||||
background-color: var(--blurple12);
|
||||
background-color: var(--blurple7);
|
||||
color: var(--fg-reduced);
|
||||
}
|
||||
|
|
|
@ -5,28 +5,26 @@
|
|||
|
||||
:root {
|
||||
/* Define our nice blurple palette */
|
||||
--blurple1: #ffffff;
|
||||
--blurple2: #ebe6f8;
|
||||
--blurple3: #d6cceb;
|
||||
--blurple4: #c2b3e1;
|
||||
--blurple5: #ad99d7;
|
||||
--blurple6: #9980cd;
|
||||
--blurple7: #8566c2;
|
||||
--blurple8: #704db8;
|
||||
--blurple9: #5c33ae;
|
||||
--blurple10: #471aa4;
|
||||
--blurple11: #33009a;
|
||||
--blurple12: #170044;
|
||||
--blurple1: #ebe6f8;
|
||||
--blurple2: #d6cceb;
|
||||
--blurple3: #c2b3e1;
|
||||
--blurple4: #aa60ff;
|
||||
--blurple5: #783d9f;
|
||||
--blurple6: #2d2b55;
|
||||
--blurple7: #1f1f41;
|
||||
|
||||
/* Override orange trim */
|
||||
--orange2: #700000;
|
||||
|
||||
/* Restyle basic colors to use blurple */
|
||||
--white1: var(--blurple2);
|
||||
--white2: var(--blurple3);
|
||||
--blue1: var(--blurple6);
|
||||
--blue2: var(--blurple8);
|
||||
--blue3: var(--blurple10);
|
||||
--blue1: var(--blurple4);
|
||||
--blue2: var(--blurple5);
|
||||
--blue3: var(--blurple6);
|
||||
|
||||
/* Basic page styling (background + foreground) */
|
||||
--bg: linear-gradient(var(--blurple2), var(--blurple1));
|
||||
--bg: linear-gradient(var(--blurple1), white);
|
||||
--bg-accent: var(--white2);
|
||||
--fg: var(--gray1);
|
||||
--fg-reduced: var(--gray2);
|
||||
|
@ -45,25 +43,25 @@
|
|||
--status-focus-info-bg: var(--white2);
|
||||
|
||||
/* Used around statuses + other items */
|
||||
--boxshadow-border: 0.08rem solid var(--blurple10);
|
||||
--boxshadow-border: 0.08rem solid var(--blurple6);
|
||||
}
|
||||
|
||||
/* Scroll bar */
|
||||
html, body {
|
||||
scrollbar-color: var(--blurple8) var(--blurple2);
|
||||
scrollbar-color: var(--blurple5) var(--blurple2);
|
||||
}
|
||||
|
||||
/* Profile fields */
|
||||
.profile .about-user .fields .field {
|
||||
border-bottom: 0.1rem solid var(--blurple10);
|
||||
border-bottom: 0.1rem solid var(--blurple6);
|
||||
}
|
||||
.profile .about-user .fields .field:first-child {
|
||||
border-top: 0.1rem solid var(--blurple10);
|
||||
border-top: 0.1rem solid var(--blurple6);
|
||||
}
|
||||
|
||||
/* Status media */
|
||||
.status .media .media-wrapper {
|
||||
border: 0.08rem solid var(--blurple10);
|
||||
border: 0.08rem solid var(--blurple6);
|
||||
}
|
||||
.status .media .media-wrapper details .unknown-attachment .placeholder {
|
||||
color: var(--blue2);
|
||||
|
@ -83,12 +81,12 @@ html, body {
|
|||
/* Code snippets */
|
||||
pre, pre[class*="language-"],
|
||||
code, code[class*="language-"] {
|
||||
background-color: var(--blurple12);
|
||||
background-color: var(--blurple7);
|
||||
color: var(--blurple2);
|
||||
}
|
||||
|
||||
/* Block quotes */
|
||||
blockquote {
|
||||
background-color: var(--blurple1);
|
||||
color: var(--blurple12);
|
||||
color: var(--blurple7);
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
--acid-green-light: #79FF4D;
|
||||
--acid-green-dark: #269900;
|
||||
--magenta: rgb(153, 50, 204);
|
||||
--darkred: rgb(58, 0, 15);
|
||||
--darkblue: rgb(0, 0, 58);
|
||||
--darkmagenta: rgb(47, 1, 65);
|
||||
|
||||
/* Override */
|
||||
|
@ -22,27 +20,7 @@
|
|||
}
|
||||
|
||||
body {
|
||||
background: linear-gradient(-45deg, black, var(--darkmagenta), var(--darkblue), var(--darkred));
|
||||
background-size: 400% 400%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media not (prefers-reduced-motion) {
|
||||
body {
|
||||
animation: gradient 30s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes gradient {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
background: linear-gradient(90deg, var(--darkmagenta), black, var(--darkmagenta));
|
||||
}
|
||||
|
||||
html, body {
|
||||
|
|
|
@ -50,10 +50,16 @@ html, body {
|
|||
scrollbar-color: var(--pink) var(--eggshell);
|
||||
}
|
||||
|
||||
/* Instance title color */
|
||||
.page-header a h1 {
|
||||
color: var(--eggshell);
|
||||
}
|
||||
|
||||
/* Role badge background */
|
||||
.profile .profile-header .basic-info .namerole .role {
|
||||
background: var(--eggshell);
|
||||
}
|
||||
|
||||
/* Profile fields */
|
||||
.profile .about-user .fields .field {
|
||||
border-bottom: 0.1rem solid var(--orange);
|
||||
|
|
|
@ -65,6 +65,7 @@ function UserProfileForm({ data: profile }) {
|
|||
- file avatar
|
||||
- file header
|
||||
- bool enable_rss
|
||||
- bool hide_collections
|
||||
- string custom_css (if enabled)
|
||||
- string theme
|
||||
*/
|
||||
|
@ -98,6 +99,7 @@ function UserProfileForm({ data: profile }) {
|
|||
locked: useBoolInput("locked", { source: profile }),
|
||||
discoverable: useBoolInput("discoverable", { source: profile}),
|
||||
enableRSS: useBoolInput("enable_rss", { source: profile }),
|
||||
hideCollections: useBoolInput("hide_collections", { source: profile }),
|
||||
fields: useFieldArrayInput("fields_attributes", {
|
||||
defaultValue: profile?.source?.fields,
|
||||
length: instanceConfig.maxPinnedFields
|
||||
|
@ -208,6 +210,10 @@ function UserProfileForm({ data: profile }) {
|
|||
field={form.enableRSS}
|
||||
label="Enable RSS feed of Public posts"
|
||||
/>
|
||||
<Checkbox
|
||||
field={form.hideCollections}
|
||||
label="Hide who you follow / are followed by"
|
||||
/>
|
||||
|
||||
<div className="form-section-docs">
|
||||
<h3>Advanced</h3>
|
||||
|
|
|
@ -2146,13 +2146,13 @@ bn.js@^5.0.0, bn.js@^5.2.1:
|
|||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
|
||||
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
|
||||
|
||||
body-parser@1.20.1:
|
||||
version "1.20.1"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
|
||||
integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
|
||||
body-parser@1.20.2:
|
||||
version "1.20.2"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
|
||||
integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
content-type "~1.0.4"
|
||||
content-type "~1.0.5"
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
destroy "1.2.0"
|
||||
|
@ -2160,7 +2160,7 @@ body-parser@1.20.1:
|
|||
iconv-lite "0.4.24"
|
||||
on-finished "2.4.1"
|
||||
qs "6.11.0"
|
||||
raw-body "2.5.1"
|
||||
raw-body "2.5.2"
|
||||
type-is "~1.6.18"
|
||||
unpipe "1.0.0"
|
||||
|
||||
|
@ -2584,7 +2584,7 @@ content-disposition@0.5.4:
|
|||
dependencies:
|
||||
safe-buffer "5.2.1"
|
||||
|
||||
content-type@~1.0.4:
|
||||
content-type@~1.0.4, content-type@~1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
|
||||
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
|
||||
|
@ -2614,10 +2614,10 @@ cookie-signature@1.0.6:
|
|||
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
|
||||
integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
|
||||
|
||||
cookie@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
cookie@0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
|
||||
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
|
||||
|
||||
core-js-compat@^3.31.0, core-js-compat@^3.32.2:
|
||||
version "3.33.0"
|
||||
|
@ -3337,16 +3337,16 @@ execall@^2.0.0:
|
|||
clone-regexp "^2.1.0"
|
||||
|
||||
express@^4.18.2:
|
||||
version "4.18.2"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
|
||||
integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
|
||||
version "4.19.2"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465"
|
||||
integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==
|
||||
dependencies:
|
||||
accepts "~1.3.8"
|
||||
array-flatten "1.1.1"
|
||||
body-parser "1.20.1"
|
||||
body-parser "1.20.2"
|
||||
content-disposition "0.5.4"
|
||||
content-type "~1.0.4"
|
||||
cookie "0.5.0"
|
||||
cookie "0.6.0"
|
||||
cookie-signature "1.0.6"
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
|
@ -5249,10 +5249,10 @@ rangetouch@^2.0.1:
|
|||
resolved "https://registry.yarnpkg.com/rangetouch/-/rangetouch-2.0.1.tgz#c01105110fd3afca2adcb1a580692837d883cb70"
|
||||
integrity sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==
|
||||
|
||||
raw-body@2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
|
||||
integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
|
||||
raw-body@2.5.2:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
|
||||
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
http-errors "2.0.0"
|
||||
|
|
|
@ -98,9 +98,9 @@
|
|||
<dt>Posts</dt>
|
||||
<dd>{{- .account.StatusesCount -}}</dd>
|
||||
<dt>Followed by</dt>
|
||||
<dd>{{- .account.FollowersCount -}}</dd>
|
||||
<dd>{{- if .account.HideCollections -}}<i>hidden</i>{{- else -}}{{- .account.FollowersCount -}}{{- end -}}</dd>
|
||||
<dt>Following</dt>
|
||||
<dd>{{- .account.FollowingCount -}}</dd>
|
||||
<dd>{{- if .account.HideCollections -}}<i>hidden</i>{{- else -}}{{- .account.FollowingCount -}}{{- end -}}</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<div class="statuses-wrapper" role="region" aria-label="Posts by {{ .account.Username -}}">
|
||||
|
|
Loading…
Reference in a new issue