[chore] Update bun / sqlite versions; update gtsmodels (#754)

* upstep bun and sqlite versions

* allow specific columns to be updated in the db

* only update necessary columns for user

* bit tidier

* only update necessary fields of media_attachment

* only update relevant instance fields

* update tests

* update only specific account columns

* use bool pointers on gtsmodels
includes attachment, status, account, user

* update columns more selectively

* test all default fields on new account insert

* updating remaining bools on gtsmodels

* initialize pointer fields when extracting AP emoji

* copy bools properly

* add copyBoolPtr convenience function + test it

* initialize false bool ptrs a bit more neatly
This commit is contained in:
tobi 2022-08-15 12:35:05 +02:00 committed by GitHub
commit ac6ed3d939
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
376 changed files with 337942 additions and 298092 deletions

View file

@ -97,10 +97,13 @@ var Confirm action.GTSAction = func(ctx context.Context) error {
return err return err
} }
u.Approved = true updatingColumns := []string{"approved", "email", "confirmed_at", "updated_at"}
approved := true
u.Approved = &approved
u.Email = u.UnconfirmedEmail u.Email = u.UnconfirmedEmail
u.ConfirmedAt = time.Now() u.ConfirmedAt = time.Now()
if err := dbConn.UpdateByPrimaryKey(ctx, u); err != nil { u.UpdatedAt = time.Now()
if err := dbConn.UpdateByPrimaryKey(ctx, u, updatingColumns...); err != nil {
return err return err
} }
@ -131,8 +134,12 @@ var Promote action.GTSAction = func(ctx context.Context) error {
if err := dbConn.GetWhere(ctx, []db.Where{{Key: "account_id", Value: a.ID}}, u); err != nil { if err := dbConn.GetWhere(ctx, []db.Where{{Key: "account_id", Value: a.ID}}, u); err != nil {
return err return err
} }
u.Admin = true
if err := dbConn.UpdateByPrimaryKey(ctx, u); err != nil { updatingColumns := []string{"admin", "updated_at"}
admin := true
u.Admin = &admin
u.UpdatedAt = time.Now()
if err := dbConn.UpdateByPrimaryKey(ctx, u, updatingColumns...); err != nil {
return err return err
} }
@ -163,8 +170,12 @@ var Demote action.GTSAction = func(ctx context.Context) error {
if err := dbConn.GetWhere(ctx, []db.Where{{Key: "account_id", Value: a.ID}}, u); err != nil { if err := dbConn.GetWhere(ctx, []db.Where{{Key: "account_id", Value: a.ID}}, u); err != nil {
return err return err
} }
u.Admin = false
if err := dbConn.UpdateByPrimaryKey(ctx, u); err != nil { updatingColumns := []string{"admin", "updated_at"}
admin := false
u.Admin = &admin
u.UpdatedAt = time.Now()
if err := dbConn.UpdateByPrimaryKey(ctx, u, updatingColumns...); err != nil {
return err return err
} }
@ -195,8 +206,12 @@ var Disable action.GTSAction = func(ctx context.Context) error {
if err := dbConn.GetWhere(ctx, []db.Where{{Key: "account_id", Value: a.ID}}, u); err != nil { if err := dbConn.GetWhere(ctx, []db.Where{{Key: "account_id", Value: a.ID}}, u); err != nil {
return err return err
} }
u.Disabled = true
if err := dbConn.UpdateByPrimaryKey(ctx, u); err != nil { updatingColumns := []string{"disabled", "updated_at"}
disabled := true
u.Disabled = &disabled
u.UpdatedAt = time.Now()
if err := dbConn.UpdateByPrimaryKey(ctx, u, updatingColumns...); err != nil {
return err return err
} }
@ -247,9 +262,10 @@ var Password action.GTSAction = func(ctx context.Context) error {
return fmt.Errorf("error hashing password: %s", err) return fmt.Errorf("error hashing password: %s", err)
} }
updatingColumns := []string{"encrypted_password", "updated_at"}
u.EncryptedPassword = string(pw) u.EncryptedPassword = string(pw)
u.UpdatedAt = time.Now()
if err := dbConn.UpdateByPrimaryKey(ctx, u); err != nil { if err := dbConn.UpdateByPrimaryKey(ctx, u, updatingColumns...); err != nil {
return err return err
} }

14
go.mod
View file

@ -42,9 +42,9 @@ require (
github.com/superseriousbusiness/exif-terminator v0.4.0 github.com/superseriousbusiness/exif-terminator v0.4.0
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB
github.com/tdewolff/minify/v2 v2.12.0 github.com/tdewolff/minify/v2 v2.12.0
github.com/uptrace/bun v1.1.3 github.com/uptrace/bun v1.1.7
github.com/uptrace/bun/dialect/pgdialect v1.1.3 github.com/uptrace/bun/dialect/pgdialect v1.1.7
github.com/uptrace/bun/dialect/sqlitedialect v1.1.3 github.com/uptrace/bun/dialect/sqlitedialect v1.1.7
github.com/wagslane/go-password-validator v0.3.0 github.com/wagslane/go-password-validator v0.3.0
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d
@ -52,7 +52,7 @@ require (
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
golang.org/x/text v0.3.7 golang.org/x/text v0.3.7
gopkg.in/mcuadros/go-syslog.v2 v2.3.0 gopkg.in/mcuadros/go-syslog.v2 v2.3.0
modernc.org/sqlite v1.17.2 modernc.org/sqlite v1.18.1
mvdan.cc/xurls/v2 v2.3.0 mvdan.cc/xurls/v2 v2.3.0
) )
@ -128,7 +128,7 @@ require (
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32 // indirect golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
golang.org/x/tools v0.1.10 // indirect golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
@ -139,8 +139,8 @@ require (
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
lukechampine.com/uint128 v1.2.0 // indirect lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.36.0 // indirect modernc.org/cc/v3 v3.36.0 // indirect
modernc.org/ccgo/v3 v3.16.6 // indirect modernc.org/ccgo/v3 v3.16.8 // indirect
modernc.org/libc v1.16.7 // indirect modernc.org/libc v1.16.19 // indirect
modernc.org/mathutil v1.4.1 // indirect modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.1.1 // indirect modernc.org/memory v1.1.1 // indirect
modernc.org/opt v0.1.3 // indirect modernc.org/opt v0.1.3 // indirect

32
go.sum
View file

@ -410,7 +410,6 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo= github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo=
github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM=
@ -550,12 +549,12 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/uptrace/bun v1.1.3 h1:v62tsUyKjVCR5q7J49uckM6CVVTqMO26aV73F3G6RFk= github.com/uptrace/bun v1.1.7 h1:biOoh5dov69hQPBlaRsXSHoEOIEnCxFzQvUmbscSNJI=
github.com/uptrace/bun v1.1.3/go.mod h1:aQbKvxs7/n9MMef/b8lYOh5Rwlo4Jd5A31E4HlYNqSc= github.com/uptrace/bun v1.1.7/go.mod h1:Z2Pd3cRvNKbrYuL6Gp1XGjA9QEYz+rDz5KkEi9MZLnQ=
github.com/uptrace/bun/dialect/pgdialect v1.1.3 h1:EMRCC98YKSpo/EXyujsr+5v0PKYkRE0rwxJKKEcrOuE= github.com/uptrace/bun/dialect/pgdialect v1.1.7 h1:94GPc8RRC9AVoQ+4KCqRX2zScevsVfOttk13wm60/P8=
github.com/uptrace/bun/dialect/pgdialect v1.1.3/go.mod h1:2GJogfkVHmCKxt6N88vRbJNSUV5wfPym/rp6N25dShc= github.com/uptrace/bun/dialect/pgdialect v1.1.7/go.mod h1:kKHFmQIyBl0kvQDsoyrlXaKsceTH2TJnbCUFlK9QAmE=
github.com/uptrace/bun/dialect/sqlitedialect v1.1.3 h1:VN978Z9dIHobFSZADUGz2f8+rJANjDVHUHYmmoNKOj4= github.com/uptrace/bun/dialect/sqlitedialect v1.1.7 h1:xxc1n1nUdn6zqY6ji1ZkiaHQyop8J237uRyptqXGW08=
github.com/uptrace/bun/dialect/sqlitedialect v1.1.3/go.mod h1:7MjbsQYpEeCt05/FoNJqmekl5NvBp/aAFLsvmBgfP9A= github.com/uptrace/bun/dialect/sqlitedialect v1.1.7/go.mod h1:GjqiPWAa9JCLlv51mB1rjk8QRgwv6HlQ+IAtyrobfAY=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.14.0 h1:67bfuW9azCMwW/Jlq/C+VeihNpAuJMWkYPBig1gdi3A= github.com/valyala/fasthttp v1.14.0 h1:67bfuW9azCMwW/Jlq/C+VeihNpAuJMWkYPBig1gdi3A=
@ -783,8 +782,8 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32 h1:Js08h5hqB5xyWR789+QqueR6sDE8mk+YvpETZ+F6X9Y= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
@ -1002,9 +1001,9 @@ modernc.org/cc/v3 v3.36.0 h1:0kmRkTmqNidmu3c7BNDSdVHCxXCkWLmWmCIVX4LUboo=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccgo/v3 v3.16.6 h1:3l18poV+iUemQ98O3X5OMr97LOqlzis+ytivU4NqGhA=
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccgo/v3 v3.16.8 h1:G0QNlTqI5uVgczBWfGKs7B++EPwCfXPWGD2MdeKloDs=
modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
@ -1012,8 +1011,9 @@ modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
modernc.org/libc v1.16.7 h1:qzQtHhsZNpVPpeCu+aMIQldXeV1P0vRhSqCL0nOIJOA= modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= modernc.org/libc v1.16.19 h1:S8flPn5ZeXx6iw/8yNa986hwTQDrY8RXU7tObZuAozo=
modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8= modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
@ -1022,16 +1022,14 @@ modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.17.2 h1:TjmF36Wi5QcPYqRoAacV1cAyJ7xB/CD0ExpVUEMebnw= modernc.org/sqlite v1.18.1 h1:ko32eKt3jf7eqIkCgPAeHMBXw3riNSLhl2f3loEF7o8=
modernc.org/sqlite v1.17.2/go.mod h1:GOQmuiXd6pTTes1Fi2s9apiCcD/wbKQtBZ0Nw6/etjM= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao=
modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM= modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM=
modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=
mvdan.cc/xurls/v2 v2.3.0 h1:59Olnbt67UKpxF1EwVBopJvkSUBmgtb468E4GVWIZ1I= mvdan.cc/xurls/v2 v2.3.0 h1:59Olnbt67UKpxF1EwVBopJvkSUBmgtb468E4GVWIZ1I=
mvdan.cc/xurls/v2 v2.3.0/go.mod h1:AjuTy7gEiUArFMjgBBDU4SMxlfUYsRokpJQgNWOt3e4= mvdan.cc/xurls/v2 v2.3.0/go.mod h1:AjuTy7gEiUArFMjgBBDU4SMxlfUYsRokpJQgNWOt3e4=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

View file

@ -529,6 +529,10 @@ func ExtractEmoji(i Emojiable) (*gtsmodel.Emoji, error) {
} }
emoji.ImageRemoteURL = imageURL.String() emoji.ImageRemoteURL = imageURL.String()
// assume false for both to begin
emoji.Disabled = new(bool)
emoji.VisibleInPicker = new(bool)
return emoji, nil return emoji, nil
} }

View file

@ -70,8 +70,8 @@ func (suite *AccountVerifyTestSuite) TestAccountVerifyGet() {
suite.Equal(testAccount.Username, apimodelAccount.Username) suite.Equal(testAccount.Username, apimodelAccount.Username)
suite.Equal(testAccount.Username, apimodelAccount.Acct) suite.Equal(testAccount.Username, apimodelAccount.Acct)
suite.Equal(testAccount.DisplayName, apimodelAccount.DisplayName) suite.Equal(testAccount.DisplayName, apimodelAccount.DisplayName)
suite.Equal(testAccount.Locked, apimodelAccount.Locked) suite.Equal(*testAccount.Locked, apimodelAccount.Locked)
suite.Equal(testAccount.Bot, apimodelAccount.Bot) suite.Equal(*testAccount.Bot, apimodelAccount.Bot)
suite.WithinDuration(testAccount.CreatedAt, createdAt, 30*time.Second) // we lose a bit of accuracy serializing so fuzz this a bit suite.WithinDuration(testAccount.CreatedAt, createdAt, 30*time.Second) // we lose a bit of accuracy serializing so fuzz this a bit
suite.Equal(testAccount.URL, apimodelAccount.URL) suite.Equal(testAccount.URL, apimodelAccount.URL)
suite.Equal("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpeg", apimodelAccount.Avatar) suite.Equal("http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpeg", apimodelAccount.Avatar)

View file

@ -87,7 +87,7 @@ func (m *Module) AccountActionPOSTHandler(c *gin.Context) {
return return
} }
if !authed.User.Admin { if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID) err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet) api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return return

View file

@ -123,7 +123,7 @@ func (m *Module) DomainBlocksPOSTHandler(c *gin.Context) {
return return
} }
if !authed.User.Admin { if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID) err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet) api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return return

View file

@ -75,7 +75,7 @@ func (m *Module) DomainBlockDELETEHandler(c *gin.Context) {
return return
} }
if !authed.User.Admin { if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID) err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet) api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return return

View file

@ -76,7 +76,7 @@ func (m *Module) DomainBlockGETHandler(c *gin.Context) {
return return
} }
if !authed.User.Admin { if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID) err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet) api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return return

View file

@ -81,7 +81,7 @@ func (m *Module) DomainBlocksGETHandler(c *gin.Context) {
return return
} }
if !authed.User.Admin { if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID) err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet) api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return return

View file

@ -90,7 +90,7 @@ func (m *Module) EmojiCreatePOSTHandler(c *gin.Context) {
return return
} }
if !authed.User.Admin { if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID) err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet) api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return return

View file

@ -97,9 +97,9 @@ func (suite *EmojiCreateTestSuite) TestEmojiCreate() {
suite.Equal("image/png", dbEmoji.ImageStaticContentType) suite.Equal("image/png", dbEmoji.ImageStaticContentType)
suite.Equal(36702, dbEmoji.ImageFileSize) suite.Equal(36702, dbEmoji.ImageFileSize)
suite.Equal(10413, dbEmoji.ImageStaticFileSize) suite.Equal(10413, dbEmoji.ImageStaticFileSize)
suite.False(dbEmoji.Disabled) suite.False(*dbEmoji.Disabled)
suite.NotEmpty(dbEmoji.URI) suite.NotEmpty(dbEmoji.URI)
suite.True(dbEmoji.VisibleInPicker) suite.True(*dbEmoji.VisibleInPicker)
suite.Empty(dbEmoji.CategoryID) suite.Empty(dbEmoji.CategoryID)
// emoji should be in storage // emoji should be in storage

View file

@ -74,7 +74,7 @@ func (m *Module) MediaCleanupPOSTHandler(c *gin.Context) {
return return
} }
if !authed.User.Admin { if !*authed.User.Admin {
err := fmt.Errorf("user %s not an admin", authed.User.ID) err := fmt.Errorf("user %s not an admin", authed.User.ID)
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet) api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return return

View file

@ -35,7 +35,7 @@ type MediaCleanupTestSuite struct {
func (suite *MediaCleanupTestSuite) TestMediaCleanup() { func (suite *MediaCleanupTestSuite) TestMediaCleanup() {
testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_2"] testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_2"]
suite.True(testAttachment.Cached) suite.True(*testAttachment.Cached)
// set up the request // set up the request
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
@ -55,12 +55,12 @@ func (suite *MediaCleanupTestSuite) TestMediaCleanup() {
suite.NoError(err) suite.NoError(err)
// the media should no longer be cached // the media should no longer be cached
suite.False(prunedAttachment.Cached) suite.False(*prunedAttachment.Cached)
} }
func (suite *MediaCleanupTestSuite) TestMediaCleanupNoArg() { func (suite *MediaCleanupTestSuite) TestMediaCleanupNoArg() {
testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_2"] testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_2"]
suite.True(testAttachment.Cached) suite.True(*testAttachment.Cached)
println("TIME: ", testAttachment.CreatedAt.String()) println("TIME: ", testAttachment.CreatedAt.String())
// set up the request // set up the request
@ -81,12 +81,12 @@ func (suite *MediaCleanupTestSuite) TestMediaCleanupNoArg() {
suite.NoError(err) suite.NoError(err)
// the media should no longer be cached // the media should no longer be cached
suite.False(prunedAttachment.Cached) suite.False(*prunedAttachment.Cached)
} }
func (suite *MediaCleanupTestSuite) TestMediaCleanupNotOldEnough() { func (suite *MediaCleanupTestSuite) TestMediaCleanupNotOldEnough() {
testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_2"] testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_2"]
suite.True(testAttachment.Cached) suite.True(*testAttachment.Cached)
// set up the request // set up the request
recorder := httptest.NewRecorder() recorder := httptest.NewRecorder()
@ -106,7 +106,7 @@ func (suite *MediaCleanupTestSuite) TestMediaCleanupNotOldEnough() {
suite.NoError(err) suite.NoError(err)
// the media should still be cached // the media should still be cached
suite.True(prunedAttachment.Cached) suite.True(*prunedAttachment.Cached)
} }
func TestMediaCleanupTestSuite(t *testing.T) { func TestMediaCleanupTestSuite(t *testing.T) {

View file

@ -320,13 +320,13 @@ func ensureUserIsAuthorizedOrRedirect(ctx *gin.Context, user *gtsmodel.User, acc
return return
} }
if !user.Approved { if !*user.Approved {
ctx.Redirect(http.StatusSeeOther, WaitForApprovalPath) ctx.Redirect(http.StatusSeeOther, WaitForApprovalPath)
redirected = true redirected = true
return return
} }
if user.Disabled || !account.SuspendedAt.IsZero() { if *user.Disabled || !account.SuspendedAt.IsZero() {
ctx.Redirect(http.StatusSeeOther, AccountDisabledPath) ctx.Redirect(http.StatusSeeOther, AccountDisabledPath)
redirected = true redirected = true
return return

View file

@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/api/client/auth" "github.com/superseriousbusiness/gotosocial/internal/api/client/auth"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
type AuthAuthorizeTestSuite struct { type AuthAuthorizeTestSuite struct {
@ -19,7 +20,7 @@ type AuthAuthorizeTestSuite struct {
type authorizeHandlerTestCase struct { type authorizeHandlerTestCase struct {
description string description string
mutateUserAccount func(*gtsmodel.User, *gtsmodel.Account) mutateUserAccount func(*gtsmodel.User, *gtsmodel.Account) []string
expectedStatusCode int expectedStatusCode int
expectedLocationHeader string expectedLocationHeader string
} }
@ -28,40 +29,44 @@ func (suite *AuthAuthorizeTestSuite) TestAccountAuthorizeHandler() {
tests := []authorizeHandlerTestCase{ tests := []authorizeHandlerTestCase{
{ {
description: "user has their email unconfirmed", description: "user has their email unconfirmed",
mutateUserAccount: func(user *gtsmodel.User, account *gtsmodel.Account) { mutateUserAccount: func(user *gtsmodel.User, account *gtsmodel.Account) []string {
// nothing to do, weed_lord420 already has their email unconfirmed // nothing to do, weed_lord420 already has their email unconfirmed
return nil
}, },
expectedStatusCode: http.StatusSeeOther, expectedStatusCode: http.StatusSeeOther,
expectedLocationHeader: auth.CheckYourEmailPath, expectedLocationHeader: auth.CheckYourEmailPath,
}, },
{ {
description: "user has their email confirmed but is not approved", description: "user has their email confirmed but is not approved",
mutateUserAccount: func(user *gtsmodel.User, account *gtsmodel.Account) { mutateUserAccount: func(user *gtsmodel.User, account *gtsmodel.Account) []string {
user.ConfirmedAt = time.Now() user.ConfirmedAt = time.Now()
user.Email = user.UnconfirmedEmail user.Email = user.UnconfirmedEmail
return []string{"confirmed_at", "email"}
}, },
expectedStatusCode: http.StatusSeeOther, expectedStatusCode: http.StatusSeeOther,
expectedLocationHeader: auth.WaitForApprovalPath, expectedLocationHeader: auth.WaitForApprovalPath,
}, },
{ {
description: "user has their email confirmed and is approved, but User entity has been disabled", description: "user has their email confirmed and is approved, but User entity has been disabled",
mutateUserAccount: func(user *gtsmodel.User, account *gtsmodel.Account) { mutateUserAccount: func(user *gtsmodel.User, account *gtsmodel.Account) []string {
user.ConfirmedAt = time.Now() user.ConfirmedAt = time.Now()
user.Email = user.UnconfirmedEmail user.Email = user.UnconfirmedEmail
user.Approved = true user.Approved = testrig.TrueBool()
user.Disabled = true user.Disabled = testrig.TrueBool()
return []string{"confirmed_at", "email", "approved", "disabled"}
}, },
expectedStatusCode: http.StatusSeeOther, expectedStatusCode: http.StatusSeeOther,
expectedLocationHeader: auth.AccountDisabledPath, expectedLocationHeader: auth.AccountDisabledPath,
}, },
{ {
description: "user has their email confirmed and is approved, but Account entity has been suspended", description: "user has their email confirmed and is approved, but Account entity has been suspended",
mutateUserAccount: func(user *gtsmodel.User, account *gtsmodel.Account) { mutateUserAccount: func(user *gtsmodel.User, account *gtsmodel.Account) []string {
user.ConfirmedAt = time.Now() user.ConfirmedAt = time.Now()
user.Email = user.UnconfirmedEmail user.Email = user.UnconfirmedEmail
user.Approved = true user.Approved = testrig.TrueBool()
user.Disabled = false user.Disabled = testrig.FalseBool()
account.SuspendedAt = time.Now() account.SuspendedAt = time.Now()
return []string{"confirmed_at", "email", "approved", "disabled"}
}, },
expectedStatusCode: http.StatusSeeOther, expectedStatusCode: http.StatusSeeOther,
expectedLocationHeader: auth.AccountDisabledPath, expectedLocationHeader: auth.AccountDisabledPath,
@ -81,12 +86,13 @@ func (suite *AuthAuthorizeTestSuite) TestAccountAuthorizeHandler() {
panic(fmt.Errorf("failed on case %s: %w", testCase.description, err)) panic(fmt.Errorf("failed on case %s: %w", testCase.description, err))
} }
testCase.mutateUserAccount(user, account) updatingColumns := testCase.mutateUserAccount(user, account)
testCase.description = fmt.Sprintf("%s, %t, %s", user.Email, user.Disabled, account.SuspendedAt) testCase.description = fmt.Sprintf("%s, %t, %s", user.Email, *user.Disabled, account.SuspendedAt)
updatingColumns = append(updatingColumns, "updated_at")
user.UpdatedAt = time.Now() user.UpdatedAt = time.Now()
err := suite.db.UpdateByPrimaryKey(context.Background(), user) err := suite.db.UpdateByPrimaryKey(context.Background(), user, updatingColumns...)
suite.NoError(err) suite.NoError(err)
_, err = suite.db.UpdateAccount(context.Background(), account) _, err = suite.db.UpdateAccount(context.Background(), account)
suite.NoError(err) suite.NoError(err)

View file

@ -124,7 +124,7 @@ func (m *Module) InstanceUpdatePATCHHandler(c *gin.Context) {
return return
} }
if !authed.User.Admin { if !*authed.User.Admin {
err := errors.New("user is not an admin so cannot update instance settings") err := errors.New("user is not an admin so cannot update instance settings")
api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet) api.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGet)
return return

View file

@ -190,7 +190,7 @@ func (suite *InstancePeersGetTestSuite) TestInstancePeersGetAllWithObfuscated()
Domain: "omg.just.the.worst.org.ever", Domain: "omg.just.the.worst.org.ever",
CreatedByAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", CreatedByAccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
PublicComment: "just absolutely the worst, wowza", PublicComment: "just absolutely the worst, wowza",
Obfuscate: true, Obfuscate: testrig.TrueBool(),
}) })
suite.NoError(err) suite.NoError(err)

View file

@ -469,8 +469,8 @@ func (suite *InboxPostTestSuite) TestPostDelete() {
suite.Empty(dbAccount.HeaderRemoteURL) suite.Empty(dbAccount.HeaderRemoteURL)
suite.Empty(dbAccount.Reason) suite.Empty(dbAccount.Reason)
suite.Empty(dbAccount.Fields) suite.Empty(dbAccount.Fields)
suite.True(dbAccount.HideCollections) suite.True(*dbAccount.HideCollections)
suite.False(dbAccount.Discoverable) suite.False(*dbAccount.Discoverable)
suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second) suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second)
suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin) suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin)
} }

View file

@ -67,12 +67,12 @@ func (m *Module) TokenCheck(c *gin.Context) {
return return
} }
if !user.Approved { if !*user.Approved {
log.Warnf("authenticated user %s's account was never approved by an admin", userID) log.Warnf("authenticated user %s's account was never approved by an admin", userID)
return return
} }
if user.Disabled { if *user.Disabled {
log.Warnf("authenticated user %s's account was disabled'", userID) log.Warnf("authenticated user %s's account was disabled'", userID)
return return
} }

View file

@ -103,16 +103,16 @@ func copyAccount(account *gtsmodel.Account) *gtsmodel.Account {
Fields: account.Fields, Fields: account.Fields,
Note: account.Note, Note: account.Note,
NoteRaw: account.NoteRaw, NoteRaw: account.NoteRaw,
Memorial: account.Memorial, Memorial: copyBoolPtr(account.Memorial),
MovedToAccountID: account.MovedToAccountID, MovedToAccountID: account.MovedToAccountID,
Bot: copyBoolPtr(account.Bot),
CreatedAt: account.CreatedAt, CreatedAt: account.CreatedAt,
UpdatedAt: account.UpdatedAt, UpdatedAt: account.UpdatedAt,
Bot: account.Bot,
Reason: account.Reason, Reason: account.Reason,
Locked: account.Locked, Locked: copyBoolPtr(account.Locked),
Discoverable: account.Discoverable, Discoverable: copyBoolPtr(account.Discoverable),
Privacy: account.Privacy, Privacy: account.Privacy,
Sensitive: account.Sensitive, Sensitive: copyBoolPtr(account.Sensitive),
Language: account.Language, Language: account.Language,
StatusFormat: account.StatusFormat, StatusFormat: account.StatusFormat,
URI: account.URI, URI: account.URI,
@ -131,7 +131,7 @@ func copyAccount(account *gtsmodel.Account) *gtsmodel.Account {
SensitizedAt: account.SensitizedAt, SensitizedAt: account.SensitizedAt,
SilencedAt: account.SilencedAt, SilencedAt: account.SilencedAt,
SuspendedAt: account.SuspendedAt, SuspendedAt: account.SuspendedAt,
HideCollections: account.HideCollections, HideCollections: copyBoolPtr(account.HideCollections),
SuspensionOrigin: account.SuspensionOrigin, SuspensionOrigin: account.SuspensionOrigin,
} }
} }

View file

@ -102,9 +102,9 @@ func copyStatus(status *gtsmodel.Status) *gtsmodel.Status {
Mentions: nil, Mentions: nil,
EmojiIDs: status.EmojiIDs, EmojiIDs: status.EmojiIDs,
Emojis: nil, Emojis: nil,
Local: copyBoolPtr(status.Local),
CreatedAt: status.CreatedAt, CreatedAt: status.CreatedAt,
UpdatedAt: status.UpdatedAt, UpdatedAt: status.UpdatedAt,
Local: status.Local,
AccountID: status.AccountID, AccountID: status.AccountID,
Account: nil, Account: nil,
AccountURI: status.AccountURI, AccountURI: status.AccountURI,
@ -119,15 +119,15 @@ func copyStatus(status *gtsmodel.Status) *gtsmodel.Status {
BoostOfAccount: nil, BoostOfAccount: nil,
ContentWarning: status.ContentWarning, ContentWarning: status.ContentWarning,
Visibility: status.Visibility, Visibility: status.Visibility,
Sensitive: status.Sensitive, Sensitive: copyBoolPtr(status.Sensitive),
Language: status.Language, Language: status.Language,
CreatedWithApplicationID: status.CreatedWithApplicationID, CreatedWithApplicationID: status.CreatedWithApplicationID,
Federated: status.Federated,
Boostable: status.Boostable,
Replyable: status.Replyable,
Likeable: status.Likeable,
ActivityStreamsType: status.ActivityStreamsType, ActivityStreamsType: status.ActivityStreamsType,
Text: status.Text, Text: status.Text,
Pinned: status.Pinned, Pinned: copyBoolPtr(status.Pinned),
Federated: copyBoolPtr(status.Federated),
Boostable: copyBoolPtr(status.Boostable),
Replyable: copyBoolPtr(status.Replyable),
Likeable: copyBoolPtr(status.Likeable),
} }
} }

View file

@ -72,6 +72,32 @@ func (suite *StatusCacheTestSuite) TestStatusCache() {
} }
} }
func (suite *StatusCacheTestSuite) TestBoolPointerCopying() {
originalStatus := suite.data["local_account_1_status_1"]
// mark the status as pinned + cache it
pinned := true
originalStatus.Pinned = &pinned
suite.cache.Put(originalStatus)
// retrieve it
cachedStatus, ok := suite.cache.GetByID(originalStatus.ID)
if !ok {
suite.FailNow("status wasn't retrievable from cache")
}
// we should be able to change the original status values + cached
// values independently since they use different pointers
suite.True(*cachedStatus.Pinned)
*originalStatus.Pinned = false
suite.False(*originalStatus.Pinned)
suite.True(*cachedStatus.Pinned)
*originalStatus.Pinned = true
*cachedStatus.Pinned = false
suite.True(*originalStatus.Pinned)
suite.False(*cachedStatus.Pinned)
}
func TestStatusCache(t *testing.T) { func TestStatusCache(t *testing.T) {
suite.Run(t, &StatusCacheTestSuite{}) suite.Run(t, &StatusCacheTestSuite{})
} }

31
internal/cache/util.go vendored Normal file
View file

@ -0,0 +1,31 @@
/*
GoToSocial
Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cache
// copyBoolPtr returns a bool pointer with the same value as the pointer passed into it.
//
// Useful when copying things from the cache to a caller.
func copyBoolPtr(in *bool) *bool {
if in == nil {
return nil
}
b := new(bool)
*b = *in
return b
}

View file

@ -62,9 +62,11 @@ type Basic interface {
// The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice. // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
Put(ctx context.Context, i interface{}) Error Put(ctx context.Context, i interface{}) Error
// UpdateByPrimaryKey updates all values of i based on its primary key. // UpdateByPrimaryKey updates values of i based on its primary key.
// If any columns are specified, these will be updated exclusively.
// Otherwise, the whole model will be updated.
// The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice. // The given interface i will be set to the result of the query, whatever it is. Use a pointer or a slice.
UpdateByPrimaryKey(ctx context.Context, i interface{}) Error UpdateByPrimaryKey(ctx context.Context, i interface{}, columns ...string) Error
// UpdateWhere updates column key of interface i with the given value, where the given parameters apply. // UpdateWhere updates column key of interface i with the given value, where the given parameters apply.
UpdateWhere(ctx context.Context, where []Where, key string, value interface{}, i interface{}) Error UpdateWhere(ctx context.Context, where []Where, key string, value interface{}, i interface{}) Error

View file

@ -164,15 +164,15 @@ func (a *accountDB) GetAccountLastPosted(ctx context.Context, accountID string)
} }
func (a *accountDB) SetAccountHeaderOrAvatar(ctx context.Context, mediaAttachment *gtsmodel.MediaAttachment, accountID string) db.Error { func (a *accountDB) SetAccountHeaderOrAvatar(ctx context.Context, mediaAttachment *gtsmodel.MediaAttachment, accountID string) db.Error {
if mediaAttachment.Avatar && mediaAttachment.Header { if *mediaAttachment.Avatar && *mediaAttachment.Header {
return errors.New("one media attachment cannot be both header and avatar") return errors.New("one media attachment cannot be both header and avatar")
} }
var headerOrAVI string var headerOrAVI string
switch { switch {
case mediaAttachment.Avatar: case *mediaAttachment.Avatar:
headerOrAVI = "avatar" headerOrAVI = "avatar"
case mediaAttachment.Header: case *mediaAttachment.Header:
headerOrAVI = "header" headerOrAVI = "header"
default: default:
return errors.New("given media attachment was neither a header nor an avatar") return errors.New("given media attachment was neither a header nor an avatar")

View file

@ -93,11 +93,11 @@ func (suite *AccountTestSuite) TestInsertAccountWithDefaults() {
suite.Equal("en", newAccount.Language) suite.Equal("en", newAccount.Language)
suite.WithinDuration(time.Now(), newAccount.CreatedAt, 30*time.Second) suite.WithinDuration(time.Now(), newAccount.CreatedAt, 30*time.Second)
suite.WithinDuration(time.Now(), newAccount.UpdatedAt, 30*time.Second) suite.WithinDuration(time.Now(), newAccount.UpdatedAt, 30*time.Second)
suite.False(newAccount.Memorial) suite.False(*newAccount.Memorial)
suite.False(newAccount.Bot) suite.False(*newAccount.Bot)
suite.False(newAccount.Discoverable) suite.False(*newAccount.Discoverable)
suite.False(newAccount.Sensitive) suite.False(*newAccount.Sensitive)
suite.False(newAccount.HideCollections) suite.False(*newAccount.HideCollections)
} }
func TestAccountTestSuite(t *testing.T) { func TestAccountTestSuite(t *testing.T) {

View file

@ -142,6 +142,8 @@ func (a *adminDB) NewSignup(ctx context.Context, username string, reason string,
return nil, err return nil, err
} }
// if we don't require moderator approval, just pre-approve the user
approved := !requireApproval
u := &gtsmodel.User{ u := &gtsmodel.User{
ID: newUserID, ID: newUserID,
AccountID: acct.ID, AccountID: acct.ID,
@ -151,7 +153,7 @@ func (a *adminDB) NewSignup(ctx context.Context, username string, reason string,
Locale: locale, Locale: locale,
UnconfirmedEmail: email, UnconfirmedEmail: email,
CreatedByApplicationID: appID, CreatedByApplicationID: appID,
Approved: !requireApproval, // if we don't require moderator approval, just pre-approve the user Approved: &approved,
} }
if emailVerified { if emailVerified {
@ -161,8 +163,10 @@ func (a *adminDB) NewSignup(ctx context.Context, username string, reason string,
} }
if admin { if admin {
u.Admin = true admin := true
u.Moderator = true moderator := true
u.Admin = &admin
u.Moderator = &moderator
} }
if _, err = a.conn. if _, err = a.conn.

View file

@ -94,10 +94,11 @@ func (b *basicDB) DeleteWhere(ctx context.Context, where []db.Where, i interface
return b.conn.ProcessError(err) return b.conn.ProcessError(err)
} }
func (b *basicDB) UpdateByPrimaryKey(ctx context.Context, i interface{}) db.Error { func (b *basicDB) UpdateByPrimaryKey(ctx context.Context, i interface{}, columns ...string) db.Error {
q := b.conn. q := b.conn.
NewUpdate(). NewUpdate().
Model(i). Model(i).
Column(columns...).
WherePK() WherePK()
_, err := q.Exec(ctx) _, err := q.Exec(ctx)

View file

@ -21,6 +21,7 @@ package bundb_test
import ( import (
"context" "context"
"testing" "testing"
"time"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/db"
@ -39,6 +40,75 @@ func (suite *BasicTestSuite) TestGetAccountByID() {
suite.NoError(err) suite.NoError(err)
} }
func (suite *BasicTestSuite) TestPutAccountWithBunDefaultFields() {
testAccount := &gtsmodel.Account{
ID: "01GADR1AH9VCKH8YYCM86XSZ00",
Username: "test",
URI: "https://example.org/users/test",
URL: "https://example.org/@test",
InboxURI: "https://example.org/users/test/inbox",
OutboxURI: "https://example.org/users/test/outbox",
ActorType: "Person",
PublicKeyURI: "https://example.org/test#main-key",
}
if err := suite.db.Put(context.Background(), testAccount); err != nil {
suite.FailNow(err.Error())
}
a := &gtsmodel.Account{}
if err := suite.db.GetByID(context.Background(), testAccount.ID, a); err != nil {
suite.FailNow(err.Error())
}
// check all fields are set as expected, including database defaults
suite.Equal(testAccount.ID, a.ID)
suite.WithinDuration(time.Now(), a.CreatedAt, 5*time.Second)
suite.WithinDuration(time.Now(), a.UpdatedAt, 5*time.Second)
suite.Equal(testAccount.Username, a.Username)
suite.Empty(a.Domain)
suite.Empty(a.AvatarMediaAttachmentID)
suite.Nil(a.AvatarMediaAttachment)
suite.Empty(a.AvatarRemoteURL)
suite.Empty(a.HeaderMediaAttachmentID)
suite.Nil(a.HeaderMediaAttachment)
suite.Empty(a.HeaderRemoteURL)
suite.Empty(a.DisplayName)
suite.Nil(a.Fields)
suite.Empty(a.Note)
suite.Empty(a.NoteRaw)
suite.False(*a.Memorial)
suite.Empty(a.AlsoKnownAs)
suite.Empty(a.MovedToAccountID)
suite.False(*a.Bot)
suite.Empty(a.Reason)
// Locked is especially important, since it's a bool that defaults
// to true, which is why we use pointers for bools in the first place
suite.True(*a.Locked)
suite.False(*a.Discoverable)
suite.Empty(a.Privacy)
suite.False(*a.Sensitive)
suite.Equal("en", a.Language)
suite.Empty(a.StatusFormat)
suite.Equal(testAccount.URI, a.URI)
suite.Equal(testAccount.URL, a.URL)
suite.Zero(testAccount.LastWebfingeredAt)
suite.Equal(testAccount.InboxURI, a.InboxURI)
suite.Equal(testAccount.OutboxURI, a.OutboxURI)
suite.Empty(a.FollowingURI)
suite.Empty(a.FollowersURI)
suite.Empty(a.FeaturedCollectionURI)
suite.Equal(testAccount.ActorType, a.ActorType)
suite.Nil(a.PrivateKey)
suite.Nil(a.PublicKey)
suite.Equal(testAccount.PublicKeyURI, a.PublicKeyURI)
suite.Zero(a.SensitizedAt)
suite.Zero(a.SilencedAt)
suite.Zero(a.SuspendedAt)
suite.False(*a.HideCollections)
suite.Empty(a.SuspensionOrigin)
}
func (suite *BasicTestSuite) TestGetAllStatuses() { func (suite *BasicTestSuite) TestGetAllStatuses() {
s := []*gtsmodel.Status{} s := []*gtsmodel.Status{}
err := suite.db.GetAll(context.Background(), &s) err := suite.db.GetAll(context.Background(), &s)

View file

@ -409,15 +409,17 @@ func (ps *bunDBService) TagStringsToTags(ctx context.Context, tags []string, ori
tag.FirstSeenFromAccountID = originAccountID tag.FirstSeenFromAccountID = originAccountID
tag.CreatedAt = time.Now() tag.CreatedAt = time.Now()
tag.UpdatedAt = time.Now() tag.UpdatedAt = time.Now()
tag.Useable = true useable := true
tag.Listable = true tag.Useable = &useable
listable := true
tag.Listable = &listable
} else { } else {
return nil, fmt.Errorf("error getting tag with name %s: %s", t, err) return nil, fmt.Errorf("error getting tag with name %s: %s", t, err)
} }
} }
// bail already if the tag isn't useable // bail already if the tag isn't useable
if !tag.Useable { if !*tag.Useable {
continue continue
} }
tag.LastStatusAt = time.Now() tag.LastStatusAt = time.Now()

View file

@ -27,6 +27,7 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/id" "github.com/superseriousbusiness/gotosocial/internal/id"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
func (suite *NotificationTestSuite) spamNotifs() { func (suite *NotificationTestSuite) spamNotifs() {
@ -71,7 +72,7 @@ func (suite *NotificationTestSuite) spamNotifs() {
TargetAccountID: targetAccountID, TargetAccountID: targetAccountID,
OriginAccountID: originAccountID, OriginAccountID: originAccountID,
StatusID: statusID, StatusID: statusID,
Read: false, Read: testrig.FalseBool(),
} }
if err := suite.db.Put(context.Background(), notif); err != nil { if err := suite.db.Put(context.Background(), notif); err != nil {

View file

@ -114,8 +114,8 @@ func (r *relationshipDB) GetRelationship(ctx context.Context, requestingAccount
} else { } else {
// follow exists so we can fill these fields out... // follow exists so we can fill these fields out...
rel.Following = true rel.Following = true
rel.ShowingReblogs = follow.ShowReblogs rel.ShowingReblogs = *follow.ShowReblogs
rel.Notifying = follow.Notify rel.Notifying = *follow.Notify
} }
// check if the target account follows the requesting account // check if the target account follows the requesting account

View file

@ -43,10 +43,10 @@ func (suite *StatusTestSuite) TestGetStatusByID() {
suite.Nil(status.BoostOfAccount) suite.Nil(status.BoostOfAccount)
suite.Nil(status.InReplyTo) suite.Nil(status.InReplyTo)
suite.Nil(status.InReplyToAccount) suite.Nil(status.InReplyToAccount)
suite.True(status.Federated) suite.True(*status.Federated)
suite.True(status.Boostable) suite.True(*status.Boostable)
suite.True(status.Replyable) suite.True(*status.Replyable)
suite.True(status.Likeable) suite.True(*status.Likeable)
} }
func (suite *StatusTestSuite) TestGetStatusByURI() { func (suite *StatusTestSuite) TestGetStatusByURI() {
@ -61,10 +61,10 @@ func (suite *StatusTestSuite) TestGetStatusByURI() {
suite.Nil(status.BoostOfAccount) suite.Nil(status.BoostOfAccount)
suite.Nil(status.InReplyTo) suite.Nil(status.InReplyTo)
suite.Nil(status.InReplyToAccount) suite.Nil(status.InReplyToAccount)
suite.True(status.Federated) suite.True(*status.Federated)
suite.True(status.Boostable) suite.True(*status.Boostable)
suite.False(status.Replyable) suite.False(*status.Replyable)
suite.False(status.Likeable) suite.False(*status.Likeable)
} }
func (suite *StatusTestSuite) TestGetStatusWithExtras() { func (suite *StatusTestSuite) TestGetStatusWithExtras() {
@ -78,10 +78,10 @@ func (suite *StatusTestSuite) TestGetStatusWithExtras() {
suite.NotEmpty(status.Tags) suite.NotEmpty(status.Tags)
suite.NotEmpty(status.Attachments) suite.NotEmpty(status.Attachments)
suite.NotEmpty(status.Emojis) suite.NotEmpty(status.Emojis)
suite.True(status.Federated) suite.True(*status.Federated)
suite.True(status.Boostable) suite.True(*status.Boostable)
suite.True(status.Replyable) suite.True(*status.Replyable)
suite.True(status.Likeable) suite.True(*status.Likeable)
} }
func (suite *StatusTestSuite) TestGetStatusWithMention() { func (suite *StatusTestSuite) TestGetStatusWithMention() {
@ -95,10 +95,10 @@ func (suite *StatusTestSuite) TestGetStatusWithMention() {
suite.NotEmpty(status.MentionIDs) suite.NotEmpty(status.MentionIDs)
suite.NotEmpty(status.InReplyToID) suite.NotEmpty(status.InReplyToID)
suite.NotEmpty(status.InReplyToAccountID) suite.NotEmpty(status.InReplyToAccountID)
suite.True(status.Federated) suite.True(*status.Federated)
suite.True(status.Boostable) suite.True(*status.Boostable)
suite.True(status.Replyable) suite.True(*status.Replyable)
suite.True(status.Likeable) suite.True(*status.Likeable)
} }
func (suite *StatusTestSuite) TestGetStatusTwice() { func (suite *StatusTestSuite) TestGetStatusTwice() {

View file

@ -46,7 +46,7 @@ func (suite *StatusTestSuite) TestDereferenceSimpleStatus() {
suite.Equal("https://unknown-instance.com/users/@brand_new_person/01FE4NTHKWW7THT67EF10EB839", status.URL) suite.Equal("https://unknown-instance.com/users/@brand_new_person/01FE4NTHKWW7THT67EF10EB839", status.URL)
suite.Equal("Hello world!", status.Content) suite.Equal("Hello world!", status.Content)
suite.Equal("https://unknown-instance.com/users/brand_new_person", status.AccountURI) suite.Equal("https://unknown-instance.com/users/brand_new_person", status.AccountURI)
suite.False(status.Local) suite.False(*status.Local)
suite.Empty(status.ContentWarning) suite.Empty(status.ContentWarning)
suite.Equal(gtsmodel.VisibilityPublic, status.Visibility) suite.Equal(gtsmodel.VisibilityPublic, status.Visibility)
suite.Equal(ap.ObjectNote, status.ActivityStreamsType) suite.Equal(ap.ObjectNote, status.ActivityStreamsType)
@ -55,16 +55,16 @@ func (suite *StatusTestSuite) TestDereferenceSimpleStatus() {
dbStatus, err := suite.db.GetStatusByURI(context.Background(), status.URI) dbStatus, err := suite.db.GetStatusByURI(context.Background(), status.URI)
suite.NoError(err) suite.NoError(err)
suite.Equal(status.ID, dbStatus.ID) suite.Equal(status.ID, dbStatus.ID)
suite.True(dbStatus.Federated) suite.True(*dbStatus.Federated)
suite.True(dbStatus.Boostable) suite.True(*dbStatus.Boostable)
suite.True(dbStatus.Replyable) suite.True(*dbStatus.Replyable)
suite.True(dbStatus.Likeable) suite.True(*dbStatus.Likeable)
// account should be in the database now too // account should be in the database now too
account, err := suite.db.GetAccountByURI(context.Background(), status.AccountURI) account, err := suite.db.GetAccountByURI(context.Background(), status.AccountURI)
suite.NoError(err) suite.NoError(err)
suite.NotNil(account) suite.NotNil(account)
suite.True(account.Discoverable) suite.True(*account.Discoverable)
suite.Equal("https://unknown-instance.com/users/brand_new_person", account.URI) suite.Equal("https://unknown-instance.com/users/brand_new_person", account.URI)
suite.Equal("hey I'm a new person, your instance hasn't seen me yet uwu", account.Note) suite.Equal("hey I'm a new person, your instance hasn't seen me yet uwu", account.Note)
suite.Equal("Geoff Brando New Personson", account.DisplayName) suite.Equal("Geoff Brando New Personson", account.DisplayName)
@ -86,7 +86,7 @@ func (suite *StatusTestSuite) TestDereferenceStatusWithMention() {
suite.Equal("https://unknown-instance.com/users/@brand_new_person/01FE5Y30E3W4P7TRE0R98KAYQV", status.URL) suite.Equal("https://unknown-instance.com/users/@brand_new_person/01FE5Y30E3W4P7TRE0R98KAYQV", status.URL)
suite.Equal("Hey @the_mighty_zork@localhost:8080 how's it going?", status.Content) suite.Equal("Hey @the_mighty_zork@localhost:8080 how's it going?", status.Content)
suite.Equal("https://unknown-instance.com/users/brand_new_person", status.AccountURI) suite.Equal("https://unknown-instance.com/users/brand_new_person", status.AccountURI)
suite.False(status.Local) suite.False(*status.Local)
suite.Empty(status.ContentWarning) suite.Empty(status.ContentWarning)
suite.Equal(gtsmodel.VisibilityPublic, status.Visibility) suite.Equal(gtsmodel.VisibilityPublic, status.Visibility)
suite.Equal(ap.ObjectNote, status.ActivityStreamsType) suite.Equal(ap.ObjectNote, status.ActivityStreamsType)
@ -95,16 +95,16 @@ func (suite *StatusTestSuite) TestDereferenceStatusWithMention() {
dbStatus, err := suite.db.GetStatusByURI(context.Background(), status.URI) dbStatus, err := suite.db.GetStatusByURI(context.Background(), status.URI)
suite.NoError(err) suite.NoError(err)
suite.Equal(status.ID, dbStatus.ID) suite.Equal(status.ID, dbStatus.ID)
suite.True(dbStatus.Federated) suite.True(*dbStatus.Federated)
suite.True(dbStatus.Boostable) suite.True(*dbStatus.Boostable)
suite.True(dbStatus.Replyable) suite.True(*dbStatus.Replyable)
suite.True(dbStatus.Likeable) suite.True(*dbStatus.Likeable)
// account should be in the database now too // account should be in the database now too
account, err := suite.db.GetAccountByURI(context.Background(), status.AccountURI) account, err := suite.db.GetAccountByURI(context.Background(), status.AccountURI)
suite.NoError(err) suite.NoError(err)
suite.NotNil(account) suite.NotNil(account)
suite.True(account.Discoverable) suite.True(*account.Discoverable)
suite.Equal("https://unknown-instance.com/users/brand_new_person", account.URI) suite.Equal("https://unknown-instance.com/users/brand_new_person", account.URI)
suite.Equal("hey I'm a new person, your instance hasn't seen me yet uwu", account.Note) suite.Equal("hey I'm a new person, your instance hasn't seen me yet uwu", account.Note)
suite.Equal("Geoff Brando New Personson", account.DisplayName) suite.Equal("Geoff Brando New Personson", account.DisplayName)
@ -121,7 +121,7 @@ func (suite *StatusTestSuite) TestDereferenceStatusWithMention() {
suite.Equal(account.ID, m.OriginAccountID) suite.Equal(account.ID, m.OriginAccountID)
suite.Equal(fetchingAccount.ID, m.TargetAccountID) suite.Equal(fetchingAccount.ID, m.TargetAccountID)
suite.Equal(account.URI, m.OriginAccountURI) suite.Equal(account.URI, m.OriginAccountURI)
suite.False(m.Silent) suite.False(*m.Silent)
} }
func (suite *StatusTestSuite) TestDereferenceStatusWithImageAndNoContent() { func (suite *StatusTestSuite) TestDereferenceStatusWithImageAndNoContent() {
@ -137,7 +137,7 @@ func (suite *StatusTestSuite) TestDereferenceStatusWithImageAndNoContent() {
suite.Equal("https://turnip.farm/@turniplover6969/70c53e54-3146-42d5-a630-83c8b6c7c042", status.URL) suite.Equal("https://turnip.farm/@turniplover6969/70c53e54-3146-42d5-a630-83c8b6c7c042", status.URL)
suite.Equal("", status.Content) suite.Equal("", status.Content)
suite.Equal("https://turnip.farm/users/turniplover6969", status.AccountURI) suite.Equal("https://turnip.farm/users/turniplover6969", status.AccountURI)
suite.False(status.Local) suite.False(*status.Local)
suite.Empty(status.ContentWarning) suite.Empty(status.ContentWarning)
suite.Equal(gtsmodel.VisibilityPublic, status.Visibility) suite.Equal(gtsmodel.VisibilityPublic, status.Visibility)
suite.Equal(ap.ObjectNote, status.ActivityStreamsType) suite.Equal(ap.ObjectNote, status.ActivityStreamsType)
@ -146,16 +146,16 @@ func (suite *StatusTestSuite) TestDereferenceStatusWithImageAndNoContent() {
dbStatus, err := suite.db.GetStatusByURI(context.Background(), status.URI) dbStatus, err := suite.db.GetStatusByURI(context.Background(), status.URI)
suite.NoError(err) suite.NoError(err)
suite.Equal(status.ID, dbStatus.ID) suite.Equal(status.ID, dbStatus.ID)
suite.True(dbStatus.Federated) suite.True(*dbStatus.Federated)
suite.True(dbStatus.Boostable) suite.True(*dbStatus.Boostable)
suite.True(dbStatus.Replyable) suite.True(*dbStatus.Replyable)
suite.True(dbStatus.Likeable) suite.True(*dbStatus.Likeable)
// account should be in the database now too // account should be in the database now too
account, err := suite.db.GetAccountByURI(context.Background(), status.AccountURI) account, err := suite.db.GetAccountByURI(context.Background(), status.AccountURI)
suite.NoError(err) suite.NoError(err)
suite.NotNil(account) suite.NotNil(account)
suite.True(account.Discoverable) suite.True(*account.Discoverable)
suite.Equal("https://turnip.farm/users/turniplover6969", account.URI) suite.Equal("https://turnip.farm/users/turniplover6969", account.URI)
suite.Equal("I just think they're neat", account.Note) suite.Equal("I just think they're neat", account.Note)
suite.Equal("Turnip Lover 6969", account.DisplayName) suite.Equal("Turnip Lover 6969", account.DisplayName)

View file

@ -82,9 +82,9 @@ func (suite *FederatingActorTestSuite) TestSendRemoteFollower() {
UpdatedAt: testrig.TimeMustParse("2022-06-02T12:22:21+02:00"), UpdatedAt: testrig.TimeMustParse("2022-06-02T12:22:21+02:00"),
AccountID: testRemoteAccount.ID, AccountID: testRemoteAccount.ID,
TargetAccountID: testAccount.ID, TargetAccountID: testAccount.ID,
ShowReblogs: true, ShowReblogs: testrig.TrueBool(),
URI: "http://fossbros-anonymous.io/users/foss_satan/follows/01G1TRWV4AYCDBX5HRWT2EVBCV", URI: "http://fossbros-anonymous.io/users/foss_satan/follows/01G1TRWV4AYCDBX5HRWT2EVBCV",
Notify: false, Notify: testrig.FalseBool(),
}) })
suite.NoError(err) suite.NoError(err)

View file

@ -62,7 +62,7 @@ func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
// an actual error happened // an actual error happened
return false, fmt.Errorf("database error fetching status with id %s: %s", uid, err) return false, fmt.Errorf("database error fetching status with id %s: %s", uid, err)
} }
return status.Local, nil return *status.Local, nil
} }
if uris.IsUserPath(id) { if uris.IsUserPath(id) {

View file

@ -44,15 +44,15 @@ type Account struct {
Fields []Field `validate:"-"` // a key/value map of fields that this account has added to their profile Fields []Field `validate:"-"` // a key/value map of fields that this account has added to their profile
Note string `validate:"-" bun:""` // A note that this account has on their profile (ie., the account's bio/description of themselves) Note string `validate:"-" bun:""` // A note that this account has on their profile (ie., the account's bio/description of themselves)
NoteRaw string `validate:"-" bun:""` // The raw contents of .Note without conversion to HTML, only available when requester = target NoteRaw string `validate:"-" bun:""` // The raw contents of .Note without conversion to HTML, only available when requester = target
Memorial bool `validate:"-" bun:",default:false"` // Is this a memorial account, ie., has the user passed away? Memorial *bool `validate:"-" bun:",default:false"` // Is this a memorial account, ie., has the user passed away?
AlsoKnownAs string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // This account is associated with x account id (TODO: migrate to be AlsoKnownAsID) AlsoKnownAs string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // This account is associated with x account id (TODO: migrate to be AlsoKnownAsID)
MovedToAccountID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // This account has moved this account id in the database MovedToAccountID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // This account has moved this account id in the database
Bot bool `validate:"-" bun:",default:false"` // Does this account identify itself as a bot? Bot *bool `validate:"-" bun:",default:false"` // Does this account identify itself as a bot?
Reason string `validate:"-" bun:""` // What reason was given for signing up when this account was created? Reason string `validate:"-" bun:""` // What reason was given for signing up when this account was created?
Locked bool `validate:"-" bun:",default:true"` // Does this account need an approval for new followers? Locked *bool `validate:"-" bun:",default:true"` // Does this account need an approval for new followers?
Discoverable bool `validate:"-" bun:",default:false"` // Should this account be shown in the instance's profile directory? Discoverable *bool `validate:"-" bun:",default:false"` // Should this account be shown in the instance's profile directory?
Privacy Visibility `validate:"required_without=Domain,omitempty,oneof=public unlocked followers_only mutuals_only direct" bun:",nullzero"` // Default post privacy for this account Privacy Visibility `validate:"required_without=Domain,omitempty,oneof=public unlocked followers_only mutuals_only direct" bun:",nullzero"` // Default post privacy for this account
Sensitive bool `validate:"-" bun:",default:false"` // Set posts from this account to sensitive by default? Sensitive *bool `validate:"-" bun:",default:false"` // Set posts from this account to sensitive by default?
Language string `validate:"omitempty,bcp47_language_tag" bun:",nullzero,notnull,default:'en'"` // What language does this account post in? Language string `validate:"omitempty,bcp47_language_tag" bun:",nullzero,notnull,default:'en'"` // What language does this account post in?
StatusFormat string `validate:"required_without=Domain,omitempty,oneof=plain markdown" bun:",nullzero"` // What is the default format for statuses posted by this account (only for local accounts). StatusFormat string `validate:"required_without=Domain,omitempty,oneof=plain markdown" bun:",nullzero"` // What is the default format for statuses posted by this account (only for local accounts).
URI string `validate:"required,url" bun:",nullzero,notnull,unique"` // ActivityPub URI for this account. URI string `validate:"required,url" bun:",nullzero,notnull,unique"` // ActivityPub URI for this account.
@ -70,7 +70,7 @@ type Account struct {
SensitizedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero"` // When was this account set to have all its media shown as sensitive? SensitizedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero"` // When was this account set to have all its media shown as sensitive?
SilencedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero"` // When was this account silenced (eg., statuses only visible to followers, not public)? SilencedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero"` // When was this account silenced (eg., statuses only visible to followers, not public)?
SuspendedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero"` // When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account) SuspendedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero"` // When was this account suspended (eg., don't allow it to log in/post, don't accept media/posts from this account)
HideCollections bool `validate:"-" bun:",default:false"` // Hide this account's collections HideCollections *bool `validate:"-" bun:",default:false"` // Hide this account's collections
SuspensionOrigin string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the database entry that caused this account to become suspended -- can be an account ID or a domain block ID SuspensionOrigin string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // id of the database entry that caused this account to become suspended -- can be an account ID or a domain block ID
} }

View file

@ -30,6 +30,6 @@ type DomainBlock struct {
CreatedByAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to createdByAccountID CreatedByAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to createdByAccountID
PrivateComment string `validate:"-" bun:""` // Private comment on this block, viewable to admins PrivateComment string `validate:"-" bun:""` // Private comment on this block, viewable to admins
PublicComment string `validate:"-" bun:""` // Public comment on this block, viewable (optionally) by everyone PublicComment string `validate:"-" bun:""` // Public comment on this block, viewable (optionally) by everyone
Obfuscate bool `validate:"-" bun:",default:false"` // whether the domain name should appear obfuscated when displaying it publicly Obfuscate *bool `validate:"-" bun:",nullzero,notnull,default:false"` // whether the domain name should appear obfuscated when displaying it publicly
SubscriptionID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // if this block was created through a subscription, what's the subscription ID? SubscriptionID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // if this block was created through a subscription, what's the subscription ID?
} }

View file

@ -38,8 +38,8 @@ type Emoji struct {
ImageFileSize int `validate:"required,min=1" bun:",nullzero,notnull"` // Size of the emoji image file in bytes, for serving purposes. ImageFileSize int `validate:"required,min=1" bun:",nullzero,notnull"` // Size of the emoji image file in bytes, for serving purposes.
ImageStaticFileSize int `validate:"required,min=1" bun:",nullzero,notnull"` // Size of the static version of the emoji image file in bytes, for serving purposes. ImageStaticFileSize int `validate:"required,min=1" bun:",nullzero,notnull"` // Size of the static version of the emoji image file in bytes, for serving purposes.
ImageUpdatedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // When was the emoji image last updated? ImageUpdatedAt time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // When was the emoji image last updated?
Disabled bool `validate:"-" bun:",notnull,default:false"` // Has a moderation action disabled this emoji from being shown? Disabled *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Has a moderation action disabled this emoji from being shown?
URI string `validate:"url" bun:",nullzero,notnull,unique"` // ActivityPub uri of this emoji. Something like 'https://example.org/emojis/1234' URI string `validate:"url" bun:",nullzero,notnull,unique"` // ActivityPub uri of this emoji. Something like 'https://example.org/emojis/1234'
VisibleInPicker bool `validate:"-" bun:",notnull,default:true"` // Is this emoji visible in the admin emoji picker? VisibleInPicker *bool `validate:"-" bun:",nullzero,notnull,default:true"` // Is this emoji visible in the admin emoji picker?
CategoryID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // In which emoji category is this emoji visible? CategoryID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // In which emoji category is this emoji visible?
} }

View file

@ -30,6 +30,6 @@ type Follow struct {
Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID
TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull,nullzero"` // Who is the target of this follow ? TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:srctarget,notnull,nullzero"` // Who is the target of this follow ?
TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID
ShowReblogs bool `validate:"-" bun:",default:true"` // Does this follow also want to see reblogs and not just posts? ShowReblogs *bool `validate:"-" bun:",nullzero,notnull,default:true"` // Does this follow also want to see reblogs and not just posts?
Notify bool `validate:"-" bun:",default:false"` // does the following account want to be notified when the followed account posts? Notify *bool `validate:"-" bun:",nullzero,notnull,default:false"` // does the following account want to be notified when the followed account posts?
} }

View file

@ -30,6 +30,6 @@ type FollowRequest struct {
Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID Account *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to accountID
TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull,nullzero"` // Who is the target of this follow request? TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),unique:frsrctarget,notnull,nullzero"` // Who is the target of this follow request?
TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to targetAccountID
ShowReblogs bool `validate:"-" bun:",default:true"` // Does this follow also want to see reblogs and not just posts? ShowReblogs *bool `validate:"-" bun:",nullzero,notnull,default:true"` // Does this follow also want to see reblogs and not just posts?
Notify bool `validate:"-" bun:",default:false"` // does the following account want to be notified when the followed account posts? Notify *bool `validate:"-" bun:",nullzero,notnull,default:false"` // does the following account want to be notified when the followed account posts?
} }

View file

@ -41,9 +41,9 @@ type MediaAttachment struct {
Processing ProcessingStatus `validate:"oneof=0 1 2 666" bun:",notnull,default:2"` // What is the processing status of this attachment Processing ProcessingStatus `validate:"oneof=0 1 2 666" bun:",notnull,default:2"` // What is the processing status of this attachment
File File `validate:"required" bun:",embed:file_,notnull,nullzero"` // metadata for the whole file File File `validate:"required" bun:",embed:file_,notnull,nullzero"` // metadata for the whole file
Thumbnail Thumbnail `validate:"required" bun:",embed:thumbnail_,notnull,nullzero"` // small image thumbnail derived from a larger image, video, or audio file. Thumbnail Thumbnail `validate:"required" bun:",embed:thumbnail_,notnull,nullzero"` // small image thumbnail derived from a larger image, video, or audio file.
Avatar bool `validate:"-" bun:",notnull,default:false"` // Is this attachment being used as an avatar? Avatar *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Is this attachment being used as an avatar?
Header bool `validate:"-" bun:",notnull,default:false"` // Is this attachment being used as a header? Header *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Is this attachment being used as a header?
Cached bool `validate:"-" bun:",notnull"` // Is this attachment currently cached by our instance? Cached *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Is this attachment currently cached by our instance?
} }
// File refers to the metadata for the whole file // File refers to the metadata for the whole file

View file

@ -35,7 +35,7 @@ type Mention struct {
OriginAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by originAccountID OriginAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by originAccountID
TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Mention target/receiver account ID TargetAccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // Mention target/receiver account ID
TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by targetAccountID TargetAccount *Account `validate:"-" bun:"rel:belongs-to"` // account referred to by targetAccountID
Silent bool `validate:"-" bun:",notnull,default:false"` // Prevent this mention from generating a notification? Silent *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Prevent this mention from generating a notification?
/* /*
NON-DATABASE CONVENIENCE FIELDS NON-DATABASE CONVENIENCE FIELDS

View file

@ -32,7 +32,7 @@ type Notification struct {
OriginAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to originAccountID OriginAccount *Account `validate:"-" bun:"rel:belongs-to"` // Account corresponding to originAccountID
StatusID string `validate:"required_if=NotificationType mention,required_if=NotificationType reblog,required_if=NotificationType favourite,required_if=NotificationType status,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // If the notification pertains to a status, what is the database ID of that status? StatusID string `validate:"required_if=NotificationType mention,required_if=NotificationType reblog,required_if=NotificationType favourite,required_if=NotificationType status,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // If the notification pertains to a status, what is the database ID of that status?
Status *Status `validate:"-" bun:"rel:belongs-to"` // Status corresponding to statusID Status *Status `validate:"-" bun:"rel:belongs-to"` // Status corresponding to statusID
Read bool `validate:"-" bun:",notnull,default:false"` // Notification has been seen/read Read *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Notification has been seen/read
} }
// NotificationType describes the reason/type of this notification. // NotificationType describes the reason/type of this notification.

View file

@ -38,7 +38,7 @@ type Status struct {
Mentions []*Mention `validate:"-" bun:"attached_mentions,rel:has-many"` // Mentions corresponding to mentionIDs Mentions []*Mention `validate:"-" bun:"attached_mentions,rel:has-many"` // Mentions corresponding to mentionIDs
EmojiIDs []string `validate:"dive,ulid" bun:"emojis,array"` // Database IDs of any emojis used in this status EmojiIDs []string `validate:"dive,ulid" bun:"emojis,array"` // Database IDs of any emojis used in this status
Emojis []*Emoji `validate:"-" bun:"attached_emojis,m2m:status_to_emojis"` // Emojis corresponding to emojiIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation Emojis []*Emoji `validate:"-" bun:"attached_emojis,m2m:status_to_emojis"` // Emojis corresponding to emojiIDs. https://bun.uptrace.dev/guide/relations.html#many-to-many-relation
Local bool `validate:"-" bun:",notnull,default:false"` // is this status from a local account? Local *bool `validate:"-" bun:",nullzero,notnull,default:false"` // is this status from a local account?
AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // which account posted this status? AccountID string `validate:"required,ulid" bun:"type:CHAR(26),nullzero,notnull"` // which account posted this status?
Account *Account `validate:"-" bun:"rel:belongs-to"` // account corresponding to accountID Account *Account `validate:"-" bun:"rel:belongs-to"` // account corresponding to accountID
AccountURI string `validate:"required,url" bun:",nullzero,notnull"` // activitypub uri of the owner of this status AccountURI string `validate:"required,url" bun:",nullzero,notnull"` // activitypub uri of the owner of this status
@ -53,17 +53,17 @@ type Status struct {
BoostOfAccount *Account `validate:"-" bun:"rel:belongs-to"` // account that corresponds to boostOfAccountID BoostOfAccount *Account `validate:"-" bun:"rel:belongs-to"` // account that corresponds to boostOfAccountID
ContentWarning string `validate:"-" bun:",nullzero"` // cw string for this status ContentWarning string `validate:"-" bun:",nullzero"` // cw string for this status
Visibility Visibility `validate:"oneof=public unlocked followers_only mutuals_only direct" bun:",nullzero,notnull"` // visibility entry for this status Visibility Visibility `validate:"oneof=public unlocked followers_only mutuals_only direct" bun:",nullzero,notnull"` // visibility entry for this status
Sensitive bool `validate:"-" bun:",notnull,default:false"` // mark the status as sensitive? Sensitive *bool `validate:"-" bun:",nullzero,notnull,default:false"` // mark the status as sensitive?
Language string `validate:"-" bun:",nullzero"` // what language is this status written in? Language string `validate:"-" bun:",nullzero"` // what language is this status written in?
CreatedWithApplicationID string `validate:"required_if=Local true,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which application was used to create this status? CreatedWithApplicationID string `validate:"required_if=Local true,omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which application was used to create this status?
CreatedWithApplication *Application `validate:"-" bun:"rel:belongs-to"` // application corresponding to createdWithApplicationID CreatedWithApplication *Application `validate:"-" bun:"rel:belongs-to"` // application corresponding to createdWithApplicationID
ActivityStreamsType string `validate:"required" bun:",nullzero,notnull"` // What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types. Will probably almost always be Note but who knows!. ActivityStreamsType string `validate:"required" bun:",nullzero,notnull"` // What is the activitystreams type of this status? See: https://www.w3.org/TR/activitystreams-vocabulary/#object-types. Will probably almost always be Note but who knows!.
Text string `validate:"-" bun:""` // Original text of the status without formatting Text string `validate:"-" bun:""` // Original text of the status without formatting
Pinned bool `validate:"-" bun:",notnull,default:false"` // Has this status been pinned by its owner? Pinned *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Has this status been pinned by its owner?
Federated bool `validate:"-" bun:",notnull"` // This status will be federated beyond the local timeline(s) Federated *bool `validate:"-" bun:",notnull"` // This status will be federated beyond the local timeline(s)
Boostable bool `validate:"-" bun:",notnull"` // This status can be boosted/reblogged Boostable *bool `validate:"-" bun:",notnull"` // This status can be boosted/reblogged
Replyable bool `validate:"-" bun:",notnull"` // This status can be replied to Replyable *bool `validate:"-" bun:",notnull"` // This status can be replied to
Likeable bool `validate:"-" bun:",notnull"` // This status can be liked/faved Likeable *bool `validate:"-" bun:",notnull"` // This status can be liked/faved
} }
/* /*

View file

@ -28,7 +28,7 @@ type Tag struct {
URL string `validate:"required,url" bun:",nullzero,notnull"` // Href/web address of this tag, eg https://example.org/tags/somehashtag URL string `validate:"required,url" bun:",nullzero,notnull"` // Href/web address of this tag, eg https://example.org/tags/somehashtag
Name string `validate:"required" bun:",unique,nullzero,notnull"` // name of this tag -- the tag without the hash part Name string `validate:"required" bun:",unique,nullzero,notnull"` // name of this tag -- the tag without the hash part
FirstSeenFromAccountID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which account ID is the first one we saw using this tag? FirstSeenFromAccountID string `validate:"omitempty,ulid" bun:"type:CHAR(26),nullzero"` // Which account ID is the first one we saw using this tag?
Useable bool `validate:"-" bun:",notnull,default:true"` // can our instance users use this tag? Useable *bool `validate:"-" bun:",nullzero,notnull,default:true"` // can our instance users use this tag?
Listable bool `validate:"-" bun:",notnull,default:true"` // can our instance users look up this tag? Listable *bool `validate:"-" bun:",nullzero,notnull,default:true"` // can our instance users look up this tag?
LastStatusAt time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was this tag last used? LastStatusAt time.Time `validate:"-" bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was this tag last used?
} }

View file

@ -50,10 +50,10 @@ type User struct {
ConfirmationSentAt time.Time `validate:"required_with=ConfirmationToken" bun:"type:timestamptz,nullzero"` // When did we send email confirmation to this user? ConfirmationSentAt time.Time `validate:"required_with=ConfirmationToken" bun:"type:timestamptz,nullzero"` // When did we send email confirmation to this user?
ConfirmedAt time.Time `validate:"required_with=Email" bun:"type:timestamptz,nullzero"` // When did the user confirm their email address ConfirmedAt time.Time `validate:"required_with=Email" bun:"type:timestamptz,nullzero"` // When did the user confirm their email address
UnconfirmedEmail string `validate:"required_without=Email" bun:",nullzero"` // Email address that hasn't yet been confirmed UnconfirmedEmail string `validate:"required_without=Email" bun:",nullzero"` // Email address that hasn't yet been confirmed
Moderator bool `validate:"-" bun:",notnull,default:false"` // Is this user a moderator? Moderator *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Is this user a moderator?
Admin bool `validate:"-" bun:",notnull,default:false"` // Is this user an admin? Admin *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Is this user an admin?
Disabled bool `validate:"-" bun:",notnull,default:false"` // Is this user disabled from posting? Disabled *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Is this user disabled from posting?
Approved bool `validate:"-" bun:",notnull,default:false"` // Has this user been approved by a moderator? Approved *bool `validate:"-" bun:",nullzero,notnull,default:false"` // Has this user been approved by a moderator?
ResetPasswordToken string `validate:"required_with=ResetPasswordSentAt" bun:",nullzero"` // The generated token that the user can use to reset their password ResetPasswordToken string `validate:"required_with=ResetPasswordSentAt" bun:",nullzero"` // The generated token that the user can use to reset their password
ResetPasswordSentAt time.Time `validate:"required_with=ResetPasswordToken" bun:"type:timestamptz,nullzero"` // When did we email the user their reset-password email? ResetPasswordSentAt time.Time `validate:"required_with=ResetPasswordToken" bun:"type:timestamptz,nullzero"` // When did we email the user their reset-password email?
} }

View file

@ -230,6 +230,9 @@ func (m *manager) preProcessEmoji(ctx context.Context, data DataFunc, postData P
return nil, fmt.Errorf("preProcessEmoji: error fetching this instance account from the db: %s", err) return nil, fmt.Errorf("preProcessEmoji: error fetching this instance account from the db: %s", err)
} }
disabled := false
visibleInPicker := true
// populate initial fields on the emoji -- some of these will be overwritten as we proceed // populate initial fields on the emoji -- some of these will be overwritten as we proceed
emoji := &gtsmodel.Emoji{ emoji := &gtsmodel.Emoji{
ID: id, ID: id,
@ -248,9 +251,9 @@ func (m *manager) preProcessEmoji(ctx context.Context, data DataFunc, postData P
ImageFileSize: 0, ImageFileSize: 0,
ImageStaticFileSize: 0, ImageStaticFileSize: 0,
ImageUpdatedAt: time.Now(), ImageUpdatedAt: time.Now(),
Disabled: false, Disabled: &disabled,
URI: uri, URI: uri,
VisibleInPicker: true, VisibleInPicker: &visibleInPicker,
CategoryID: "", CategoryID: "",
} }
@ -274,11 +277,11 @@ func (m *manager) preProcessEmoji(ctx context.Context, data DataFunc, postData P
} }
if ai.Disabled != nil { if ai.Disabled != nil {
emoji.Disabled = *ai.Disabled emoji.Disabled = ai.Disabled
} }
if ai.VisibleInPicker != nil { if ai.VisibleInPicker != nil {
emoji.VisibleInPicker = *ai.VisibleInPicker emoji.VisibleInPicker = ai.VisibleInPicker
} }
if ai.CategoryID != nil { if ai.CategoryID != nil {

View file

@ -346,7 +346,9 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
if err := p.storage.PutStream(ctx, p.attachment.File.Path, clean); err != nil { if err := p.storage.PutStream(ctx, p.attachment.File.Path, clean); err != nil {
return fmt.Errorf("store: error storing stream: %s", err) return fmt.Errorf("store: error storing stream: %s", err)
} }
p.attachment.Cached = true
cached := true
p.attachment.Cached = &cached
p.read = true p.read = true
if p.postData != nil { if p.postData != nil {
@ -376,6 +378,10 @@ func (m *manager) preProcessMedia(ctx context.Context, data DataFunc, postData P
UpdatedAt: time.Now(), UpdatedAt: time.Now(),
} }
avatar := false
header := false
cached := false
// populate initial fields on the media attachment -- some of these will be overwritten as we proceed // populate initial fields on the media attachment -- some of these will be overwritten as we proceed
attachment := &gtsmodel.MediaAttachment{ attachment := &gtsmodel.MediaAttachment{
ID: id, ID: id,
@ -393,9 +399,9 @@ func (m *manager) preProcessMedia(ctx context.Context, data DataFunc, postData P
Processing: gtsmodel.ProcessingStatusReceived, Processing: gtsmodel.ProcessingStatusReceived,
File: file, File: file,
Thumbnail: thumbnail, Thumbnail: thumbnail,
Avatar: false, Avatar: &avatar,
Header: false, Header: &header,
Cached: false, Cached: &cached,
} }
// check if we have additional info to add to the attachment, // check if we have additional info to add to the attachment,
@ -426,11 +432,11 @@ func (m *manager) preProcessMedia(ctx context.Context, data DataFunc, postData P
} }
if ai.Avatar != nil { if ai.Avatar != nil {
attachment.Avatar = *ai.Avatar attachment.Avatar = ai.Avatar
} }
if ai.Header != nil { if ai.Header != nil {
attachment.Header = *ai.Header attachment.Header = ai.Header
} }
if ai.FocusX != nil { if ai.FocusX != nil {

View file

@ -46,8 +46,8 @@ func (m *manager) PruneAllMeta(ctx context.Context) (int, error) {
// - is an avatar but isn't the owning account's current avatar // - is an avatar but isn't the owning account's current avatar
for _, attachment := range attachments { for _, attachment := range attachments {
if attachment.Account == nil || if attachment.Account == nil ||
(attachment.Header && attachment.ID != attachment.Account.HeaderMediaAttachmentID) || (*attachment.Header && attachment.ID != attachment.Account.HeaderMediaAttachmentID) ||
(attachment.Avatar && attachment.ID != attachment.Account.AvatarMediaAttachmentID) { (*attachment.Avatar && attachment.ID != attachment.Account.AvatarMediaAttachmentID) {
if err := m.pruneOneAvatarOrHeader(ctx, attachment); err != nil { if err := m.pruneOneAvatarOrHeader(ctx, attachment); err != nil {
return totalPruned, err return totalPruned, err
} }

View file

@ -40,7 +40,7 @@ func (suite *PruneMetaTestSuite) TestPruneMeta() {
zork := suite.testAccounts["local_account_1"] zork := suite.testAccounts["local_account_1"]
zork.AvatarMediaAttachmentID = "" zork.AvatarMediaAttachmentID = ""
zork.HeaderMediaAttachmentID = "" zork.HeaderMediaAttachmentID = ""
if err := suite.db.UpdateByPrimaryKey(ctx, zork); err != nil { if err := suite.db.UpdateByPrimaryKey(ctx, zork, "avatar_media_attachment_id", "header_media_attachment_id"); err != nil {
panic(err) panic(err)
} }
@ -72,7 +72,7 @@ func (suite *PruneMetaTestSuite) TestPruneMetaTwice() {
zork := suite.testAccounts["local_account_1"] zork := suite.testAccounts["local_account_1"]
zork.AvatarMediaAttachmentID = "" zork.AvatarMediaAttachmentID = ""
zork.HeaderMediaAttachmentID = "" zork.HeaderMediaAttachmentID = ""
if err := suite.db.UpdateByPrimaryKey(ctx, zork); err != nil { if err := suite.db.UpdateByPrimaryKey(ctx, zork, "avatar_media_attachment_id", "header_media_attachment_id"); err != nil {
panic(err) panic(err)
} }
@ -95,14 +95,14 @@ func (suite *PruneMetaTestSuite) TestPruneMetaMultipleAccounts() {
zork := suite.testAccounts["local_account_1"] zork := suite.testAccounts["local_account_1"]
zork.AvatarMediaAttachmentID = "" zork.AvatarMediaAttachmentID = ""
zork.HeaderMediaAttachmentID = "" zork.HeaderMediaAttachmentID = ""
if err := suite.db.UpdateByPrimaryKey(ctx, zork); err != nil { if err := suite.db.UpdateByPrimaryKey(ctx, zork, "avatar_media_attachment_id", "header_media_attachment_id"); err != nil {
panic(err) panic(err)
} }
// set zork's unused header as belonging to turtle // set zork's unused header as belonging to turtle
turtle := suite.testAccounts["local_account_1"] turtle := suite.testAccounts["local_account_1"]
zorkOldHeader.AccountID = turtle.ID zorkOldHeader.AccountID = turtle.ID
if err := suite.db.UpdateByPrimaryKey(ctx, zorkOldHeader); err != nil { if err := suite.db.UpdateByPrimaryKey(ctx, zorkOldHeader, "account_id"); err != nil {
panic(err) panic(err)
} }

View file

@ -64,13 +64,17 @@ func (m *manager) PruneAllRemote(ctx context.Context, olderThanDays int) (int, e
} }
func (m *manager) pruneOneRemote(ctx context.Context, attachment *gtsmodel.MediaAttachment) error { func (m *manager) pruneOneRemote(ctx context.Context, attachment *gtsmodel.MediaAttachment) error {
var changed bool
if attachment.File.Path != "" { if attachment.File.Path != "" {
// delete the full size attachment from storage // delete the full size attachment from storage
log.Tracef("pruneOneRemote: deleting %s", attachment.File.Path) log.Tracef("pruneOneRemote: deleting %s", attachment.File.Path)
if err := m.storage.Delete(ctx, attachment.File.Path); err != nil && err != storage.ErrNotFound { if err := m.storage.Delete(ctx, attachment.File.Path); err != nil && err != storage.ErrNotFound {
return err return err
} }
attachment.Cached = false cached := false
attachment.Cached = &cached
changed = true
} }
if attachment.Thumbnail.Path != "" { if attachment.Thumbnail.Path != "" {
@ -79,9 +83,15 @@ func (m *manager) pruneOneRemote(ctx context.Context, attachment *gtsmodel.Media
if err := m.storage.Delete(ctx, attachment.Thumbnail.Path); err != nil && err != storage.ErrNotFound { if err := m.storage.Delete(ctx, attachment.Thumbnail.Path); err != nil && err != storage.ErrNotFound {
return err return err
} }
attachment.Cached = false cached := false
attachment.Cached = &cached
changed = true
} }
// update the attachment to reflect that we no longer have it cached // update the attachment to reflect that we no longer have it cached
return m.db.UpdateByPrimaryKey(ctx, attachment) if changed {
return m.db.UpdateByPrimaryKey(ctx, attachment, "updated_at", "cached")
}
return nil
} }

View file

@ -35,7 +35,7 @@ type PruneRemoteTestSuite struct {
func (suite *PruneRemoteTestSuite) TestPruneRemote() { func (suite *PruneRemoteTestSuite) TestPruneRemote() {
testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"] testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"]
suite.True(testAttachment.Cached) suite.True(*testAttachment.Cached)
totalPruned, err := suite.manager.PruneAllRemote(context.Background(), 1) totalPruned, err := suite.manager.PruneAllRemote(context.Background(), 1)
suite.NoError(err) suite.NoError(err)
@ -45,7 +45,7 @@ func (suite *PruneRemoteTestSuite) TestPruneRemote() {
suite.NoError(err) suite.NoError(err)
// the media should no longer be cached // the media should no longer be cached
suite.False(prunedAttachment.Cached) suite.False(*prunedAttachment.Cached)
} }
func (suite *PruneRemoteTestSuite) TestPruneRemoteTwice() { func (suite *PruneRemoteTestSuite) TestPruneRemoteTwice() {
@ -91,7 +91,7 @@ func (suite *PruneRemoteTestSuite) TestPruneAndRecache() {
suite.NotNil(recachedAttachment) suite.NotNil(recachedAttachment)
// recachedAttachment should be basically the same as the old attachment // recachedAttachment should be basically the same as the old attachment
suite.True(recachedAttachment.Cached) suite.True(*recachedAttachment.Cached)
suite.Equal(testAttachment.ID, recachedAttachment.ID) suite.Equal(testAttachment.ID, recachedAttachment.ID)
suite.Equal(testAttachment.File.Path, recachedAttachment.File.Path) // file should be stored in the same place suite.Equal(testAttachment.File.Path, recachedAttachment.File.Path) // file should be stored in the same place
suite.Equal(testAttachment.Thumbnail.Path, recachedAttachment.Thumbnail.Path) // as should the thumbnail suite.Equal(testAttachment.Thumbnail.Path, recachedAttachment.Thumbnail.Path) // as should the thumbnail
@ -111,7 +111,7 @@ func (suite *PruneRemoteTestSuite) TestPruneOneNonExistent() {
// Delete this attachment cached on disk // Delete this attachment cached on disk
media, err := suite.db.GetAttachmentByID(ctx, testAttachment.ID) media, err := suite.db.GetAttachmentByID(ctx, testAttachment.ID)
suite.NoError(err) suite.NoError(err)
suite.True(media.Cached) suite.True(*media.Cached)
err = suite.storage.Delete(ctx, media.File.Path) err = suite.storage.Delete(ctx, media.File.Path)
suite.NoError(err) suite.NoError(err)

View file

@ -32,7 +32,7 @@ type PruneUnusedLocalTestSuite struct {
func (suite *PruneUnusedLocalTestSuite) TestPruneUnusedLocal() { func (suite *PruneUnusedLocalTestSuite) TestPruneUnusedLocal() {
testAttachment := suite.testAttachments["local_account_1_unattached_1"] testAttachment := suite.testAttachments["local_account_1_unattached_1"]
suite.True(testAttachment.Cached) suite.True(*testAttachment.Cached)
totalPruned, err := suite.manager.PruneUnusedLocalAttachments(context.Background()) totalPruned, err := suite.manager.PruneUnusedLocalAttachments(context.Background())
suite.NoError(err) suite.NoError(err)
@ -60,7 +60,7 @@ func (suite *PruneUnusedLocalTestSuite) TestPruneOneNonExistent() {
// Delete this attachment cached on disk // Delete this attachment cached on disk
media, err := suite.db.GetAttachmentByID(ctx, testAttachment.ID) media, err := suite.db.GetAttachmentByID(ctx, testAttachment.ID)
suite.NoError(err) suite.NoError(err)
suite.True(media.Cached) suite.True(*media.Cached)
err = suite.storage.Delete(ctx, media.File.Path) err = suite.storage.Delete(ctx, media.File.Path)
suite.NoError(err) suite.NoError(err)

View file

@ -76,19 +76,21 @@ func (p *processor) FollowCreate(ctx context.Context, requestingAccount *gtsmode
return nil, gtserror.NewErrorInternalError(err) return nil, gtserror.NewErrorInternalError(err)
} }
showReblogs := true
notify := false
fr := &gtsmodel.FollowRequest{ fr := &gtsmodel.FollowRequest{
ID: newFollowID, ID: newFollowID,
AccountID: requestingAccount.ID, AccountID: requestingAccount.ID,
TargetAccountID: form.ID, TargetAccountID: form.ID,
ShowReblogs: true, ShowReblogs: &showReblogs,
URI: uris.GenerateURIForFollow(requestingAccount.Username, newFollowID), URI: uris.GenerateURIForFollow(requestingAccount.Username, newFollowID),
Notify: false, Notify: &notify,
} }
if form.Reblogs != nil { if form.Reblogs != nil {
fr.ShowReblogs = *form.Reblogs fr.ShowReblogs = form.Reblogs
} }
if form.Notify != nil { if form.Notify != nil {
fr.Notify = *form.Notify fr.Notify = form.Notify
} }
// whack it in the database // whack it in the database
@ -97,7 +99,7 @@ func (p *processor) FollowCreate(ctx context.Context, requestingAccount *gtsmode
} }
// if it's a local account that's not locked we can just straight up accept the follow request // if it's a local account that's not locked we can just straight up accept the follow request
if !targetAcct.Locked && targetAcct.Domain == "" { if !*targetAcct.Locked && targetAcct.Domain == "" {
if _, err := p.db.AcceptFollowRequest(ctx, requestingAccount.ID, form.ID); err != nil { if _, err := p.db.AcceptFollowRequest(ctx, requestingAccount.ID, form.ID); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error accepting folow request for local unlocked account: %s", err)) return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error accepting folow request for local unlocked account: %s", err))
} }

View file

@ -285,8 +285,10 @@ selectStatusesLoop:
account.HeaderRemoteURL = "" account.HeaderRemoteURL = ""
account.Reason = "" account.Reason = ""
account.Fields = []gtsmodel.Field{} account.Fields = []gtsmodel.Field{}
account.HideCollections = true hideCollections := true
account.Discoverable = false account.HideCollections = &hideCollections
discoverable := false
account.Discoverable = &discoverable
account.SuspendedAt = time.Now() account.SuspendedAt = time.Now()
account.SuspensionOrigin = origin account.SuspensionOrigin = origin

View file

@ -39,11 +39,11 @@ import (
func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, gtserror.WithCode) { func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form *apimodel.UpdateCredentialsRequest) (*apimodel.Account, gtserror.WithCode) {
if form.Discoverable != nil { if form.Discoverable != nil {
account.Discoverable = *form.Discoverable account.Discoverable = form.Discoverable
} }
if form.Bot != nil { if form.Bot != nil {
account.Bot = *form.Bot account.Bot = form.Bot
} }
if form.DisplayName != nil { if form.DisplayName != nil {
@ -92,7 +92,7 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
} }
if form.Locked != nil { if form.Locked != nil {
account.Locked = *form.Locked account.Locked = form.Locked
} }
if form.Source != nil { if form.Source != nil {
@ -104,7 +104,7 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
} }
if form.Source.Sensitive != nil { if form.Source.Sensitive != nil {
account.Sensitive = *form.Source.Sensitive account.Sensitive = form.Source.Sensitive
} }
if form.Source.Privacy != nil { if form.Source.Privacy != nil {

View file

@ -65,7 +65,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateSimple() {
// fields should be updated in the database as well // fields should be updated in the database as well
dbAccount, err := suite.db.GetAccountByID(context.Background(), testAccount.ID) dbAccount, err := suite.db.GetAccountByID(context.Background(), testAccount.ID)
suite.NoError(err) suite.NoError(err)
suite.True(dbAccount.Locked) suite.True(*dbAccount.Locked)
suite.Equal(displayName, dbAccount.DisplayName) suite.Equal(displayName, dbAccount.DisplayName)
suite.Equal(`<p><a href="http://localhost:8080/tags/hello" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>hello</span></a> here i am!</p>`, dbAccount.Note) suite.Equal(`<p><a href="http://localhost:8080/tags/hello" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>hello</span></a> here i am!</p>`, dbAccount.Note)
} }
@ -107,7 +107,7 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateWithMention() {
// fields should be updated in the database as well // fields should be updated in the database as well
dbAccount, err := suite.db.GetAccountByID(context.Background(), testAccount.ID) dbAccount, err := suite.db.GetAccountByID(context.Background(), testAccount.ID)
suite.NoError(err) suite.NoError(err)
suite.True(dbAccount.Locked) suite.True(*dbAccount.Locked)
suite.Equal(displayName, dbAccount.DisplayName) suite.Equal(displayName, dbAccount.DisplayName)
suite.Equal(noteExpected, dbAccount.Note) suite.Equal(noteExpected, dbAccount.Note)
} }

View file

@ -62,7 +62,7 @@ func (p *processor) DomainBlockCreate(ctx context.Context, account *gtsmodel.Acc
CreatedByAccountID: account.ID, CreatedByAccountID: account.ID,
PrivateComment: text.SanitizePlaintext(privateComment), PrivateComment: text.SanitizePlaintext(privateComment),
PublicComment: text.SanitizePlaintext(publicComment), PublicComment: text.SanitizePlaintext(publicComment),
Obfuscate: obfuscate, Obfuscate: &obfuscate,
SubscriptionID: subscriptionID, SubscriptionID: subscriptionID,
} }
@ -101,6 +101,19 @@ func (p *processor) initiateDomainBlockSideEffects(ctx context.Context, account
// if we have an instance entry for this domain, update it with the new block ID and clear all fields // if we have an instance entry for this domain, update it with the new block ID and clear all fields
instance := &gtsmodel.Instance{} instance := &gtsmodel.Instance{}
if err := p.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: block.Domain}}, instance); err == nil { if err := p.db.GetWhere(ctx, []db.Where{{Key: "domain", Value: block.Domain}}, instance); err == nil {
updatingColumns := []string{
"title",
"updated_at",
"suspended_at",
"domain_block_id",
"short_description",
"description",
"terms",
"contact_email",
"contact_account_username",
"contact_account_id",
"version",
}
instance.Title = "" instance.Title = ""
instance.UpdatedAt = time.Now() instance.UpdatedAt = time.Now()
instance.SuspendedAt = time.Now() instance.SuspendedAt = time.Now()
@ -112,7 +125,7 @@ func (p *processor) initiateDomainBlockSideEffects(ctx context.Context, account
instance.ContactAccountUsername = "" instance.ContactAccountUsername = ""
instance.ContactAccountID = "" instance.ContactAccountID = ""
instance.Version = "" instance.Version = ""
if err := p.db.UpdateByPrimaryKey(ctx, instance); err != nil { if err := p.db.UpdateByPrimaryKey(ctx, instance, updatingColumns...); err != nil {
l.Errorf("domainBlockProcessSideEffects: db error updating instance: %s", err) l.Errorf("domainBlockProcessSideEffects: db error updating instance: %s", err)
} }
l.Debug("domainBlockProcessSideEffects: instance entry updated") l.Debug("domainBlockProcessSideEffects: instance entry updated")

View file

@ -58,9 +58,11 @@ func (p *processor) DomainBlockDelete(ctx context.Context, account *gtsmodel.Acc
{Key: "domain", Value: domainBlock.Domain, CaseInsensitive: true}, {Key: "domain", Value: domainBlock.Domain, CaseInsensitive: true},
{Key: "domain_block_id", Value: id}, {Key: "domain_block_id", Value: id},
}, i); err == nil { }, i); err == nil {
updatingColumns := []string{"suspended_at", "domain_block_id", "updated_at"}
i.SuspendedAt = time.Time{} i.SuspendedAt = time.Time{}
i.DomainBlockID = "" i.DomainBlockID = ""
if err := p.db.UpdateByPrimaryKey(ctx, i); err != nil { i.UpdatedAt = time.Now()
if err := p.db.UpdateByPrimaryKey(ctx, i, updatingColumns...); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("couldn't update database entry for instance %s: %s", domainBlock.Domain, err)) return nil, gtserror.NewErrorInternalError(fmt.Errorf("couldn't update database entry for instance %s: %s", domainBlock.Domain, err))
} }
} }

View file

@ -33,7 +33,7 @@ import (
) )
func (p *processor) EmojiCreate(ctx context.Context, account *gtsmodel.Account, user *gtsmodel.User, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, gtserror.WithCode) { func (p *processor) EmojiCreate(ctx context.Context, account *gtsmodel.Account, user *gtsmodel.User, form *apimodel.EmojiCreateRequest) (*apimodel.Emoji, gtserror.WithCode) {
if !user.Admin { if !*user.Admin {
return nil, gtserror.NewErrorUnauthorized(fmt.Errorf("user %s not an admin", user.ID), "user is not an admin") return nil, gtserror.NewErrorUnauthorized(fmt.Errorf("user %s not an admin", user.ID), "user is not an admin")
} }

View file

@ -392,7 +392,7 @@ func (p *processor) federateAccountDelete(ctx context.Context, account *gtsmodel
func (p *processor) federateStatus(ctx context.Context, status *gtsmodel.Status) error { func (p *processor) federateStatus(ctx context.Context, status *gtsmodel.Status) error {
// do nothing if the status shouldn't be federated // do nothing if the status shouldn't be federated
if !status.Federated { if !*status.Federated {
return nil return nil
} }

View file

@ -66,20 +66,21 @@ func (suite *FromClientAPITestSuite) TestProcessStreamNewStatus() {
EmojiIDs: []string{}, EmojiIDs: []string{},
CreatedAt: testrig.TimeMustParse("2021-10-20T11:36:45Z"), CreatedAt: testrig.TimeMustParse("2021-10-20T11:36:45Z"),
UpdatedAt: testrig.TimeMustParse("2021-10-20T11:36:45Z"), UpdatedAt: testrig.TimeMustParse("2021-10-20T11:36:45Z"),
Local: true, Local: testrig.TrueBool(),
AccountURI: "http://localhost:8080/users/admin", AccountURI: "http://localhost:8080/users/admin",
AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", AccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityFollowersOnly, Visibility: gtsmodel.VisibilityFollowersOnly,
Sensitive: false, Sensitive: testrig.FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F",
Federated: false, // set federated as false for this one, since we're not testing federation stuff now Pinned: testrig.FalseBool(),
Boostable: true, Federated: testrig.FalseBool(),
Replyable: true, Boostable: testrig.TrueBool(),
Likeable: true, Replyable: testrig.TrueBool(),
Likeable: testrig.TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
} }

View file

@ -259,7 +259,7 @@ func (p *processor) processCreateFollowRequestFromFederator(ctx context.Context,
followRequest.TargetAccount = a followRequest.TargetAccount = a
} }
if followRequest.TargetAccount.Locked { if *followRequest.TargetAccount.Locked {
// if the account is locked just notify the follow request and nothing else // if the account is locked just notify the follow request and nothing else
return p.notifyFollowRequest(ctx, followRequest) return p.notifyFollowRequest(ctx, followRequest)
} }

View file

@ -84,13 +84,14 @@ func (suite *FromFederatorTestSuite) TestProcessFederationAnnounce() {
suite.Equal(boostedStatus.AccountID, notif.TargetAccountID) suite.Equal(boostedStatus.AccountID, notif.TargetAccountID)
suite.Equal(announceStatus.AccountID, notif.OriginAccountID) suite.Equal(announceStatus.AccountID, notif.OriginAccountID)
suite.Equal(announceStatus.ID, notif.StatusID) suite.Equal(announceStatus.ID, notif.StatusID)
suite.False(notif.Read) suite.False(*notif.Read)
} }
func (suite *FromFederatorTestSuite) TestProcessReplyMention() { func (suite *FromFederatorTestSuite) TestProcessReplyMention() {
repliedAccount := suite.testAccounts["local_account_1"] repliedAccount := suite.testAccounts["local_account_1"]
repliedStatus := suite.testStatuses["local_account_1_status_1"] repliedStatus := suite.testStatuses["local_account_1_status_1"]
replyingAccount := suite.testAccounts["remote_account_1"] replyingAccount := suite.testAccounts["remote_account_1"]
replyingStatus := &gtsmodel.Status{ replyingStatus := &gtsmodel.Status{
CreatedAt: time.Now(), CreatedAt: time.Now(),
UpdatedAt: time.Now(), UpdatedAt: time.Now(),
@ -110,10 +111,10 @@ func (suite *FromFederatorTestSuite) TestProcessReplyMention() {
InReplyToAccountID: repliedAccount.ID, InReplyToAccountID: repliedAccount.ID,
Visibility: gtsmodel.VisibilityUnlocked, Visibility: gtsmodel.VisibilityUnlocked,
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
Federated: true, Federated: testrig.TrueBool(),
Boostable: true, Boostable: testrig.TrueBool(),
Replyable: true, Replyable: testrig.TrueBool(),
Likeable: true, Likeable: testrig.FalseBool(),
} }
wssStream, errWithCode := suite.processor.OpenStreamForAccount(context.Background(), repliedAccount, stream.TimelineHome) wssStream, errWithCode := suite.processor.OpenStreamForAccount(context.Background(), repliedAccount, stream.TimelineHome)
@ -156,10 +157,17 @@ func (suite *FromFederatorTestSuite) TestProcessReplyMention() {
suite.Equal(replyingStatus.InReplyToAccountID, notif.TargetAccountID) suite.Equal(replyingStatus.InReplyToAccountID, notif.TargetAccountID)
suite.Equal(replyingStatus.AccountID, notif.OriginAccountID) suite.Equal(replyingStatus.AccountID, notif.OriginAccountID)
suite.Equal(replyingStatus.ID, notif.StatusID) suite.Equal(replyingStatus.ID, notif.StatusID)
suite.False(notif.Read) suite.False(*notif.Read)
// the notification should be streamed
var msg *stream.Message
select {
case msg = <-wssStream.Messages:
// fine
case <-time.After(5 * time.Second):
suite.FailNow("no message from wssStream")
}
// the notification should also be streamed
msg := <-wssStream.Messages
suite.Equal(stream.EventTypeNotification, msg.Event) suite.Equal(stream.EventTypeNotification, msg.Event)
suite.NotEmpty(msg.Payload) suite.NotEmpty(msg.Payload)
suite.EqualValues([]string{stream.TimelineHome}, msg.Stream) suite.EqualValues([]string{stream.TimelineHome}, msg.Stream)
@ -222,10 +230,16 @@ func (suite *FromFederatorTestSuite) TestProcessFave() {
suite.Equal(fave.TargetAccountID, notif.TargetAccountID) suite.Equal(fave.TargetAccountID, notif.TargetAccountID)
suite.Equal(fave.AccountID, notif.OriginAccountID) suite.Equal(fave.AccountID, notif.OriginAccountID)
suite.Equal(fave.StatusID, notif.StatusID) suite.Equal(fave.StatusID, notif.StatusID)
suite.False(notif.Read) suite.False(*notif.Read)
// 2. a notification should be streamed // 2. a notification should be streamed
msg := <-wssStream.Messages var msg *stream.Message
select {
case msg = <-wssStream.Messages:
// fine
case <-time.After(5 * time.Second):
suite.FailNow("no message from wssStream")
}
suite.Equal(stream.EventTypeNotification, msg.Event) suite.Equal(stream.EventTypeNotification, msg.Event)
suite.NotEmpty(msg.Payload) suite.NotEmpty(msg.Payload)
suite.EqualValues([]string{stream.TimelineNotifications}, msg.Stream) suite.EqualValues([]string{stream.TimelineNotifications}, msg.Stream)
@ -289,7 +303,7 @@ func (suite *FromFederatorTestSuite) TestProcessFaveWithDifferentReceivingAccoun
suite.Equal(fave.TargetAccountID, notif.TargetAccountID) suite.Equal(fave.TargetAccountID, notif.TargetAccountID)
suite.Equal(fave.AccountID, notif.OriginAccountID) suite.Equal(fave.AccountID, notif.OriginAccountID)
suite.Equal(fave.StatusID, notif.StatusID) suite.Equal(fave.StatusID, notif.StatusID)
suite.False(notif.Read) suite.False(*notif.Read)
// 2. no notification should be streamed to the account that received the fave message, because they weren't the target // 2. no notification should be streamed to the account that received the fave message, because they weren't the target
suite.Empty(wssStream.Messages) suite.Empty(wssStream.Messages)
@ -309,9 +323,9 @@ func (suite *FromFederatorTestSuite) TestProcessAccountDelete() {
UpdatedAt: time.Now().Add(-1 * time.Hour), UpdatedAt: time.Now().Add(-1 * time.Hour),
AccountID: deletedAccount.ID, AccountID: deletedAccount.ID,
TargetAccountID: receivingAccount.ID, TargetAccountID: receivingAccount.ID,
ShowReblogs: true, ShowReblogs: testrig.TrueBool(),
URI: fmt.Sprintf("%s/follows/01FGRY72ASHBSET64353DPHK9T", deletedAccount.URI), URI: fmt.Sprintf("%s/follows/01FGRY72ASHBSET64353DPHK9T", deletedAccount.URI),
Notify: false, Notify: testrig.FalseBool(),
} }
err := suite.db.Put(ctx, zorkFollowSatan) err := suite.db.Put(ctx, zorkFollowSatan)
suite.NoError(err) suite.NoError(err)
@ -322,9 +336,9 @@ func (suite *FromFederatorTestSuite) TestProcessAccountDelete() {
UpdatedAt: time.Now().Add(-1 * time.Hour), UpdatedAt: time.Now().Add(-1 * time.Hour),
AccountID: receivingAccount.ID, AccountID: receivingAccount.ID,
TargetAccountID: deletedAccount.ID, TargetAccountID: deletedAccount.ID,
ShowReblogs: true, ShowReblogs: testrig.TrueBool(),
URI: fmt.Sprintf("%s/follows/01FGRYAVAWWPP926J175QGM0WV", receivingAccount.URI), URI: fmt.Sprintf("%s/follows/01FGRYAVAWWPP926J175QGM0WV", receivingAccount.URI),
Notify: false, Notify: testrig.FalseBool(),
} }
err = suite.db.Put(ctx, satanFollowZork) err = suite.db.Put(ctx, satanFollowZork)
suite.NoError(err) suite.NoError(err)
@ -369,8 +383,8 @@ func (suite *FromFederatorTestSuite) TestProcessAccountDelete() {
suite.Empty(dbAccount.HeaderRemoteURL) suite.Empty(dbAccount.HeaderRemoteURL)
suite.Empty(dbAccount.Reason) suite.Empty(dbAccount.Reason)
suite.Empty(dbAccount.Fields) suite.Empty(dbAccount.Fields)
suite.True(dbAccount.HideCollections) suite.True(*dbAccount.HideCollections)
suite.False(dbAccount.Discoverable) suite.False(*dbAccount.Discoverable)
suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second) suite.WithinDuration(time.Now(), dbAccount.SuspendedAt, 30*time.Second)
suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin) suite.Equal(dbAccount.ID, dbAccount.SuspensionOrigin)
} }
@ -395,9 +409,9 @@ func (suite *FromFederatorTestSuite) TestProcessFollowRequestLocked() {
Account: originAccount, Account: originAccount,
TargetAccountID: targetAccount.ID, TargetAccountID: targetAccount.ID,
TargetAccount: targetAccount, TargetAccount: targetAccount,
ShowReblogs: true, ShowReblogs: testrig.TrueBool(),
URI: fmt.Sprintf("%s/follows/01FGRYAVAWWPP926J175QGM0WV", originAccount.URI), URI: fmt.Sprintf("%s/follows/01FGRYAVAWWPP926J175QGM0WV", originAccount.URI),
Notify: false, Notify: testrig.FalseBool(),
} }
err := suite.db.Put(ctx, satanFollowRequestTurtle) err := suite.db.Put(ctx, satanFollowRequestTurtle)
@ -412,7 +426,13 @@ func (suite *FromFederatorTestSuite) TestProcessFollowRequestLocked() {
suite.NoError(err) suite.NoError(err)
// a notification should be streamed // a notification should be streamed
msg := <-wssStream.Messages var msg *stream.Message
select {
case msg = <-wssStream.Messages:
// fine
case <-time.After(5 * time.Second):
suite.FailNow("no message from wssStream")
}
suite.Equal(stream.EventTypeNotification, msg.Event) suite.Equal(stream.EventTypeNotification, msg.Event)
suite.NotEmpty(msg.Payload) suite.NotEmpty(msg.Payload)
suite.EqualValues([]string{stream.TimelineHome}, msg.Stream) suite.EqualValues([]string{stream.TimelineHome}, msg.Stream)
@ -446,9 +466,9 @@ func (suite *FromFederatorTestSuite) TestProcessFollowRequestUnlocked() {
Account: originAccount, Account: originAccount,
TargetAccountID: targetAccount.ID, TargetAccountID: targetAccount.ID,
TargetAccount: targetAccount, TargetAccount: targetAccount,
ShowReblogs: true, ShowReblogs: testrig.TrueBool(),
URI: fmt.Sprintf("%s/follows/01FGRYAVAWWPP926J175QGM0WV", originAccount.URI), URI: fmt.Sprintf("%s/follows/01FGRYAVAWWPP926J175QGM0WV", originAccount.URI),
Notify: false, Notify: testrig.FalseBool(),
} }
err := suite.db.Put(ctx, satanFollowRequestTurtle) err := suite.db.Put(ctx, satanFollowRequestTurtle)
@ -463,7 +483,13 @@ func (suite *FromFederatorTestSuite) TestProcessFollowRequestUnlocked() {
suite.NoError(err) suite.NoError(err)
// a notification should be streamed // a notification should be streamed
msg := <-wssStream.Messages var msg *stream.Message
select {
case msg = <-wssStream.Messages:
// fine
case <-time.After(5 * time.Second):
suite.FailNow("no message from wssStream")
}
suite.Equal(stream.EventTypeNotification, msg.Event) suite.Equal(stream.EventTypeNotification, msg.Event)
suite.NotEmpty(msg.Payload) suite.NotEmpty(msg.Payload)
suite.EqualValues([]string{stream.TimelineHome}, msg.Stream) suite.EqualValues([]string{stream.TimelineHome}, msg.Stream)

View file

@ -81,7 +81,7 @@ func (p *processor) InstancePeersGet(ctx context.Context, authed *oauth.Auth, in
} }
for _, d := range domainBlocks { for _, d := range domainBlocks {
if d.Obfuscate { if *d.Obfuscate {
d.Domain = obfuscate(d.Domain) d.Domain = obfuscate(d.Domain)
} }
@ -123,11 +123,14 @@ func (p *processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSe
return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error fetching instance account %s: %s", host, err)) return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error fetching instance account %s: %s", host, err))
} }
updatingColumns := []string{}
// validate & update site title if it's set on the form // validate & update site title if it's set on the form
if form.Title != nil { if form.Title != nil {
if err := validate.SiteTitle(*form.Title); err != nil { if err := validate.SiteTitle(*form.Title); err != nil {
return nil, gtserror.NewErrorBadRequest(err, fmt.Sprintf("site title invalid: %s", err)) return nil, gtserror.NewErrorBadRequest(err, fmt.Sprintf("site title invalid: %s", err))
} }
updatingColumns = append(updatingColumns, "title")
i.Title = text.SanitizePlaintext(*form.Title) // don't allow html in site title i.Title = text.SanitizePlaintext(*form.Title) // don't allow html in site title
} }
@ -153,15 +156,16 @@ func (p *processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSe
err := fmt.Errorf("user of selected contact account %s is not confirmed", contactAccount.Username) err := fmt.Errorf("user of selected contact account %s is not confirmed", contactAccount.Username)
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
if !contactUser.Approved { if !*contactUser.Approved {
err := fmt.Errorf("user of selected contact account %s is not approved", contactAccount.Username) err := fmt.Errorf("user of selected contact account %s is not approved", contactAccount.Username)
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
// contact account user must be admin or moderator otherwise what's the point of contacting them // contact account user must be admin or moderator otherwise what's the point of contacting them
if !contactUser.Admin && !contactUser.Moderator { if !*contactUser.Admin && !*contactUser.Moderator {
err := fmt.Errorf("user of selected contact account %s is neither admin nor moderator", contactAccount.Username) err := fmt.Errorf("user of selected contact account %s is neither admin nor moderator", contactAccount.Username)
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
updatingColumns = append(updatingColumns, "contact_account_id")
i.ContactAccountID = contactAccount.ID i.ContactAccountID = contactAccount.ID
} }
@ -173,6 +177,7 @@ func (p *processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSe
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
} }
updatingColumns = append(updatingColumns, "contact_email")
i.ContactEmail = contactEmail i.ContactEmail = contactEmail
} }
@ -181,6 +186,7 @@ func (p *processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSe
if err := validate.SiteShortDescription(*form.ShortDescription); err != nil { if err := validate.SiteShortDescription(*form.ShortDescription); err != nil {
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
updatingColumns = append(updatingColumns, "short_description")
i.ShortDescription = text.SanitizeHTML(*form.ShortDescription) // html is OK in site description, but we should sanitize it i.ShortDescription = text.SanitizeHTML(*form.ShortDescription) // html is OK in site description, but we should sanitize it
} }
@ -189,6 +195,7 @@ func (p *processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSe
if err := validate.SiteDescription(*form.Description); err != nil { if err := validate.SiteDescription(*form.Description); err != nil {
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
updatingColumns = append(updatingColumns, "description")
i.Description = text.SanitizeHTML(*form.Description) // html is OK in site description, but we should sanitize it i.Description = text.SanitizeHTML(*form.Description) // html is OK in site description, but we should sanitize it
} }
@ -197,6 +204,7 @@ func (p *processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSe
if err := validate.SiteTerms(*form.Terms); err != nil { if err := validate.SiteTerms(*form.Terms); err != nil {
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
updatingColumns = append(updatingColumns, "terms")
i.Terms = text.SanitizeHTML(*form.Terms) // html is OK in site terms, but we should sanitize it i.Terms = text.SanitizeHTML(*form.Terms) // html is OK in site terms, but we should sanitize it
} }
@ -216,7 +224,7 @@ func (p *processor) InstancePatch(ctx context.Context, form *apimodel.InstanceSe
} }
} }
if err := p.db.UpdateByPrimaryKey(ctx, i); err != nil { if err := p.db.UpdateByPrimaryKey(ctx, i, updatingColumns...); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error updating instance %s: %s", host, err)) return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error updating instance %s: %s", host, err))
} }

View file

@ -112,7 +112,7 @@ func (p *processor) getAttachmentContent(ctx context.Context, requestingAccount
} }
// if we have the media cached on our server already, we can now simply return it from storage // if we have the media cached on our server already, we can now simply return it from storage
if a.Cached { if *a.Cached {
return p.retrieveFromStorage(ctx, storagePath, attachmentContent) return p.retrieveFromStorage(ctx, storagePath, attachmentContent)
} }
@ -236,7 +236,7 @@ func (p *processor) getEmojiContent(ctx context.Context, wantedEmojiID string, e
return nil, gtserror.NewErrorNotFound(fmt.Errorf("emoji %s could not be taken from the db: %s", wantedEmojiID, err)) return nil, gtserror.NewErrorNotFound(fmt.Errorf("emoji %s could not be taken from the db: %s", wantedEmojiID, err))
} }
if e.Disabled { if *e.Disabled {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("emoji %s has been disabled", wantedEmojiID)) return nil, gtserror.NewErrorNotFound(fmt.Errorf("emoji %s has been disabled", wantedEmojiID))
} }

View file

@ -28,6 +28,7 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/media" "github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
type GetFileTestSuite struct { type GetFileTestSuite struct {
@ -67,8 +68,8 @@ func (suite *GetFileTestSuite) TestGetRemoteFileUncached() {
// uncache the file from local // uncache the file from local
testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"] testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"]
testAttachment.Cached = false testAttachment.Cached = testrig.FalseBool()
err := suite.db.UpdateByPrimaryKey(ctx, testAttachment) err := suite.db.UpdateByPrimaryKey(ctx, testAttachment, "cached")
suite.NoError(err) suite.NoError(err)
err = suite.storage.Delete(ctx, testAttachment.File.Path) err = suite.storage.Delete(ctx, testAttachment.File.Path)
suite.NoError(err) suite.NoError(err)
@ -103,7 +104,7 @@ func (suite *GetFileTestSuite) TestGetRemoteFileUncached() {
// the attachment should be updated in the database // the attachment should be updated in the database
dbAttachment, err := suite.db.GetAttachmentByID(ctx, testAttachment.ID) dbAttachment, err := suite.db.GetAttachmentByID(ctx, testAttachment.ID)
suite.NoError(err) suite.NoError(err)
suite.True(dbAttachment.Cached) suite.True(*dbAttachment.Cached)
// the file should be back in storage at the same path as before // the file should be back in storage at the same path as before
refreshedBytes, err := suite.storage.Get(ctx, testAttachment.File.Path) refreshedBytes, err := suite.storage.Get(ctx, testAttachment.File.Path)
@ -116,8 +117,8 @@ func (suite *GetFileTestSuite) TestGetRemoteFileUncachedInterrupted() {
// uncache the file from local // uncache the file from local
testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"] testAttachment := suite.testAttachments["remote_account_1_status_1_attachment_1"]
testAttachment.Cached = false testAttachment.Cached = testrig.FalseBool()
err := suite.db.UpdateByPrimaryKey(ctx, testAttachment) err := suite.db.UpdateByPrimaryKey(ctx, testAttachment, "cached")
suite.NoError(err) suite.NoError(err)
err = suite.storage.Delete(ctx, testAttachment.File.Path) err = suite.storage.Delete(ctx, testAttachment.File.Path)
suite.NoError(err) suite.NoError(err)
@ -153,7 +154,7 @@ func (suite *GetFileTestSuite) TestGetRemoteFileUncachedInterrupted() {
// the attachment should still be updated in the database even though the caller hung up // the attachment should still be updated in the database even though the caller hung up
dbAttachment, err := suite.db.GetAttachmentByID(ctx, testAttachment.ID) dbAttachment, err := suite.db.GetAttachmentByID(ctx, testAttachment.ID)
suite.NoError(err) suite.NoError(err)
suite.True(dbAttachment.Cached) suite.True(*dbAttachment.Cached)
// the file should be back in storage at the same path as before // the file should be back in storage at the same path as before
refreshedBytes, err := suite.storage.Get(ctx, testAttachment.File.Path) refreshedBytes, err := suite.storage.Get(ctx, testAttachment.File.Path)
@ -170,8 +171,8 @@ func (suite *GetFileTestSuite) TestGetRemoteFileThumbnailUncached() {
suite.NoError(err) suite.NoError(err)
// uncache the file from local // uncache the file from local
testAttachment.Cached = false testAttachment.Cached = testrig.FalseBool()
err = suite.db.UpdateByPrimaryKey(ctx, testAttachment) err = suite.db.UpdateByPrimaryKey(ctx, testAttachment, "cached")
suite.NoError(err) suite.NoError(err)
err = suite.storage.Delete(ctx, testAttachment.File.Path) err = suite.storage.Delete(ctx, testAttachment.File.Path)
suite.NoError(err) suite.NoError(err)

View file

@ -43,10 +43,11 @@ func (p *processor) Unattach(ctx context.Context, account *gtsmodel.Account, med
return nil, gtserror.NewErrorNotFound(errors.New("attachment not owned by requesting account")) return nil, gtserror.NewErrorNotFound(errors.New("attachment not owned by requesting account"))
} }
updatingColumns := []string{"updated_at", "status_id"}
attachment.UpdatedAt = time.Now() attachment.UpdatedAt = time.Now()
attachment.StatusID = "" attachment.StatusID = ""
if err := p.db.UpdateByPrimaryKey(ctx, attachment); err != nil { if err := p.db.UpdateByPrimaryKey(ctx, attachment, updatingColumns...); err != nil {
return nil, gtserror.NewErrorNotFound(fmt.Errorf("db error updating attachment: %s", err)) return nil, gtserror.NewErrorNotFound(fmt.Errorf("db error updating attachment: %s", err))
} }

View file

@ -30,7 +30,7 @@ type UnattachTestSuite struct {
MediaStandardTestSuite MediaStandardTestSuite
} }
func (suite *GetFileTestSuite) TestUnattachMedia() { func (suite *UnattachTestSuite) TestUnattachMedia() {
ctx := context.Background() ctx := context.Background()
testAttachment := suite.testAttachments["admin_account_status_1_attachment_1"] testAttachment := suite.testAttachments["admin_account_status_1_attachment_1"]

View file

@ -44,11 +44,11 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, media
return nil, gtserror.NewErrorNotFound(errors.New("attachment not owned by requesting account")) return nil, gtserror.NewErrorNotFound(errors.New("attachment not owned by requesting account"))
} }
updatingColumns := []string{}
if form.Description != nil { if form.Description != nil {
attachment.Description = text.SanitizePlaintext(*form.Description) attachment.Description = text.SanitizePlaintext(*form.Description)
if err := p.db.UpdateByPrimaryKey(ctx, attachment); err != nil { updatingColumns = append(updatingColumns, "description")
return nil, gtserror.NewErrorInternalError(fmt.Errorf("database error updating description: %s", err))
}
} }
if form.Focus != nil { if form.Focus != nil {
@ -58,9 +58,11 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, media
} }
attachment.FileMeta.Focus.X = focusx attachment.FileMeta.Focus.X = focusx
attachment.FileMeta.Focus.Y = focusy attachment.FileMeta.Focus.Y = focusy
if err := p.db.UpdateByPrimaryKey(ctx, attachment); err != nil { updatingColumns = append(updatingColumns, "focus_x", "focus_y")
return nil, gtserror.NewErrorInternalError(fmt.Errorf("database error updating focus: %s", err)) }
}
if err := p.db.UpdateByPrimaryKey(ctx, attachment, updatingColumns...); err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("database error updating media: %s", err))
} }
a, err := p.tc.AttachmentToAPIAttachment(ctx, attachment) a, err := p.tc.AttachmentToAPIAttachment(ctx, attachment)

View file

@ -40,18 +40,21 @@ func (p *processor) Create(ctx context.Context, account *gtsmodel.Account, appli
return nil, gtserror.NewErrorInternalError(err) return nil, gtserror.NewErrorInternalError(err)
} }
local := true
sensitive := form.Sensitive
newStatus := &gtsmodel.Status{ newStatus := &gtsmodel.Status{
ID: thisStatusID, ID: thisStatusID,
URI: accountURIs.StatusesURI + "/" + thisStatusID, URI: accountURIs.StatusesURI + "/" + thisStatusID,
URL: accountURIs.StatusesURL + "/" + thisStatusID, URL: accountURIs.StatusesURL + "/" + thisStatusID,
CreatedAt: time.Now(), CreatedAt: time.Now(),
UpdatedAt: time.Now(), UpdatedAt: time.Now(),
Local: true, Local: &local,
AccountID: account.ID, AccountID: account.ID,
AccountURI: account.URI, AccountURI: account.URI,
ContentWarning: text.SanitizePlaintext(form.SpoilerText), ContentWarning: text.SanitizePlaintext(form.SpoilerText),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
Sensitive: form.Sensitive, Sensitive: &sensitive,
Language: form.Language, Language: form.Language,
CreatedWithApplicationID: application.ID, CreatedWithApplicationID: application.ID,
Text: form.Status, Text: form.Status,

View file

@ -49,7 +49,7 @@ func (p *processor) Fave(ctx context.Context, requestingAccount *gtsmodel.Accoun
if !visible { if !visible {
return nil, gtserror.NewErrorNotFound(errors.New("status is not visible")) return nil, gtserror.NewErrorNotFound(errors.New("status is not visible"))
} }
if !targetStatus.Likeable { if !*targetStatus.Likeable {
return nil, gtserror.NewErrorForbidden(errors.New("status is not faveable")) return nil, gtserror.NewErrorForbidden(errors.New("status is not faveable"))
} }

View file

@ -98,10 +98,10 @@ func (p *processor) ProcessVisibility(ctx context.Context, form *apimodel.Advanc
} }
status.Visibility = vis status.Visibility = vis
status.Federated = federated status.Federated = &federated
status.Boostable = boostable status.Boostable = &boostable
status.Replyable = replyable status.Replyable = &replyable
status.Likeable = likeable status.Likeable = &likeable
return nil return nil
} }
@ -128,7 +128,7 @@ func (p *processor) ProcessReplyToID(ctx context.Context, form *apimodel.Advance
err := fmt.Errorf("db error fetching status with id %s: %s", form.InReplyToID, err) err := fmt.Errorf("db error fetching status with id %s: %s", form.InReplyToID, err)
return gtserror.NewErrorInternalError(err) return gtserror.NewErrorInternalError(err)
} }
if !repliedStatus.Replyable { if !*repliedStatus.Replyable {
err := fmt.Errorf("status with id %s is marked as not replyable", form.InReplyToID) err := fmt.Errorf("status with id %s is marked as not replyable", form.InReplyToID)
return gtserror.NewErrorForbidden(err, err.Error()) return gtserror.NewErrorForbidden(err, err.Error())
} }

View file

@ -20,6 +20,7 @@ package user
import ( import (
"context" "context"
"time"
"github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@ -42,7 +43,9 @@ func (p *processor) ChangePassword(ctx context.Context, user *gtsmodel.User, old
} }
user.EncryptedPassword = string(newPasswordHash) user.EncryptedPassword = string(newPasswordHash)
if err := p.db.UpdateByPrimaryKey(ctx, user); err != nil { user.UpdatedAt = time.Now()
if err := p.db.UpdateByPrimaryKey(ctx, user, "encrypted_password", "updated_at"); err != nil {
return gtserror.NewErrorInternalError(err, "database error") return gtserror.NewErrorInternalError(err, "database error")
} }

View file

@ -71,12 +71,13 @@ func (p *processor) SendConfirmEmail(ctx context.Context, user *gtsmodel.User, u
} }
// email sent, now we need to update the user entry with the token we just sent them // email sent, now we need to update the user entry with the token we just sent them
updatingColumns := []string{"confirmation_sent_at", "confirmation_token", "last_emailed_at", "updated_at"}
user.ConfirmationSentAt = time.Now() user.ConfirmationSentAt = time.Now()
user.ConfirmationToken = confirmationToken user.ConfirmationToken = confirmationToken
user.LastEmailedAt = time.Now() user.LastEmailedAt = time.Now()
user.UpdatedAt = time.Now() user.UpdatedAt = time.Now()
if err := p.db.UpdateByPrimaryKey(ctx, user); err != nil { if err := p.db.UpdateByPrimaryKey(ctx, user, updatingColumns...); err != nil {
return fmt.Errorf("SendConfirmEmail: error updating user entry after email sent: %s", err) return fmt.Errorf("SendConfirmEmail: error updating user entry after email sent: %s", err)
} }
@ -118,13 +119,14 @@ func (p *processor) ConfirmEmail(ctx context.Context, token string) (*gtsmodel.U
} }
// mark the user's email address as confirmed + remove the unconfirmed address and the token // mark the user's email address as confirmed + remove the unconfirmed address and the token
updatingColumns := []string{"email", "unconfirmed_email", "confirmed_at", "confirmation_token", "updated_at"}
user.Email = user.UnconfirmedEmail user.Email = user.UnconfirmedEmail
user.UnconfirmedEmail = "" user.UnconfirmedEmail = ""
user.ConfirmedAt = time.Now() user.ConfirmedAt = time.Now()
user.ConfirmationToken = "" user.ConfirmationToken = ""
user.UpdatedAt = time.Now() user.UpdatedAt = time.Now()
if err := p.db.UpdateByPrimaryKey(ctx, user); err != nil { if err := p.db.UpdateByPrimaryKey(ctx, user, updatingColumns...); err != nil {
return nil, gtserror.NewErrorInternalError(err) return nil, gtserror.NewErrorInternalError(err)
} }

View file

@ -67,13 +67,14 @@ func (suite *EmailConfirmTestSuite) TestConfirmEmail() {
user := suite.testUsers["local_account_1"] user := suite.testUsers["local_account_1"]
// set a bunch of stuff on the user as though zork hasn't been confirmed yet, but has had an email sent 5 minutes ago // set a bunch of stuff on the user as though zork hasn't been confirmed yet, but has had an email sent 5 minutes ago
updatingColumns := []string{"unconfirmed_email", "email", "confirmed_at", "confirmation_sent_at", "confirmation_token"}
user.UnconfirmedEmail = "some.email@example.org" user.UnconfirmedEmail = "some.email@example.org"
user.Email = "" user.Email = ""
user.ConfirmedAt = time.Time{} user.ConfirmedAt = time.Time{}
user.ConfirmationSentAt = time.Now().Add(-5 * time.Minute) user.ConfirmationSentAt = time.Now().Add(-5 * time.Minute)
user.ConfirmationToken = "1d1aa44b-afa4-49c8-ac4b-eceb61715cc6" user.ConfirmationToken = "1d1aa44b-afa4-49c8-ac4b-eceb61715cc6"
err := suite.db.UpdateByPrimaryKey(ctx, user) err := suite.db.UpdateByPrimaryKey(ctx, user, updatingColumns...)
suite.NoError(err) suite.NoError(err)
// confirm with the token set above // confirm with the token set above
@ -94,13 +95,14 @@ func (suite *EmailConfirmTestSuite) TestConfirmEmailOldToken() {
user := suite.testUsers["local_account_1"] user := suite.testUsers["local_account_1"]
// set a bunch of stuff on the user as though zork hasn't been confirmed yet, but has had an email sent 8 days ago // set a bunch of stuff on the user as though zork hasn't been confirmed yet, but has had an email sent 8 days ago
updatingColumns := []string{"unconfirmed_email", "email", "confirmed_at", "confirmation_sent_at", "confirmation_token"}
user.UnconfirmedEmail = "some.email@example.org" user.UnconfirmedEmail = "some.email@example.org"
user.Email = "" user.Email = ""
user.ConfirmedAt = time.Time{} user.ConfirmedAt = time.Time{}
user.ConfirmationSentAt = time.Now().Add(-192 * time.Hour) user.ConfirmationSentAt = time.Now().Add(-192 * time.Hour)
user.ConfirmationToken = "1d1aa44b-afa4-49c8-ac4b-eceb61715cc6" user.ConfirmationToken = "1d1aa44b-afa4-49c8-ac4b-eceb61715cc6"
err := suite.db.UpdateByPrimaryKey(ctx, user) err := suite.db.UpdateByPrimaryKey(ctx, user, updatingColumns...)
suite.NoError(err) suite.NoError(err)
// confirm with the token set above // confirm with the token set above

View file

@ -40,8 +40,8 @@ type UserStandardTestSuite struct {
} }
func (suite *UserStandardTestSuite) SetupTest() { func (suite *UserStandardTestSuite) SetupTest() {
testrig.InitTestLog()
testrig.InitTestConfig() testrig.InitTestConfig()
testrig.InitTestLog()
suite.db = testrig.NewTestDB() suite.db = testrig.NewTestDB()
suite.sentEmails = make(map[string]string) suite.sentEmails = make(map[string]string)

View file

@ -34,7 +34,7 @@ type Account struct {
Domain string `json:"domain,omitempty" bun:",nullzero"` Domain string `json:"domain,omitempty" bun:",nullzero"`
HeaderRemoteURL string `json:"headerRemoteURL,omitempty" bun:",nullzero"` HeaderRemoteURL string `json:"headerRemoteURL,omitempty" bun:",nullzero"`
AvatarRemoteURL string `json:"avatarRemoteURL,omitempty" bun:",nullzero"` AvatarRemoteURL string `json:"avatarRemoteURL,omitempty" bun:",nullzero"`
Locked bool `json:"locked"` Locked *bool `json:"locked" bun:",nullzero,notnull,default:true"`
Language string `json:"language,omitempty" bun:",nullzero"` Language string `json:"language,omitempty" bun:",nullzero"`
URI string `json:"uri" bun:",nullzero"` URI string `json:"uri" bun:",nullzero"`
URL string `json:"url" bun:",nullzero"` URL string `json:"url" bun:",nullzero"`

View file

@ -29,6 +29,6 @@ type DomainBlock struct {
CreatedByAccountID string `json:"createdByAccountID" bun:",nullzero"` CreatedByAccountID string `json:"createdByAccountID" bun:",nullzero"`
PrivateComment string `json:"privateComment,omitempty" bun:",nullzero"` PrivateComment string `json:"privateComment,omitempty" bun:",nullzero"`
PublicComment string `json:"publicComment,omitempty" bun:",nullzero"` PublicComment string `json:"publicComment,omitempty" bun:",nullzero"`
Obfuscate bool `json:"obfuscate" bun:",nullzero"` Obfuscate *bool `json:"obfuscate" bun:",nullzero,notnull,default:false"`
SubscriptionID string `json:"subscriptionID,omitempty" bun:",nullzero"` SubscriptionID string `json:"subscriptionID,omitempty" bun:",nullzero"`
} }

View file

@ -41,10 +41,10 @@ type User struct {
ConfirmationSentAt *time.Time `json:"confirmationTokenSentAt,omitempty" bun:",nullzero"` ConfirmationSentAt *time.Time `json:"confirmationTokenSentAt,omitempty" bun:",nullzero"`
ConfirmedAt *time.Time `json:"confirmedAt,omitempty" bun:",nullzero"` ConfirmedAt *time.Time `json:"confirmedAt,omitempty" bun:",nullzero"`
UnconfirmedEmail string `json:"unconfirmedEmail,omitempty" bun:",nullzero"` UnconfirmedEmail string `json:"unconfirmedEmail,omitempty" bun:",nullzero"`
Moderator bool `json:"moderator"` Moderator *bool `json:"moderator" bun:",nullzero,notnull,default:false"`
Admin bool `json:"admin"` Admin *bool `json:"admin" bun:",nullzero,notnull,default:false"`
Disabled bool `json:"disabled"` Disabled *bool `json:"disabled" bun:",nullzero,notnull,default:false"`
Approved bool `json:"approved"` Approved *bool `json:"approved" bun:",nullzero,notnull,default:false"`
ResetPasswordToken string `json:"resetPasswordToken,omitempty" bun:",nullzero"` ResetPasswordToken string `json:"resetPasswordToken,omitempty" bun:",nullzero"`
ResetPasswordSentAt *time.Time `json:"resetPasswordSentAt,omitempty" bun:",nullzero"` ResetPasswordSentAt *time.Time `json:"resetPasswordSentAt,omitempty" bun:",nullzero"`
} }

View file

@ -99,29 +99,46 @@ func (c *converter) ASRepresentationToAccount(ctx context.Context, accountable a
switch accountable.GetTypeName() { switch accountable.GetTypeName() {
case ap.ActorPerson, ap.ActorGroup, ap.ActorOrganization: case ap.ActorPerson, ap.ActorGroup, ap.ActorOrganization:
// people, groups, and organizations aren't bots // people, groups, and organizations aren't bots
acct.Bot = false bot := false
acct.Bot = &bot
// apps and services are // apps and services are
case ap.ActorApplication, ap.ActorService: case ap.ActorApplication, ap.ActorService:
acct.Bot = true bot := true
acct.Bot = &bot
default: default:
// we don't know what this is! // we don't know what this is!
return nil, fmt.Errorf("type name %s not recognised or not convertible to ap.ActivityStreamsActor", accountable.GetTypeName()) return nil, fmt.Errorf("type name %s not recognised or not convertible to ap.ActivityStreamsActor", accountable.GetTypeName())
} }
acct.ActorType = accountable.GetTypeName() acct.ActorType = accountable.GetTypeName()
// assume not memorial (todo)
memorial := false
acct.Memorial = &memorial
// assume not sensitive (todo)
sensitive := false
acct.Sensitive = &sensitive
// assume not hide collections (todo)
hideCollections := false
acct.HideCollections = &hideCollections
// locked aka manuallyApprovesFollowers // locked aka manuallyApprovesFollowers
acct.Locked = true // assume locked by default locked := true
acct.Locked = &locked // assume locked by default
maf := accountable.GetActivityStreamsManuallyApprovesFollowers() maf := accountable.GetActivityStreamsManuallyApprovesFollowers()
if maf != nil && maf.IsXMLSchemaBoolean() { if maf != nil && maf.IsXMLSchemaBoolean() {
acct.Locked = maf.Get() locked = maf.Get()
acct.Locked = &locked
} }
// discoverable // discoverable
// default to false -- take custom value if it's set though // default to false -- take custom value if it's set though
acct.Discoverable = false discoverable := false
discoverable, err := ap.ExtractDiscoverable(accountable) acct.Discoverable = &discoverable
d, err := ap.ExtractDiscoverable(accountable)
if err == nil { if err == nil {
acct.Discoverable = discoverable acct.Discoverable = &d
} }
// url property // url property
@ -289,13 +306,20 @@ func (c *converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusab
// advanced visibility for this status // advanced visibility for this status
// TODO: a lot of work to be done here -- a new type needs to be created for this in go-fed/activity using ASTOOL // TODO: a lot of work to be done here -- a new type needs to be created for this in go-fed/activity using ASTOOL
// for now we just set everything to true // for now we just set everything to true
status.Federated = true pinned := false
status.Boostable = true federated := true
status.Replyable = true boostable := true
status.Likeable = true replyable := true
likeable := true
status.Pinned = &pinned
status.Federated = &federated
status.Boostable = &boostable
status.Replyable = &replyable
status.Likeable = &likeable
// sensitive // sensitive
status.Sensitive = ap.ExtractSensitive(statusable) sensitive := ap.ExtractSensitive(statusable)
status.Sensitive = &sensitive
// language // language
// we might be able to extract this from the contentMap field // we might be able to extract this from the contentMap field

View file

@ -51,9 +51,9 @@ func (suite *ASToInternalTestSuite) TestParsePerson() {
suite.Equal("Geoff Brando New Personson", acct.DisplayName) suite.Equal("Geoff Brando New Personson", acct.DisplayName)
suite.Equal("hey I'm a new person, your instance hasn't seen me yet uwu", acct.Note) suite.Equal("hey I'm a new person, your instance hasn't seen me yet uwu", acct.Note)
suite.Equal("https://unknown-instance.com/@brand_new_person", acct.URL) suite.Equal("https://unknown-instance.com/@brand_new_person", acct.URL)
suite.True(acct.Discoverable) suite.True(*acct.Discoverable)
suite.Equal("https://unknown-instance.com/users/brand_new_person#main-key", acct.PublicKeyURI) suite.Equal("https://unknown-instance.com/users/brand_new_person#main-key", acct.PublicKeyURI)
suite.False(acct.Locked) suite.False(*acct.Locked)
} }
func (suite *ASToInternalTestSuite) TestParsePublicStatus() { func (suite *ASToInternalTestSuite) TestParsePublicStatus() {
@ -145,10 +145,10 @@ func (suite *ASToInternalTestSuite) TestParseReplyWithMention() {
suite.Equal(inReplyToAccount.ID, status.InReplyToAccountID) suite.Equal(inReplyToAccount.ID, status.InReplyToAccountID)
suite.Equal(inReplyToStatus.ID, status.InReplyToID) suite.Equal(inReplyToStatus.ID, status.InReplyToID)
suite.Equal(inReplyToStatus.URI, status.InReplyToURI) suite.Equal(inReplyToStatus.URI, status.InReplyToURI)
suite.True(status.Federated) suite.True(*status.Federated)
suite.True(status.Boostable) suite.True(*status.Boostable)
suite.True(status.Replyable) suite.True(*status.Replyable)
suite.True(status.Likeable) suite.True(*status.Likeable)
suite.Equal(`<p><span class="h-card"><a href="http://localhost:8080/@the_mighty_zork" class="u-url mention">@<span>the_mighty_zork</span></a></span> nice there it is:</p><p><a href="http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/activity" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="ellipsis">social.pixie.town/users/f0x/st</span><span class="invisible">atuses/106221628567855262/activity</span></a></p>`, status.Content) suite.Equal(`<p><span class="h-card"><a href="http://localhost:8080/@the_mighty_zork" class="u-url mention">@<span>the_mighty_zork</span></a></span> nice there it is:</p><p><a href="http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY/activity" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="ellipsis">social.pixie.town/users/f0x/st</span><span class="invisible">atuses/106221628567855262/activity</span></a></p>`, status.Content)
suite.Len(status.Mentions, 1) suite.Len(status.Mentions, 1)
m1 := status.Mentions[0] m1 := status.Mentions[0]
@ -177,9 +177,9 @@ func (suite *ASToInternalTestSuite) TestParseOwncastService() {
suite.Equal("https://owncast.example.org/logo/external", acct.HeaderRemoteURL) suite.Equal("https://owncast.example.org/logo/external", acct.HeaderRemoteURL)
suite.Equal("Rob's Owncast Server", acct.DisplayName) suite.Equal("Rob's Owncast Server", acct.DisplayName)
suite.Equal("linux audio stuff ", acct.Note) suite.Equal("linux audio stuff ", acct.Note)
suite.True(acct.Bot) suite.True(*acct.Bot)
suite.False(acct.Locked) suite.False(*acct.Locked)
suite.True(acct.Discoverable) suite.True(*acct.Discoverable)
suite.Equal("https://owncast.example.org/federation/user/rgh", acct.URI) suite.Equal("https://owncast.example.org/federation/user/rgh", acct.URI)
suite.Equal("https://owncast.example.org/federation/user/rgh", acct.URL) suite.Equal("https://owncast.example.org/federation/user/rgh", acct.URL)
suite.Equal("https://owncast.example.org/federation/user/rgh/inbox", acct.InboxURI) suite.Equal("https://owncast.example.org/federation/user/rgh/inbox", acct.InboxURI)

View file

@ -11,15 +11,18 @@ import (
) )
func (c *converter) FollowRequestToFollow(ctx context.Context, f *gtsmodel.FollowRequest) *gtsmodel.Follow { func (c *converter) FollowRequestToFollow(ctx context.Context, f *gtsmodel.FollowRequest) *gtsmodel.Follow {
showReblogs := *f.ShowReblogs
notify := *f.Notify
return &gtsmodel.Follow{ return &gtsmodel.Follow{
ID: f.ID, ID: f.ID,
CreatedAt: f.CreatedAt, CreatedAt: f.CreatedAt,
UpdatedAt: f.UpdatedAt, UpdatedAt: f.UpdatedAt,
AccountID: f.AccountID, AccountID: f.AccountID,
TargetAccountID: f.TargetAccountID, TargetAccountID: f.TargetAccountID,
ShowReblogs: f.ShowReblogs, ShowReblogs: &showReblogs,
URI: f.URI, URI: f.URI,
Notify: f.Notify, Notify: &notify,
} }
} }
@ -38,6 +41,13 @@ func (c *converter) StatusToBoost(ctx context.Context, s *gtsmodel.Status, boost
local = false local = false
} }
sensitive := *s.Sensitive
pinned := false // can't pin a boost
federated := *s.Federated
boostable := *s.Boostable
replyable := *s.Replyable
likeable := *s.Likeable
boostWrapperStatus := &gtsmodel.Status{ boostWrapperStatus := &gtsmodel.Status{
ID: boostWrapperStatusID, ID: boostWrapperStatusID,
URI: boostWrapperStatusURI, URI: boostWrapperStatusURI,
@ -46,7 +56,7 @@ func (c *converter) StatusToBoost(ctx context.Context, s *gtsmodel.Status, boost
// the boosted status is not created now, but the boost certainly is // the boosted status is not created now, but the boost certainly is
CreatedAt: time.Now(), CreatedAt: time.Now(),
UpdatedAt: time.Now(), UpdatedAt: time.Now(),
Local: local, Local: &local,
AccountID: boostingAccount.ID, AccountID: boostingAccount.ID,
AccountURI: boostingAccount.URI, AccountURI: boostingAccount.URI,
@ -64,16 +74,17 @@ func (c *converter) StatusToBoost(ctx context.Context, s *gtsmodel.Status, boost
Content: s.Content, Content: s.Content,
ContentWarning: s.ContentWarning, ContentWarning: s.ContentWarning,
ActivityStreamsType: s.ActivityStreamsType, ActivityStreamsType: s.ActivityStreamsType,
Sensitive: s.Sensitive, Sensitive: &sensitive,
Language: s.Language, Language: s.Language,
Text: s.Text, Text: s.Text,
BoostOfID: s.ID, BoostOfID: s.ID,
BoostOfAccountID: s.AccountID, BoostOfAccountID: s.AccountID,
Visibility: s.Visibility, Visibility: s.Visibility,
Federated: s.Federated, Pinned: &pinned,
Boostable: s.Boostable, Federated: &federated,
Replyable: s.Replyable, Boostable: &boostable,
Likeable: s.Likeable, Replyable: &replyable,
Likeable: &likeable,
// attach these here for convenience -- the boosted status/account won't go in the DB // attach these here for convenience -- the boosted status/account won't go in the DB
// but they're needed in the processor and for the frontend. Since we have them, we can // but they're needed in the processor and for the frontend. Since we have them, we can

View file

@ -145,13 +145,13 @@ func (c *converter) AccountToAS(ctx context.Context, a *gtsmodel.Account) (vocab
// manuallyApprovesFollowers // manuallyApprovesFollowers
// Will be shown as a locked account. // Will be shown as a locked account.
manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty() manuallyApprovesFollowersProp := streams.NewActivityStreamsManuallyApprovesFollowersProperty()
manuallyApprovesFollowersProp.Set(a.Locked) manuallyApprovesFollowersProp.Set(*a.Locked)
person.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp) person.SetActivityStreamsManuallyApprovesFollowers(manuallyApprovesFollowersProp)
// discoverable // discoverable
// Will be shown in the profile directory. // Will be shown in the profile directory.
discoverableProp := streams.NewTootDiscoverableProperty() discoverableProp := streams.NewTootDiscoverableProperty()
discoverableProp.Set(a.Discoverable) discoverableProp.Set(*a.Discoverable)
person.SetTootDiscoverable(discoverableProp) person.SetTootDiscoverable(discoverableProp)
// devices // devices
@ -539,7 +539,7 @@ func (c *converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (vocab.A
// sensitive // sensitive
sensitiveProp := streams.NewActivityStreamsSensitiveProperty() sensitiveProp := streams.NewActivityStreamsSensitiveProperty()
sensitiveProp.AppendXMLSchemaBoolean(s.Sensitive) sensitiveProp.AppendXMLSchemaBoolean(*s.Sensitive)
status.SetActivityStreamsSensitive(sensitiveProp) status.SetActivityStreamsSensitive(sensitiveProp)
return status, nil return status, nil

View file

@ -60,7 +60,7 @@ func (c *converter) AccountToAPIAccountSensitive(ctx context.Context, a *gtsmode
apiAccount.Source = &model.Source{ apiAccount.Source = &model.Source{
Privacy: c.VisToAPIVis(ctx, a.Privacy), Privacy: c.VisToAPIVis(ctx, a.Privacy),
Sensitive: a.Sensitive, Sensitive: *a.Sensitive,
Language: a.Language, Language: a.Language,
StatusFormat: statusFormat, StatusFormat: statusFormat,
Note: a.NoteRaw, Note: a.NoteRaw,
@ -172,8 +172,8 @@ func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
Username: a.Username, Username: a.Username,
Acct: acct, Acct: acct,
DisplayName: a.DisplayName, DisplayName: a.DisplayName,
Locked: a.Locked, Locked: *a.Locked,
Bot: a.Bot, Bot: *a.Bot,
CreatedAt: util.FormatISO8601(a.CreatedAt), CreatedAt: util.FormatISO8601(a.CreatedAt),
Note: a.Note, Note: a.Note,
URL: a.URL, URL: a.URL,
@ -213,7 +213,7 @@ func (c *converter) AccountToAPIAccountBlocked(ctx context.Context, a *gtsmodel.
Username: a.Username, Username: a.Username,
Acct: acct, Acct: acct,
DisplayName: a.DisplayName, DisplayName: a.DisplayName,
Bot: a.Bot, Bot: *a.Bot,
CreatedAt: util.FormatISO8601(a.CreatedAt), CreatedAt: util.FormatISO8601(a.CreatedAt),
URL: a.URL, URL: a.URL,
Suspended: suspended, Suspended: suspended,
@ -323,7 +323,7 @@ func (c *converter) EmojiToAPIEmoji(ctx context.Context, e *gtsmodel.Emoji) (mod
Shortcode: e.Shortcode, Shortcode: e.Shortcode,
URL: e.ImageURL, URL: e.ImageURL,
StaticURL: e.ImageStaticURL, StaticURL: e.ImageStaticURL,
VisibleInPicker: e.VisibleInPicker, VisibleInPicker: *e.VisibleInPicker,
Category: e.CategoryID, Category: e.CategoryID,
}, nil }, nil
} }
@ -539,7 +539,7 @@ func (c *converter) StatusToAPIStatus(ctx context.Context, s *gtsmodel.Status, r
CreatedAt: util.FormatISO8601(s.CreatedAt), CreatedAt: util.FormatISO8601(s.CreatedAt),
InReplyToID: s.InReplyToID, InReplyToID: s.InReplyToID,
InReplyToAccountID: s.InReplyToAccountID, InReplyToAccountID: s.InReplyToAccountID,
Sensitive: s.Sensitive, Sensitive: *s.Sensitive,
SpoilerText: s.ContentWarning, SpoilerText: s.ContentWarning,
Visibility: c.VisToAPIVis(ctx, s.Visibility), Visibility: c.VisToAPIVis(ctx, s.Visibility),
Language: s.Language, Language: s.Language,
@ -552,7 +552,7 @@ func (c *converter) StatusToAPIStatus(ctx context.Context, s *gtsmodel.Status, r
Bookmarked: statusInteractions.Bookmarked, Bookmarked: statusInteractions.Bookmarked,
Muted: statusInteractions.Muted, Muted: statusInteractions.Muted,
Reblogged: statusInteractions.Reblogged, Reblogged: statusInteractions.Reblogged,
Pinned: s.Pinned, Pinned: *s.Pinned,
Content: s.Content, Content: s.Content,
Application: apiApplication, Application: apiApplication,
Account: apiAuthorAccount, Account: apiAuthorAccount,
@ -762,7 +762,7 @@ func (c *converter) DomainBlockToAPIDomainBlock(ctx context.Context, b *gtsmodel
// if we're exporting a domain block, return it with minimal information attached // if we're exporting a domain block, return it with minimal information attached
if !export { if !export {
domainBlock.ID = b.ID domainBlock.ID = b.ID
domainBlock.Obfuscate = b.Obfuscate domainBlock.Obfuscate = *b.Obfuscate
domainBlock.PrivateComment = b.PrivateComment domainBlock.PrivateComment = b.PrivateComment
domainBlock.SubscriptionID = b.SubscriptionID domainBlock.SubscriptionID = b.SubscriptionID
domainBlock.CreatedBy = b.CreatedByAccountID domainBlock.CreatedBy = b.CreatedByAccountID

View file

@ -28,6 +28,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/validate" "github.com/superseriousbusiness/gotosocial/internal/validate"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
func happyAccount() *gtsmodel.Account { func happyAccount() *gtsmodel.Account {
@ -52,15 +53,15 @@ func happyAccount() *gtsmodel.Account {
DisplayName: "original zork (he/they)", DisplayName: "original zork (he/they)",
Fields: []gtsmodel.Field{}, Fields: []gtsmodel.Field{},
Note: "hey yo this is my profile!", Note: "hey yo this is my profile!",
Memorial: false, Memorial: testrig.FalseBool(),
AlsoKnownAs: "", AlsoKnownAs: "",
MovedToAccountID: "", MovedToAccountID: "",
Bot: false, Bot: testrig.FalseBool(),
Reason: "I wanna be on this damned webbed site so bad! Please! Wow", Reason: "I wanna be on this damned webbed site so bad! Please! Wow",
Locked: false, Locked: testrig.FalseBool(),
Discoverable: true, Discoverable: testrig.TrueBool(),
Privacy: gtsmodel.VisibilityPublic, Privacy: gtsmodel.VisibilityPublic,
Sensitive: false, Sensitive: testrig.FalseBool(),
Language: "en", Language: "en",
StatusFormat: "plain", StatusFormat: "plain",
URI: "http://localhost:8080/users/the_mighty_zork", URI: "http://localhost:8080/users/the_mighty_zork",
@ -78,7 +79,7 @@ func happyAccount() *gtsmodel.Account {
SensitizedAt: time.Time{}, SensitizedAt: time.Time{},
SilencedAt: time.Time{}, SilencedAt: time.Time{},
SuspendedAt: time.Time{}, SuspendedAt: time.Time{},
HideCollections: false, HideCollections: testrig.FalseBool(),
SuspensionOrigin: "", SuspensionOrigin: "",
} }
} }

View file

@ -25,6 +25,7 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/validate" "github.com/superseriousbusiness/gotosocial/internal/validate"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
func happyDomainBlock() *gtsmodel.DomainBlock { func happyDomainBlock() *gtsmodel.DomainBlock {
@ -36,7 +37,7 @@ func happyDomainBlock() *gtsmodel.DomainBlock {
CreatedByAccountID: "01FEED79PRMVWPRMFHFQM8MJQN", CreatedByAccountID: "01FEED79PRMVWPRMFHFQM8MJQN",
PrivateComment: "we don't like em", PrivateComment: "we don't like em",
PublicComment: "poo poo dudes", PublicComment: "poo poo dudes",
Obfuscate: false, Obfuscate: testrig.FalseBool(),
SubscriptionID: "", SubscriptionID: "",
} }
} }

View file

@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/validate" "github.com/superseriousbusiness/gotosocial/internal/validate"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
func happyEmoji() *gtsmodel.Emoji { func happyEmoji() *gtsmodel.Emoji {
@ -73,9 +74,9 @@ func happyEmoji() *gtsmodel.Emoji {
ImageFileSize: 1024, ImageFileSize: 1024,
ImageStaticFileSize: 256, ImageStaticFileSize: 256,
ImageUpdatedAt: time.Now(), ImageUpdatedAt: time.Now(),
Disabled: false, Disabled: testrig.FalseBool(),
URI: "https://example.org/emojis/blob_test", URI: "https://example.org/emojis/blob_test",
VisibleInPicker: true, VisibleInPicker: testrig.TrueBool(),
CategoryID: "01FEE47ZH70PWDSEAVBRFNX325", CategoryID: "01FEE47ZH70PWDSEAVBRFNX325",
} }
} }

View file

@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/validate" "github.com/superseriousbusiness/gotosocial/internal/validate"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
func happyMediaAttachment() *gtsmodel.MediaAttachment { func happyMediaAttachment() *gtsmodel.MediaAttachment {
@ -97,8 +98,8 @@ func happyMediaAttachment() *gtsmodel.MediaAttachment {
URL: "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpeg", URL: "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpeg",
RemoteURL: "", RemoteURL: "",
}, },
Avatar: false, Avatar: testrig.FalseBool(),
Header: false, Header: testrig.FalseBool(),
} }
} }

View file

@ -26,6 +26,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/validate" "github.com/superseriousbusiness/gotosocial/internal/validate"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
func happyStatus() *gtsmodel.Status { func happyStatus() *gtsmodel.Status {
@ -44,7 +45,7 @@ func happyStatus() *gtsmodel.Status {
Mentions: nil, Mentions: nil,
EmojiIDs: nil, EmojiIDs: nil,
Emojis: nil, Emojis: nil,
Local: true, Local: testrig.TrueBool(),
AccountID: "01FEBBQ4KEP3824WW61MF52638", AccountID: "01FEBBQ4KEP3824WW61MF52638",
Account: nil, Account: nil,
AccountURI: "https://example.org/users/test_user", AccountURI: "https://example.org/users/test_user",
@ -59,17 +60,17 @@ func happyStatus() *gtsmodel.Status {
BoostOfAccount: nil, BoostOfAccount: nil,
ContentWarning: "hello world test post", ContentWarning: "hello world test post",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: false, Sensitive: testrig.FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01FEBBZHF4GFVRXSJVXD0JTZZ2", CreatedWithApplicationID: "01FEBBZHF4GFVRXSJVXD0JTZZ2",
CreatedWithApplication: nil, CreatedWithApplication: nil,
Federated: true, Federated: testrig.TrueBool(),
Boostable: true, Boostable: testrig.TrueBool(),
Replyable: true, Replyable: testrig.TrueBool(),
Likeable: true, Likeable: testrig.TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
Text: "Test status! #hello", Text: "Test status! #hello",
Pinned: false, Pinned: testrig.FalseBool(),
} }
} }
@ -127,7 +128,7 @@ func (suite *StatusValidateTestSuite) TestStatusApplicationID() {
err := validate.Struct(s) err := validate.Struct(s)
suite.EqualError(err, "Key: 'Status.CreatedWithApplicationID' Error:Field validation for 'CreatedWithApplicationID' failed on the 'required_if' tag") suite.EqualError(err, "Key: 'Status.CreatedWithApplicationID' Error:Field validation for 'CreatedWithApplicationID' failed on the 'required_if' tag")
s.Local = false s.Local = testrig.FalseBool()
err = validate.Struct(s) err = validate.Struct(s)
suite.NoError(err) suite.NoError(err)
} }

View file

@ -25,6 +25,7 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/validate" "github.com/superseriousbusiness/gotosocial/internal/validate"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
func happyTag() *gtsmodel.Tag { func happyTag() *gtsmodel.Tag {
@ -35,8 +36,8 @@ func happyTag() *gtsmodel.Tag {
URL: "https://example.org/tags/some_tag", URL: "https://example.org/tags/some_tag",
Name: "some_tag", Name: "some_tag",
FirstSeenFromAccountID: "01FE91SR5P2GW06K3AJ98P72MT", FirstSeenFromAccountID: "01FE91SR5P2GW06K3AJ98P72MT",
Useable: true, Useable: testrig.TrueBool(),
Listable: true, Listable: testrig.TrueBool(),
LastStatusAt: time.Now(), LastStatusAt: time.Now(),
} }
} }

View file

@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/validate" "github.com/superseriousbusiness/gotosocial/internal/validate"
"github.com/superseriousbusiness/gotosocial/testrig"
) )
func happyUser() *gtsmodel.User { func happyUser() *gtsmodel.User {
@ -54,10 +55,10 @@ func happyUser() *gtsmodel.User {
ConfirmedAt: time.Now(), ConfirmedAt: time.Now(),
ConfirmationSentAt: time.Time{}, ConfirmationSentAt: time.Time{},
UnconfirmedEmail: "", UnconfirmedEmail: "",
Moderator: false, Moderator: testrig.FalseBool(),
Admin: false, Admin: testrig.FalseBool(),
Disabled: false, Disabled: testrig.FalseBool(),
Approved: true, Approved: testrig.TrueBool(),
} }
} }

View file

@ -57,5 +57,5 @@ func (f *filter) StatusBoostable(ctx context.Context, targetStatus *gtsmodel.Sta
// otherwise, status is as boostable as it says it is // otherwise, status is as boostable as it says it is
log.Trace("defaulting to status.boostable value") log.Trace("defaulting to status.boostable value")
return targetStatus.Boostable, nil return *targetStatus.Boostable, nil
} }

View file

@ -91,7 +91,7 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyFollowersOnly(
Content: "didn't expect dog", Content: "didn't expect dog",
CreatedAt: testrig.TimeMustParse("2021-09-20T12:40:37+02:00"), CreatedAt: testrig.TimeMustParse("2021-09-20T12:40:37+02:00"),
UpdatedAt: testrig.TimeMustParse("2021-09-20T12:40:37+02:00"), UpdatedAt: testrig.TimeMustParse("2021-09-20T12:40:37+02:00"),
Local: false, Local: testrig.FalseBool(),
AccountURI: "http://fossbros-anonymous.io/users/foss_satan", AccountURI: "http://fossbros-anonymous.io/users/foss_satan",
AccountID: originalStatusParent.ID, AccountID: originalStatusParent.ID,
InReplyToID: "", InReplyToID: "",
@ -100,13 +100,13 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyFollowersOnly(
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityFollowersOnly, Visibility: gtsmodel.VisibilityFollowersOnly,
Sensitive: false, Sensitive: testrig.FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "", CreatedWithApplicationID: "",
Federated: true, Federated: testrig.TrueBool(),
Boostable: true, Boostable: testrig.TrueBool(),
Replyable: true, Replyable: testrig.TrueBool(),
Likeable: true, Likeable: testrig.TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
} }
if err := suite.db.PutStatus(ctx, originalStatus); err != nil { if err := suite.db.PutStatus(ctx, originalStatus); err != nil {
@ -125,7 +125,7 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyFollowersOnly(
Content: "nbnbdy expects dog", Content: "nbnbdy expects dog",
CreatedAt: testrig.TimeMustParse("2021-09-20T12:41:37+02:00"), CreatedAt: testrig.TimeMustParse("2021-09-20T12:41:37+02:00"),
UpdatedAt: testrig.TimeMustParse("2021-09-20T12:41:37+02:00"), UpdatedAt: testrig.TimeMustParse("2021-09-20T12:41:37+02:00"),
Local: false, Local: testrig.FalseBool(),
AccountURI: "http://localhost:8080/users/the_mighty_zork", AccountURI: "http://localhost:8080/users/the_mighty_zork",
AccountID: replyingAccount.ID, AccountID: replyingAccount.ID,
InReplyToID: originalStatus.ID, InReplyToID: originalStatus.ID,
@ -134,13 +134,13 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyFollowersOnly(
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityFollowersOnly, Visibility: gtsmodel.VisibilityFollowersOnly,
Sensitive: false, Sensitive: testrig.FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "", CreatedWithApplicationID: "",
Federated: true, Federated: testrig.TrueBool(),
Boostable: true, Boostable: testrig.TrueBool(),
Replyable: true, Replyable: testrig.TrueBool(),
Likeable: true, Likeable: testrig.TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
} }
if err := suite.db.PutStatus(ctx, firstReplyStatus); err != nil { if err := suite.db.PutStatus(ctx, firstReplyStatus); err != nil {
@ -159,7 +159,7 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyFollowersOnly(
Content: "*nobody", Content: "*nobody",
CreatedAt: testrig.TimeMustParse("2021-09-20T12:42:37+02:00"), CreatedAt: testrig.TimeMustParse("2021-09-20T12:42:37+02:00"),
UpdatedAt: testrig.TimeMustParse("2021-09-20T12:42:37+02:00"), UpdatedAt: testrig.TimeMustParse("2021-09-20T12:42:37+02:00"),
Local: false, Local: testrig.FalseBool(),
AccountURI: "http://localhost:8080/users/the_mighty_zork", AccountURI: "http://localhost:8080/users/the_mighty_zork",
AccountID: replyingAccount.ID, AccountID: replyingAccount.ID,
InReplyToID: firstReplyStatus.ID, InReplyToID: firstReplyStatus.ID,
@ -168,13 +168,13 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyFollowersOnly(
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityFollowersOnly, Visibility: gtsmodel.VisibilityFollowersOnly,
Sensitive: false, Sensitive: testrig.FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "", CreatedWithApplicationID: "",
Federated: true, Federated: testrig.TrueBool(),
Boostable: true, Boostable: testrig.TrueBool(),
Replyable: true, Replyable: testrig.TrueBool(),
Likeable: true, Likeable: testrig.TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
} }
if err := suite.db.PutStatus(ctx, secondReplyStatus); err != nil { if err := suite.db.PutStatus(ctx, secondReplyStatus); err != nil {
@ -204,7 +204,7 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyPublicAndUnloc
Content: "didn't expect dog", Content: "didn't expect dog",
CreatedAt: testrig.TimeMustParse("2021-09-20T12:40:37+02:00"), CreatedAt: testrig.TimeMustParse("2021-09-20T12:40:37+02:00"),
UpdatedAt: testrig.TimeMustParse("2021-09-20T12:40:37+02:00"), UpdatedAt: testrig.TimeMustParse("2021-09-20T12:40:37+02:00"),
Local: false, Local: testrig.FalseBool(),
AccountURI: "http://fossbros-anonymous.io/users/foss_satan", AccountURI: "http://fossbros-anonymous.io/users/foss_satan",
AccountID: originalStatusParent.ID, AccountID: originalStatusParent.ID,
InReplyToID: "", InReplyToID: "",
@ -213,13 +213,13 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyPublicAndUnloc
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityUnlocked, Visibility: gtsmodel.VisibilityUnlocked,
Sensitive: false, Sensitive: testrig.FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "", CreatedWithApplicationID: "",
Federated: true, Federated: testrig.TrueBool(),
Boostable: true, Boostable: testrig.TrueBool(),
Replyable: true, Replyable: testrig.TrueBool(),
Likeable: true, Likeable: testrig.TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
} }
if err := suite.db.PutStatus(ctx, originalStatus); err != nil { if err := suite.db.PutStatus(ctx, originalStatus); err != nil {
@ -238,7 +238,7 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyPublicAndUnloc
Content: "nbnbdy expects dog", Content: "nbnbdy expects dog",
CreatedAt: testrig.TimeMustParse("2021-09-20T12:41:37+02:00"), CreatedAt: testrig.TimeMustParse("2021-09-20T12:41:37+02:00"),
UpdatedAt: testrig.TimeMustParse("2021-09-20T12:41:37+02:00"), UpdatedAt: testrig.TimeMustParse("2021-09-20T12:41:37+02:00"),
Local: false, Local: testrig.FalseBool(),
AccountURI: "http://localhost:8080/users/the_mighty_zork", AccountURI: "http://localhost:8080/users/the_mighty_zork",
AccountID: replyingAccount.ID, AccountID: replyingAccount.ID,
InReplyToID: originalStatus.ID, InReplyToID: originalStatus.ID,
@ -247,13 +247,13 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyPublicAndUnloc
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: false, Sensitive: testrig.FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "", CreatedWithApplicationID: "",
Federated: true, Federated: testrig.TrueBool(),
Boostable: true, Boostable: testrig.TrueBool(),
Replyable: true, Replyable: testrig.TrueBool(),
Likeable: true, Likeable: testrig.TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
} }
if err := suite.db.PutStatus(ctx, firstReplyStatus); err != nil { if err := suite.db.PutStatus(ctx, firstReplyStatus); err != nil {
@ -272,7 +272,7 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyPublicAndUnloc
Content: "*nobody", Content: "*nobody",
CreatedAt: testrig.TimeMustParse("2021-09-20T12:42:37+02:00"), CreatedAt: testrig.TimeMustParse("2021-09-20T12:42:37+02:00"),
UpdatedAt: testrig.TimeMustParse("2021-09-20T12:42:37+02:00"), UpdatedAt: testrig.TimeMustParse("2021-09-20T12:42:37+02:00"),
Local: false, Local: testrig.FalseBool(),
AccountURI: "http://localhost:8080/users/the_mighty_zork", AccountURI: "http://localhost:8080/users/the_mighty_zork",
AccountID: replyingAccount.ID, AccountID: replyingAccount.ID,
InReplyToID: firstReplyStatus.ID, InReplyToID: firstReplyStatus.ID,
@ -281,13 +281,13 @@ func (suite *StatusStatusHometimelineableTestSuite) TestChainReplyPublicAndUnloc
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityUnlocked, Visibility: gtsmodel.VisibilityUnlocked,
Sensitive: false, Sensitive: testrig.FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "", CreatedWithApplicationID: "",
Federated: true, Federated: testrig.TrueBool(),
Boostable: true, Boostable: testrig.TrueBool(),
Replyable: true, Replyable: testrig.TrueBool(),
Likeable: true, Likeable: testrig.TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
} }
if err := suite.db.PutStatus(ctx, secondReplyStatus); err != nil { if err := suite.db.PutStatus(ctx, secondReplyStatus); err != nil {

View file

@ -79,7 +79,7 @@ func (f *filter) StatusVisible(ctx context.Context, targetStatus *gtsmodel.Statu
// if target user is disabled, not yet approved, or not confirmed then don't show the status // if target user is disabled, not yet approved, or not confirmed then don't show the status
// (although in the latter two cases it's unlikely they posted a status yet anyway, but you never know!) // (although in the latter two cases it's unlikely they posted a status yet anyway, but you never know!)
if targetUser.Disabled || !targetUser.Approved || targetUser.ConfirmedAt.IsZero() { if *targetUser.Disabled || !*targetUser.Approved || targetUser.ConfirmedAt.IsZero() {
l.Trace("target user is disabled, not approved, or not confirmed") l.Trace("target user is disabled, not approved, or not confirmed")
return false, nil return false, nil
} }
@ -108,7 +108,7 @@ func (f *filter) StatusVisible(ctx context.Context, targetStatus *gtsmodel.Statu
return false, fmt.Errorf("StatusVisible: db error selecting user for local requesting account %s: %s", requestingAccount.ID, err) return false, fmt.Errorf("StatusVisible: db error selecting user for local requesting account %s: %s", requestingAccount.ID, err)
} }
// okay, user exists, so make sure it has full privileges/is confirmed/approved // okay, user exists, so make sure it has full privileges/is confirmed/approved
if requestingUser.Disabled || !requestingUser.Approved || requestingUser.ConfirmedAt.IsZero() { if *requestingUser.Disabled || !*requestingUser.Approved || requestingUser.ConfirmedAt.IsZero() {
l.Trace("requesting account is local but corresponding user is either disabled, not approved, or not confirmed") l.Trace("requesting account is local but corresponding user is either disabled, not approved, or not confirmed")
return false, nil return false, nil
} }

View file

@ -43,6 +43,18 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/transport" "github.com/superseriousbusiness/gotosocial/internal/transport"
) )
// TrueBool just returns a pointer to boolean true.
func TrueBool() *bool {
b := new(bool)
*b = true
return b
}
// FalseBool just returns a pointer to boolean false.
func FalseBool() *bool {
return new(bool)
}
// NewTestTokens returns a map of tokens keyed according to which account the token belongs to. // NewTestTokens returns a map of tokens keyed according to which account the token belongs to.
func NewTestTokens() map[string]*gtsmodel.Token { func NewTestTokens() map[string]*gtsmodel.Token {
tokens := map[string]*gtsmodel.Token{ tokens := map[string]*gtsmodel.Token{
@ -182,10 +194,10 @@ func NewTestUsers() map[string]*gtsmodel.User {
ConfirmedAt: time.Time{}, ConfirmedAt: time.Time{},
ConfirmationSentAt: TimeMustParse("2022-06-04T13:12:00Z"), ConfirmationSentAt: TimeMustParse("2022-06-04T13:12:00Z"),
UnconfirmedEmail: "weed_lord420@example.org", UnconfirmedEmail: "weed_lord420@example.org",
Moderator: false, Moderator: FalseBool(),
Admin: false, Admin: FalseBool(),
Disabled: false, Disabled: FalseBool(),
Approved: false, Approved: FalseBool(),
ResetPasswordToken: "", ResetPasswordToken: "",
ResetPasswordSentAt: time.Time{}, ResetPasswordSentAt: time.Time{},
}, },
@ -212,10 +224,10 @@ func NewTestUsers() map[string]*gtsmodel.User {
ConfirmedAt: TimeMustParse("2022-06-02T13:12:00Z"), ConfirmedAt: TimeMustParse("2022-06-02T13:12:00Z"),
ConfirmationSentAt: time.Time{}, ConfirmationSentAt: time.Time{},
UnconfirmedEmail: "", UnconfirmedEmail: "",
Moderator: true, Moderator: TrueBool(),
Admin: true, Admin: TrueBool(),
Disabled: false, Disabled: FalseBool(),
Approved: true, Approved: TrueBool(),
ResetPasswordToken: "", ResetPasswordToken: "",
ResetPasswordSentAt: time.Time{}, ResetPasswordSentAt: time.Time{},
}, },
@ -242,10 +254,10 @@ func NewTestUsers() map[string]*gtsmodel.User {
ConfirmedAt: TimeMustParse("2022-06-02T13:12:00Z"), ConfirmedAt: TimeMustParse("2022-06-02T13:12:00Z"),
ConfirmationSentAt: TimeMustParse("2022-06-02T13:12:00Z"), ConfirmationSentAt: TimeMustParse("2022-06-02T13:12:00Z"),
UnconfirmedEmail: "", UnconfirmedEmail: "",
Moderator: false, Moderator: FalseBool(),
Admin: false, Admin: FalseBool(),
Disabled: false, Disabled: FalseBool(),
Approved: true, Approved: TrueBool(),
ResetPasswordToken: "", ResetPasswordToken: "",
ResetPasswordSentAt: time.Time{}, ResetPasswordSentAt: time.Time{},
}, },
@ -272,10 +284,10 @@ func NewTestUsers() map[string]*gtsmodel.User {
ConfirmedAt: TimeMustParse("2022-05-24T13:12:00Z"), ConfirmedAt: TimeMustParse("2022-05-24T13:12:00Z"),
ConfirmationSentAt: TimeMustParse("2022-05-23T13:12:00Z"), ConfirmationSentAt: TimeMustParse("2022-05-23T13:12:00Z"),
UnconfirmedEmail: "", UnconfirmedEmail: "",
Moderator: false, Moderator: FalseBool(),
Admin: false, Admin: FalseBool(),
Disabled: false, Disabled: FalseBool(),
Approved: true, Approved: TrueBool(),
ResetPasswordToken: "", ResetPasswordToken: "",
ResetPasswordSentAt: time.Time{}, ResetPasswordSentAt: time.Time{},
}, },
@ -295,16 +307,16 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
DisplayName: "", DisplayName: "",
Fields: []gtsmodel.Field{}, Fields: []gtsmodel.Field{},
Note: "", Note: "",
Memorial: false, Memorial: FalseBool(),
MovedToAccountID: "", MovedToAccountID: "",
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"), CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
Bot: false, Bot: FalseBool(),
Reason: "hi, please let me in! I'm looking for somewhere neato bombeato to hang out.", Reason: "hi, please let me in! I'm looking for somewhere neato bombeato to hang out.",
Locked: false, Locked: FalseBool(),
Discoverable: false, Discoverable: FalseBool(),
Privacy: gtsmodel.VisibilityPublic, Privacy: gtsmodel.VisibilityPublic,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
URI: "http://localhost:8080/users/weed_lord420", URI: "http://localhost:8080/users/weed_lord420",
URL: "http://localhost:8080/@weed_lord420", URL: "http://localhost:8080/@weed_lord420",
@ -322,7 +334,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
SensitizedAt: time.Time{}, SensitizedAt: time.Time{},
SilencedAt: time.Time{}, SilencedAt: time.Time{},
SuspendedAt: time.Time{}, SuspendedAt: time.Time{},
HideCollections: false, HideCollections: FalseBool(),
SuspensionOrigin: "", SuspensionOrigin: "",
}, },
"admin_account": { "admin_account": {
@ -334,16 +346,16 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
Fields: []gtsmodel.Field{}, Fields: []gtsmodel.Field{},
Note: "", Note: "",
NoteRaw: "", NoteRaw: "",
Memorial: false, Memorial: FalseBool(),
MovedToAccountID: "", MovedToAccountID: "",
CreatedAt: TimeMustParse("2022-05-17T13:10:59Z"), CreatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
UpdatedAt: TimeMustParse("2022-05-17T13:10:59Z"), UpdatedAt: TimeMustParse("2022-05-17T13:10:59Z"),
Bot: false, Bot: FalseBool(),
Reason: "", Reason: "",
Locked: false, Locked: FalseBool(),
Discoverable: true, Discoverable: TrueBool(),
Privacy: gtsmodel.VisibilityPublic, Privacy: gtsmodel.VisibilityPublic,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
URI: "http://localhost:8080/users/admin", URI: "http://localhost:8080/users/admin",
URL: "http://localhost:8080/@admin", URL: "http://localhost:8080/@admin",
@ -361,7 +373,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
SensitizedAt: time.Time{}, SensitizedAt: time.Time{},
SilencedAt: time.Time{}, SilencedAt: time.Time{},
SuspendedAt: time.Time{}, SuspendedAt: time.Time{},
HideCollections: false, HideCollections: FalseBool(),
SuspensionOrigin: "", SuspensionOrigin: "",
}, },
"local_account_1": { "local_account_1": {
@ -373,16 +385,16 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
Fields: []gtsmodel.Field{}, Fields: []gtsmodel.Field{},
Note: "<p>hey yo this is my profile!</p>", Note: "<p>hey yo this is my profile!</p>",
NoteRaw: "hey yo this is my profile!", NoteRaw: "hey yo this is my profile!",
Memorial: false, Memorial: FalseBool(),
MovedToAccountID: "", MovedToAccountID: "",
CreatedAt: TimeMustParse("2022-05-20T11:09:18Z"), CreatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
UpdatedAt: TimeMustParse("2022-05-20T11:09:18Z"), UpdatedAt: TimeMustParse("2022-05-20T11:09:18Z"),
Bot: false, Bot: FalseBool(),
Reason: "I wanna be on this damned webbed site so bad! Please! Wow", Reason: "I wanna be on this damned webbed site so bad! Please! Wow",
Locked: false, Locked: FalseBool(),
Discoverable: true, Discoverable: TrueBool(),
Privacy: gtsmodel.VisibilityPublic, Privacy: gtsmodel.VisibilityPublic,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
URI: "http://localhost:8080/users/the_mighty_zork", URI: "http://localhost:8080/users/the_mighty_zork",
URL: "http://localhost:8080/@the_mighty_zork", URL: "http://localhost:8080/@the_mighty_zork",
@ -400,7 +412,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
SensitizedAt: time.Time{}, SensitizedAt: time.Time{},
SilencedAt: time.Time{}, SilencedAt: time.Time{},
SuspendedAt: time.Time{}, SuspendedAt: time.Time{},
HideCollections: false, HideCollections: FalseBool(),
SuspensionOrigin: "", SuspensionOrigin: "",
}, },
"local_account_2": { "local_account_2": {
@ -412,16 +424,16 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
Fields: []gtsmodel.Field{}, Fields: []gtsmodel.Field{},
Note: "<p>i post about things that concern me</p>", Note: "<p>i post about things that concern me</p>",
NoteRaw: "i post about things that concern me", NoteRaw: "i post about things that concern me",
Memorial: false, Memorial: FalseBool(),
MovedToAccountID: "", MovedToAccountID: "",
CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"), CreatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
Bot: false, Bot: FalseBool(),
Reason: "", Reason: "",
Locked: true, Locked: TrueBool(),
Discoverable: false, Discoverable: FalseBool(),
Privacy: gtsmodel.VisibilityFollowersOnly, Privacy: gtsmodel.VisibilityFollowersOnly,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
URI: "http://localhost:8080/users/1happyturtle", URI: "http://localhost:8080/users/1happyturtle",
URL: "http://localhost:8080/@1happyturtle", URL: "http://localhost:8080/@1happyturtle",
@ -439,7 +451,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
SensitizedAt: time.Time{}, SensitizedAt: time.Time{},
SilencedAt: time.Time{}, SilencedAt: time.Time{},
SuspendedAt: time.Time{}, SuspendedAt: time.Time{},
HideCollections: false, HideCollections: FalseBool(),
SuspensionOrigin: "", SuspensionOrigin: "",
}, },
"remote_account_1": { "remote_account_1": {
@ -449,14 +461,14 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
DisplayName: "big gerald", DisplayName: "big gerald",
Fields: []gtsmodel.Field{}, Fields: []gtsmodel.Field{},
Note: "i post about like, i dunno, stuff, or whatever!!!!", Note: "i post about like, i dunno, stuff, or whatever!!!!",
Memorial: false, Memorial: FalseBool(),
MovedToAccountID: "", MovedToAccountID: "",
CreatedAt: TimeMustParse("2021-09-26T12:52:36+02:00"), CreatedAt: TimeMustParse("2021-09-26T12:52:36+02:00"),
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
Bot: false, Bot: FalseBool(),
Locked: false, Locked: FalseBool(),
Discoverable: true, Discoverable: TrueBool(),
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
URI: "http://fossbros-anonymous.io/users/foss_satan", URI: "http://fossbros-anonymous.io/users/foss_satan",
URL: "http://fossbros-anonymous.io/@foss_satan", URL: "http://fossbros-anonymous.io/@foss_satan",
@ -474,7 +486,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
SensitizedAt: time.Time{}, SensitizedAt: time.Time{},
SilencedAt: time.Time{}, SilencedAt: time.Time{},
SuspendedAt: time.Time{}, SuspendedAt: time.Time{},
HideCollections: false, HideCollections: FalseBool(),
SuspensionOrigin: "", SuspensionOrigin: "",
}, },
"remote_account_2": { "remote_account_2": {
@ -484,14 +496,14 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
DisplayName: "some user", DisplayName: "some user",
Fields: []gtsmodel.Field{}, Fields: []gtsmodel.Field{},
Note: "i'm a real son of a gun", Note: "i'm a real son of a gun",
Memorial: false, Memorial: FalseBool(),
MovedToAccountID: "", MovedToAccountID: "",
CreatedAt: TimeMustParse("2020-08-10T14:13:28+02:00"), CreatedAt: TimeMustParse("2020-08-10T14:13:28+02:00"),
UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"), UpdatedAt: TimeMustParse("2022-06-04T13:12:00Z"),
Bot: false, Bot: FalseBool(),
Locked: true, Locked: TrueBool(),
Discoverable: true, Discoverable: TrueBool(),
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
URI: "http://example.org/users/some_user", URI: "http://example.org/users/some_user",
URL: "http://example.org/@some_user", URL: "http://example.org/@some_user",
@ -509,7 +521,7 @@ func NewTestAccounts() map[string]*gtsmodel.Account {
SensitizedAt: time.Time{}, SensitizedAt: time.Time{},
SilencedAt: time.Time{}, SilencedAt: time.Time{},
SuspendedAt: time.Time{}, SuspendedAt: time.Time{},
HideCollections: false, HideCollections: FalseBool(),
SuspensionOrigin: "", SuspensionOrigin: "",
}, },
} }
@ -607,9 +619,9 @@ func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
URL: "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpeg", URL: "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.jpeg",
RemoteURL: "", RemoteURL: "",
}, },
Avatar: false, Avatar: FalseBool(),
Header: false, Header: FalseBool(),
Cached: true, Cached: TrueBool(),
}, },
"local_account_1_status_4_attachment_1": { "local_account_1_status_4_attachment_1": {
ID: "01F8MH7TDVANYKWVE8VVKFPJTJ", ID: "01F8MH7TDVANYKWVE8VVKFPJTJ",
@ -656,9 +668,9 @@ func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH7TDVANYKWVE8VVKFPJTJ.jpeg", URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH7TDVANYKWVE8VVKFPJTJ.jpeg",
RemoteURL: "", RemoteURL: "",
}, },
Avatar: false, Avatar: FalseBool(),
Header: false, Header: FalseBool(),
Cached: true, Cached: TrueBool(),
}, },
"local_account_1_unattached_1": { "local_account_1_unattached_1": {
ID: "01F8MH8RMYQ6MSNY3JM2XT1CQ5", ID: "01F8MH8RMYQ6MSNY3JM2XT1CQ5",
@ -705,9 +717,9 @@ func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpeg", URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01F8MH8RMYQ6MSNY3JM2XT1CQ5.jpeg",
RemoteURL: "", RemoteURL: "",
}, },
Avatar: false, Avatar: FalseBool(),
Header: false, Header: FalseBool(),
Cached: true, Cached: TrueBool(),
}, },
"local_account_1_avatar": { "local_account_1_avatar": {
ID: "01F8MH58A357CV5K7R7TJMSH6S", ID: "01F8MH58A357CV5K7R7TJMSH6S",
@ -754,9 +766,9 @@ func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpeg", URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.jpeg",
RemoteURL: "", RemoteURL: "",
}, },
Avatar: true, Avatar: TrueBool(),
Header: false, Header: FalseBool(),
Cached: true, Cached: TrueBool(),
}, },
"local_account_1_header": { "local_account_1_header": {
ID: "01PFPMWK2FF0D9WMHEJHR07C3Q", ID: "01PFPMWK2FF0D9WMHEJHR07C3Q",
@ -803,9 +815,9 @@ func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpeg", URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.jpeg",
RemoteURL: "", RemoteURL: "",
}, },
Avatar: false, Avatar: FalseBool(),
Header: true, Header: TrueBool(),
Cached: true, Cached: TrueBool(),
}, },
"remote_account_1_status_1_attachment_1": { "remote_account_1_status_1_attachment_1": {
ID: "01FVW7RXPQ8YJHTEXYPE7Q8ZY0", ID: "01FVW7RXPQ8YJHTEXYPE7Q8ZY0",
@ -852,9 +864,9 @@ func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpeg", URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpeg",
RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpeg", RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpeg",
}, },
Avatar: false, Avatar: FalseBool(),
Header: false, Header: FalseBool(),
Cached: true, Cached: TrueBool(),
}, },
"remote_account_1_status_1_attachment_2": { "remote_account_1_status_1_attachment_2": {
ID: "01FVW7RXPQ8YJHTEXYPE7Q8ZY1", ID: "01FVW7RXPQ8YJHTEXYPE7Q8ZY1",
@ -901,9 +913,9 @@ func NewTestAttachments() map[string]*gtsmodel.MediaAttachment {
URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpeg", URL: "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/attachment/small/01FVW7RXPQ8YJHTEXYPE7Q8ZY0.jpeg",
RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpeg", RemoteURL: "http://fossbros-anonymous.io/attachments/small/a499f55b-2d1e-4acd-98d2-1ac2ba6d79b9.jpeg",
}, },
Avatar: false, Avatar: FalseBool(),
Header: false, Header: FalseBool(),
Cached: true, Cached: TrueBool(),
}, },
} }
} }
@ -928,9 +940,9 @@ func NewTestEmojis() map[string]*gtsmodel.Emoji {
ImageFileSize: 36702, ImageFileSize: 36702,
ImageStaticFileSize: 10413, ImageStaticFileSize: 10413,
ImageUpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), ImageUpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"),
Disabled: false, Disabled: FalseBool(),
URI: "http://localhost:8080/emoji/01F8MH9H8E4VG3KDYJR9EGPXCQ", URI: "http://localhost:8080/emoji/01F8MH9H8E4VG3KDYJR9EGPXCQ",
VisibleInPicker: true, VisibleInPicker: TrueBool(),
CategoryID: "", CategoryID: "",
}, },
} }
@ -978,7 +990,7 @@ func NewTestDomainBlocks() map[string]*gtsmodel.DomainBlock {
CreatedByAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", CreatedByAccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
PrivateComment: "i blocked this domain because they keep replying with pushy + unwarranted linux advice", PrivateComment: "i blocked this domain because they keep replying with pushy + unwarranted linux advice",
PublicComment: "reply-guying to tech posts", PublicComment: "reply-guying to tech posts",
Obfuscate: false, Obfuscate: FalseBool(),
}, },
} }
} }
@ -1044,20 +1056,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
EmojiIDs: []string{"01F8MH9H8E4VG3KDYJR9EGPXCQ"}, EmojiIDs: []string{"01F8MH9H8E4VG3KDYJR9EGPXCQ"},
CreatedAt: TimeMustParse("2021-10-20T11:36:45Z"), CreatedAt: TimeMustParse("2021-10-20T11:36:45Z"),
UpdatedAt: TimeMustParse("2021-10-20T11:36:45Z"), UpdatedAt: TimeMustParse("2021-10-20T11:36:45Z"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/admin", AccountURI: "http://localhost:8080/users/admin",
AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", AccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"admin_account_status_2": { "admin_account_status_2": {
@ -1067,20 +1080,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "🐕🐕🐕🐕🐕", Content: "🐕🐕🐕🐕🐕",
CreatedAt: TimeMustParse("2021-10-20T12:36:45Z"), CreatedAt: TimeMustParse("2021-10-20T12:36:45Z"),
UpdatedAt: TimeMustParse("2021-10-20T12:36:45Z"), UpdatedAt: TimeMustParse("2021-10-20T12:36:45Z"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/admin", AccountURI: "http://localhost:8080/users/admin",
AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", AccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "open to see some puppies", ContentWarning: "open to see some puppies",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: true, Sensitive: TrueBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"admin_account_status_3": { "admin_account_status_3": {
@ -1090,7 +1104,7 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "hi @the_mighty_zork welcome to the instance!", Content: "hi @the_mighty_zork welcome to the instance!",
CreatedAt: TimeMustParse("2021-11-20T13:32:16Z"), CreatedAt: TimeMustParse("2021-11-20T13:32:16Z"),
UpdatedAt: TimeMustParse("2021-11-20T13:32:16Z"), UpdatedAt: TimeMustParse("2021-11-20T13:32:16Z"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/admin", AccountURI: "http://localhost:8080/users/admin",
MentionIDs: []string{"01FF26A6BGEKCZFWNEHXB2ZZ6M"}, MentionIDs: []string{"01FF26A6BGEKCZFWNEHXB2ZZ6M"},
AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", AccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
@ -1099,13 +1113,14 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
InReplyToURI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY", InReplyToURI: "http://localhost:8080/users/the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY",
BoostOfID: "", BoostOfID: "",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"admin_account_status_4": { "admin_account_status_4": {
@ -1115,7 +1130,7 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "hello everyone!", Content: "hello everyone!",
CreatedAt: TimeMustParse("2021-10-20T12:41:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:41:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:41:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:41:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/admin", AccountURI: "http://localhost:8080/users/admin",
AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", AccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
InReplyToID: "", InReplyToID: "",
@ -1125,13 +1140,14 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
BoostOfAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", BoostOfAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
ContentWarning: "introduction post", ContentWarning: "introduction post",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: true, Sensitive: TrueBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F", CreatedWithApplicationID: "01F8MGXQRHYF5QPMTMXP78QC2F",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_1_status_1": { "local_account_1_status_1": {
@ -1141,20 +1157,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "hello everyone!", Content: "hello everyone!",
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/the_mighty_zork", AccountURI: "http://localhost:8080/users/the_mighty_zork",
AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "introduction post", ContentWarning: "introduction post",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: true, Sensitive: TrueBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_1_status_2": { "local_account_1_status_2": {
@ -1164,20 +1181,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "this is an unlocked local-only post that shouldn't federate, but it's still boostable, replyable, and likeable", Content: "this is an unlocked local-only post that shouldn't federate, but it's still boostable, replyable, and likeable",
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/the_mighty_zork", AccountURI: "http://localhost:8080/users/the_mighty_zork",
AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityUnlocked, Visibility: gtsmodel.VisibilityUnlocked,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG",
Federated: false, Pinned: FalseBool(),
Boostable: true, Federated: FalseBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_1_status_3": { "local_account_1_status_3": {
@ -1187,20 +1205,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "this is a very personal post that I don't want anyone to interact with at all, and i only want mutuals to see it", Content: "this is a very personal post that I don't want anyone to interact with at all, and i only want mutuals to see it",
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/the_mighty_zork", AccountURI: "http://localhost:8080/users/the_mighty_zork",
AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "test: you shouldn't be able to interact with this post in any way", ContentWarning: "test: you shouldn't be able to interact with this post in any way",
Visibility: gtsmodel.VisibilityMutualsOnly, Visibility: gtsmodel.VisibilityMutualsOnly,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG",
Federated: true, Pinned: FalseBool(),
Boostable: false, Federated: TrueBool(),
Replyable: false, Boostable: FalseBool(),
Likeable: false, Replyable: FalseBool(),
Likeable: FalseBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_1_status_4": { "local_account_1_status_4": {
@ -1211,20 +1230,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
AttachmentIDs: []string{"01F8MH7TDVANYKWVE8VVKFPJTJ"}, AttachmentIDs: []string{"01F8MH7TDVANYKWVE8VVKFPJTJ"},
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/the_mighty_zork", AccountURI: "http://localhost:8080/users/the_mighty_zork",
AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "eye contact, trent reznor gif", ContentWarning: "eye contact, trent reznor gif",
Visibility: gtsmodel.VisibilityMutualsOnly, Visibility: gtsmodel.VisibilityMutualsOnly,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_1_status_5": { "local_account_1_status_5": {
@ -1235,20 +1255,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
AttachmentIDs: []string{}, AttachmentIDs: []string{},
CreatedAt: TimeMustParse("2022-05-20T11:37:55Z"), CreatedAt: TimeMustParse("2022-05-20T11:37:55Z"),
UpdatedAt: TimeMustParse("2022-05-20T11:37:55Z"), UpdatedAt: TimeMustParse("2022-05-20T11:37:55Z"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/the_mighty_zork", AccountURI: "http://localhost:8080/users/the_mighty_zork",
AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityFollowersOnly, Visibility: gtsmodel.VisibilityFollowersOnly,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG", CreatedWithApplicationID: "01F8MGY43H3N2C8EWPR2FPYEXG",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_2_status_1": { "local_account_2_status_1": {
@ -1258,20 +1279,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "🐢 hi everyone i post about turtles 🐢", Content: "🐢 hi everyone i post about turtles 🐢",
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/1happyturtle", AccountURI: "http://localhost:8080/users/1happyturtle",
AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "introduction post", ContentWarning: "introduction post",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: true, Sensitive: TrueBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_2_status_2": { "local_account_2_status_2": {
@ -1281,20 +1303,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "🐢 this one is federated, likeable, and boostable but not replyable 🐢", Content: "🐢 this one is federated, likeable, and boostable but not replyable 🐢",
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/1happyturtle", AccountURI: "http://localhost:8080/users/1happyturtle",
AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: true, Sensitive: TrueBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: false, Boostable: TrueBool(),
Likeable: true, Replyable: FalseBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_2_status_3": { "local_account_2_status_3": {
@ -1304,20 +1327,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "🐢 i don't mind people sharing this one but I don't want likes or replies to it because cba🐢", Content: "🐢 i don't mind people sharing this one but I don't want likes or replies to it because cba🐢",
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/1happyturtle", AccountURI: "http://localhost:8080/users/1happyturtle",
AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "you won't be able to like or reply to this", ContentWarning: "you won't be able to like or reply to this",
Visibility: gtsmodel.VisibilityUnlocked, Visibility: gtsmodel.VisibilityUnlocked,
Sensitive: true, Sensitive: TrueBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: false, Boostable: TrueBool(),
Likeable: false, Replyable: FalseBool(),
Likeable: FalseBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_2_status_4": { "local_account_2_status_4": {
@ -1327,20 +1351,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "🐢 this is a public status but I want it local only and not boostable 🐢", Content: "🐢 this is a public status but I want it local only and not boostable 🐢",
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/1happyturtle", AccountURI: "http://localhost:8080/users/1happyturtle",
AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: true, Sensitive: TrueBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ",
Federated: false, Pinned: FalseBool(),
Boostable: false, Federated: FalseBool(),
Replyable: true, Boostable: FalseBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
@ -1351,7 +1376,7 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "🐢 @the_mighty_zork hi zork! 🐢", Content: "🐢 @the_mighty_zork hi zork! 🐢",
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/1happyturtle", AccountURI: "http://localhost:8080/users/1happyturtle",
MentionIDs: []string{"01FDF2HM2NF6FSRZCDEDV451CN"}, MentionIDs: []string{"01FDF2HM2NF6FSRZCDEDV451CN"},
AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
@ -1361,13 +1386,14 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityPublic, Visibility: gtsmodel.VisibilityPublic,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_2_status_6": { "local_account_2_status_6": {
@ -1377,7 +1403,7 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
Content: "🐢 @the_mighty_zork hi zork, this is a direct message, shhhhhh! 🐢", Content: "🐢 @the_mighty_zork hi zork, this is a direct message, shhhhhh! 🐢",
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/1happyturtle", AccountURI: "http://localhost:8080/users/1happyturtle",
MentionIDs: []string{"01FDF2HM2NF6FSRZCDEDV451CN"}, MentionIDs: []string{"01FDF2HM2NF6FSRZCDEDV451CN"},
AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
@ -1387,13 +1413,14 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityDirect, Visibility: gtsmodel.VisibilityDirect,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"local_account_2_status_7": { "local_account_2_status_7": {
@ -1404,20 +1431,21 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
AttachmentIDs: []string{}, AttachmentIDs: []string{},
CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-10-20T12:40:37+02:00"),
Local: true, Local: TrueBool(),
AccountURI: "http://localhost:8080/users/1happyturtle", AccountURI: "http://localhost:8080/users/1happyturtle",
AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
InReplyToID: "", InReplyToID: "",
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityFollowersOnly, Visibility: gtsmodel.VisibilityFollowersOnly,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ", CreatedWithApplicationID: "01F8MGYG9E893WRHW0TAEXR8GJ",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
"remote_account_1_status_1": { "remote_account_1_status_1": {
@ -1428,7 +1456,7 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
AttachmentIDs: []string{"01FVW7RXPQ8YJHTEXYPE7Q8ZY0"}, AttachmentIDs: []string{"01FVW7RXPQ8YJHTEXYPE7Q8ZY0"},
CreatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), CreatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"),
UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"), UpdatedAt: TimeMustParse("2021-09-20T12:40:37+02:00"),
Local: false, Local: FalseBool(),
AccountURI: "http://fossbros-anonymous.io/users/foss_satan", AccountURI: "http://fossbros-anonymous.io/users/foss_satan",
MentionIDs: []string{}, MentionIDs: []string{},
AccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX", AccountID: "01F8MH5ZK5VRH73AKHQM6Y9VNX",
@ -1438,13 +1466,14 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
BoostOfID: "", BoostOfID: "",
ContentWarning: "", ContentWarning: "",
Visibility: gtsmodel.VisibilityUnlocked, Visibility: gtsmodel.VisibilityUnlocked,
Sensitive: false, Sensitive: FalseBool(),
Language: "en", Language: "en",
CreatedWithApplicationID: "", CreatedWithApplicationID: "",
Federated: true, Pinned: FalseBool(),
Boostable: true, Federated: TrueBool(),
Replyable: true, Boostable: TrueBool(),
Likeable: true, Replyable: TrueBool(),
Likeable: TrueBool(),
ActivityStreamsType: ap.ObjectNote, ActivityStreamsType: ap.ObjectNote,
}, },
} }
@ -1460,8 +1489,8 @@ func NewTestTags() map[string]*gtsmodel.Tag {
FirstSeenFromAccountID: "", FirstSeenFromAccountID: "",
CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
Useable: true, Useable: TrueBool(),
Listable: true, Listable: TrueBool(),
LastStatusAt: TimeMustParse("2022-05-14T13:21:09+02:00"), LastStatusAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
}, },
"Hashtag": { "Hashtag": {
@ -1471,8 +1500,8 @@ func NewTestTags() map[string]*gtsmodel.Tag {
FirstSeenFromAccountID: "", FirstSeenFromAccountID: "",
CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
Useable: true, Useable: TrueBool(),
Listable: true, Listable: TrueBool(),
LastStatusAt: TimeMustParse("2022-05-14T13:21:09+02:00"), LastStatusAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
}, },
} }
@ -1564,7 +1593,7 @@ func NewTestNotifications() map[string]*gtsmodel.Notification {
TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
OriginAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", OriginAccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
StatusID: "01F8MHAMCHF6Y650WCRSCP4WMY", StatusID: "01F8MHAMCHF6Y650WCRSCP4WMY",
Read: false, Read: FalseBool(),
}, },
} }
} }
@ -1578,9 +1607,9 @@ func NewTestFollows() map[string]*gtsmodel.Follow {
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF", TargetAccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
ShowReblogs: true, ShowReblogs: TrueBool(),
URI: "http://localhost:8080/users/the_mighty_zork/follow/01F8PY8RHWRQZV038T4E8T9YK8", URI: "http://localhost:8080/users/the_mighty_zork/follow/01F8PY8RHWRQZV038T4E8T9YK8",
Notify: false, Notify: FalseBool(),
}, },
"local_account_1_local_account_2": { "local_account_1_local_account_2": {
ID: "01F8PYDCE8XE23GRE5DPZJDZDP", ID: "01F8PYDCE8XE23GRE5DPZJDZDP",
@ -1588,9 +1617,9 @@ func NewTestFollows() map[string]*gtsmodel.Follow {
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", AccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", TargetAccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
ShowReblogs: true, ShowReblogs: TrueBool(),
URI: "http://localhost:8080/users/the_mighty_zork/follow/01F8PYDCE8XE23GRE5DPZJDZDP", URI: "http://localhost:8080/users/the_mighty_zork/follow/01F8PYDCE8XE23GRE5DPZJDZDP",
Notify: false, Notify: FalseBool(),
}, },
"local_account_2_local_account_1": { "local_account_2_local_account_1": {
ID: "01G1TK1RS4K3E0MSFTXBFWAH9Q", ID: "01G1TK1RS4K3E0MSFTXBFWAH9Q",
@ -1598,9 +1627,9 @@ func NewTestFollows() map[string]*gtsmodel.Follow {
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF", AccountID: "01F8MH5NBDF2MV7CTC4Q5128HF",
TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
ShowReblogs: true, ShowReblogs: TrueBool(),
URI: "http://localhost:8080/users/1happyturtle/follow/01F8PYDCE8XE23GRE5DPZJDZDP", URI: "http://localhost:8080/users/1happyturtle/follow/01F8PYDCE8XE23GRE5DPZJDZDP",
Notify: false, Notify: FalseBool(),
}, },
"admin_account_local_account_1": { "admin_account_local_account_1": {
ID: "01G1TK3PQKFW1BQZ9WVYRTFECK", ID: "01G1TK3PQKFW1BQZ9WVYRTFECK",
@ -1608,9 +1637,9 @@ func NewTestFollows() map[string]*gtsmodel.Follow {
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"), UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
AccountID: "01F8MH17FWEB39HZJ76B6VXSKF", AccountID: "01F8MH17FWEB39HZJ76B6VXSKF",
TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF", TargetAccountID: "01F8MH1H7YV1Z7D2C8K2730QBF",
ShowReblogs: true, ShowReblogs: TrueBool(),
URI: "http://localhost:8080/users/admin/follow/01G1TK3PQKFW1BQZ9WVYRTFECK", URI: "http://localhost:8080/users/admin/follow/01G1TK3PQKFW1BQZ9WVYRTFECK",
Notify: false, Notify: FalseBool(),
}, },
} }
} }

View file

@ -1,18 +1,87 @@
# [](https://github.com/uptrace/bun/compare/v1.1.2...v) (2022-03-29) ## [1.1.7](https://github.com/uptrace/bun/compare/v1.1.6...v1.1.7) (2022-07-29)
### Bug Fixes ### Bug Fixes
* fix panic message when has-many encounter an error ([cfd2747](https://github.com/uptrace/bun/commit/cfd27475fac89a1c8cf798bfa64898bd77bbba79)) * change ScanAndCount without a limit to select all rows ([de5c570](https://github.com/uptrace/bun/commit/de5c5704166563aea41a82f7863f2db88ff108e2))
* **migrate:** change rollback to match migrate behavior ([df5af9c](https://github.com/uptrace/bun/commit/df5af9c9cbdf54ce243e037bbb2c7b154f8422b3))
## [1.1.6](https://github.com/uptrace/bun/compare/v1.1.5...v1.1.6) (2022-07-10)
### Bug Fixes
* bunotel add set attributes to query metrics ([dae82cc](https://github.com/uptrace/bun/commit/dae82cc0e3af49be1e474027b55c34364676985d))
* **db.ScanRows:** ensure rows.Close is called ([9ffbc6a](https://github.com/uptrace/bun/commit/9ffbc6a46e24b908742b6973f33ef8e5b17cc12b))
* merge apply ([3081849](https://github.com/uptrace/bun/commit/30818499eacddd3b1a3e749091ba6a1468125641))
* **migrate:** close conn/tx on error ([7b168ea](https://github.com/uptrace/bun/commit/7b168eabfe0f844bcbf8dc89629d04c385b9f58c))
* **migrate:** type Migration should be used as a value rather than a pointer ([fb43935](https://github.com/uptrace/bun/commit/fb4393582b49fe528800a66aac5fb1c9a6033048))
* **migrate:** type MigrationGroup should be used as a value rather than a pointer ([649da1b](https://github.com/uptrace/bun/commit/649da1b3c158060add9b61b32c289260daafa65a))
* mssql cursor pagination ([#589](https://github.com/uptrace/bun/issues/589)) ([b34ec97](https://github.com/uptrace/bun/commit/b34ec97ddda95629f73762721d60fd3e00e7e99f))
### Features ### Features
* added QueryBuilder interface for SelectQuery, UpdateQuery, DeleteQuery ([#499](https://github.com/uptrace/bun/issues/499)) ([59fef48](https://github.com/uptrace/bun/commit/59fef48f6b3ec7f32bdda779b6693c333ff1dfdb)) * "skipupdate" model field tag ([#565](https://github.com/uptrace/bun/issues/565)) ([9288294](https://github.com/uptrace/bun/commit/928829482c718a0c215aa4f4adfa6f3fb3ed4302))
* add pgdriver write error to log ([5ddda3d](https://github.com/uptrace/bun/commit/5ddda3de31cd08ceee4bdea64ceae8d15eace07b))
* add query string representation ([520da7e](https://github.com/uptrace/bun/commit/520da7e1d6dbf7b06846f6b39a7f99e8753c1466))
* add relation condition with tag ([fe5bbf6](https://github.com/uptrace/bun/commit/fe5bbf64f33d25b310e5510ece7d705b9eb3bfea))
* add support for ON UPDATE and ON DELETE rules on belongs-to relationships from struct tags ([#533](https://github.com/uptrace/bun/issues/533)) ([a327b2a](https://github.com/uptrace/bun/commit/a327b2ae216abb55a705626296c0cdbf8d648697))
* add tx methods to IDB ([#587](https://github.com/uptrace/bun/issues/587)) ([feab313](https://github.com/uptrace/bun/commit/feab313c0358200b6e270ac70f4551b011ab5276))
* added raw query calls ([#596](https://github.com/uptrace/bun/issues/596)) ([127644d](https://github.com/uptrace/bun/commit/127644d2eea443736fbd6bed3417595d439e4639))
* **bunotel:** add option to enable formatting of queries ([#547](https://github.com/uptrace/bun/issues/547)) ([b9c768c](https://github.com/uptrace/bun/commit/b9c768cec3b5dea36c3c9c344d1e76e0ffad1369))
* **config.go:** add sslrootcert support to DSN parameters ([3bd5d69](https://github.com/uptrace/bun/commit/3bd5d692d7df4f30d07b835d6a46fc7af382489a))
* create an extra module for newrelic ([#599](https://github.com/uptrace/bun/issues/599)) ([6c676ce](https://github.com/uptrace/bun/commit/6c676ce13f05fe763471fbec2d5a2db48bc88650))
* **migrate:** add WithMarkAppliedOnSuccess ([31b2cc4](https://github.com/uptrace/bun/commit/31b2cc4f5ccd794a436d081073d4974835d3780d))
* **pgdialect:** add hstore support ([66b44f7](https://github.com/uptrace/bun/commit/66b44f7c0edc205927fb8be96aaf263b31828fa1))
* **pgdialect:** add identity support ([646251e](https://github.com/uptrace/bun/commit/646251ec02a1e2ec717e907e6f128d8b51f17c6d))
* **pgdriver:** expose pgdriver.ParseTime ([405a7d7](https://github.com/uptrace/bun/commit/405a7d78d8f60cf27e8f175deaf95db5877d84be))
## [1.1.5](https://github.com/uptrace/bun/compare/v1.1.4...v1.1.5) (2022-05-12)
### Bug Fixes
* **driver/sqliteshim:** make it work with recent version of modernc sqlite ([2360584](https://github.com/uptrace/bun/commit/23605846c20684e39bf1eaac50a2147a1b68a729))
## [1.1.4](https://github.com/uptrace/bun/compare/v1.1.3...v1.1.4) (2022-04-20)
### Bug Fixes
* automatically set nullzero when there is default:value option ([72c44ae](https://github.com/uptrace/bun/commit/72c44aebbeec3a83ed97ea25a3262174d744df65))
* fix ForceDelete on live/undeleted rows ([1a33250](https://github.com/uptrace/bun/commit/1a33250f27f00e752a735ce10311ac95dcb0c968))
* fix OmitZero and value overriding ([087ea07](https://github.com/uptrace/bun/commit/087ea0730551f1e841bacb6ad2fa3afd512a1df8))
* rename Query to QueryBuilder ([98d111b](https://github.com/uptrace/bun/commit/98d111b7cc00fa61b6b2cec147f43285f4baadb4))
### Features
* add ApplyQueryBuilder ([582eca0](https://github.com/uptrace/bun/commit/582eca09cf2b59e67c2e4a2ad24f1a74cb53addd))
* **config.go:** add connect_timeout to DSN parsable params ([998b04d](https://github.com/uptrace/bun/commit/998b04d51a9a4f182ac3458f90db8dbf9185c4ba)), closes [#505](https://github.com/uptrace/bun/issues/505)
# [1.1.3](https://github.com/uptrace/bun/compare/v1.1.2...v) (2022-03-29)
### Bug Fixes
- fix panic message when has-many encounter an error
([cfd2747](https://github.com/uptrace/bun/commit/cfd27475fac89a1c8cf798bfa64898bd77bbba79))
- **migrate:** change rollback to match migrate behavior
([df5af9c](https://github.com/uptrace/bun/commit/df5af9c9cbdf54ce243e037bbb2c7b154f8422b3))
### Features
- added QueryBuilder interface for SelectQuery, UpdateQuery, DeleteQuery
([#499](https://github.com/uptrace/bun/issues/499))
([59fef48](https://github.com/uptrace/bun/commit/59fef48f6b3ec7f32bdda779b6693c333ff1dfdb))
# [1.1.2](https://github.com/uptrace/bun/compare/v1.1.2...v) (2022-03-22) # [1.1.2](https://github.com/uptrace/bun/compare/v1.1.2...v) (2022-03-22)
### Bug Fixes ### Bug Fixes

View file

@ -1,13 +1,14 @@
# SQL-first Go ORM for PostgreSQL, MySQL, MSSQL, and SQLite # SQL-first Golang ORM for PostgreSQL, MySQL, MSSQL, and SQLite
[![build workflow](https://github.com/uptrace/bun/actions/workflows/build.yml/badge.svg)](https://github.com/uptrace/bun/actions) [![build workflow](https://github.com/uptrace/bun/actions/workflows/build.yml/badge.svg)](https://github.com/uptrace/bun/actions)
[![PkgGoDev](https://pkg.go.dev/badge/github.com/uptrace/bun)](https://pkg.go.dev/github.com/uptrace/bun) [![PkgGoDev](https://pkg.go.dev/badge/github.com/uptrace/bun)](https://pkg.go.dev/github.com/uptrace/bun)
[![Documentation](https://img.shields.io/badge/bun-documentation-informational)](https://bun.uptrace.dev/) [![Documentation](https://img.shields.io/badge/bun-documentation-informational)](https://bun.uptrace.dev/)
[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj) [![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj)
Bun is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace). Uptrace > Bun is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace). Uptrace
is an open source and blazingly fast **distributed tracing** backend powered by OpenTelemetry and > is an open source and blazingly fast
ClickHouse. Give it a star as well! > [distributed tracing tool](https://get.uptrace.dev/compare/distributed-tracing-tools.html) powered
> by OpenTelemetry and ClickHouse. Give it a star as well!
## Features ## Features
@ -26,7 +27,7 @@ ClickHouse. Give it a star as well!
Resources: Resources:
- [**Get started**](https://bun.uptrace.dev/guide/getting-started.html) - [**Get started**](https://bun.uptrace.dev/guide/golang-orm.html)
- [Examples](https://github.com/uptrace/bun/tree/master/example) - [Examples](https://github.com/uptrace/bun/tree/master/example)
- [Discussions](https://github.com/uptrace/bun/discussions) - [Discussions](https://github.com/uptrace/bun/discussions)
- [Chat](https://discord.gg/rWtp5Aj) - [Chat](https://discord.gg/rWtp5Aj)
@ -253,7 +254,7 @@ topRegions := db.NewSelect().
TableExpr("regional_sales"). TableExpr("regional_sales").
Where("total_sales > (SELECT SUM(total_sales) / 10 FROM regional_sales)") Where("total_sales > (SELECT SUM(total_sales) / 10 FROM regional_sales)")
var items map[string]interface{} var items []map[string]interface{}
err := db.NewSelect(). err := db.NewSelect().
With("regional_sales", regionalSales). With("regional_sales", regionalSales).
With("top_regions", topRegions). With("top_regions", topRegions).
@ -301,9 +302,15 @@ if err := db.NewSelect().Model(user1).Where("id = ?", 1).Scan(ctx); err != nil {
} }
``` ```
See [**Getting started**](https://bun.uptrace.dev/guide/getting-started.html) guide and check See [**Getting started**](https://bun.uptrace.dev/guide/golang-orm.html) guide and check
[examples](example). [examples](example).
## See also
- [Golang HTTP router](https://github.com/uptrace/bunrouter)
- [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse)
- [Golang msgpack](https://github.com/vmihailenco/msgpack)
## Contributors ## Contributors
Thanks to all the people who already contributed! Thanks to all the people who already contributed!

Some files were not shown because too many files have changed in this diff Show more