forked from mirrors/pronouns.cc
feat(backend): add /api/v2/users/@me/settings
This commit is contained in:
parent
0c2eeaf954
commit
d97b3f8da1
9 changed files with 136 additions and 1 deletions
|
@ -54,6 +54,7 @@ type User struct {
|
|||
ListPrivate bool
|
||||
LastSIDReroll time.Time `db:"last_sid_reroll"`
|
||||
Timezone *string
|
||||
Settings UserSettings
|
||||
|
||||
DeletedAt *time.Time
|
||||
SelfDelete *bool
|
||||
|
|
26
backend/db/user_settings.go
Normal file
26
backend/db/user_settings.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"emperror.dev/errors"
|
||||
"github.com/rs/xid"
|
||||
)
|
||||
|
||||
type UserSettings struct {
|
||||
ReadChangelog string `json:"read_changelog"`
|
||||
ReadSettingsNotice string `json:"read_settings_notice"`
|
||||
}
|
||||
|
||||
func (db *DB) UpdateUserSettings(ctx context.Context, id xid.ID, us UserSettings) error {
|
||||
sql, args, err := sq.Update("users").Set("settings", us).Where("id = ?", id).ToSql()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "building sql")
|
||||
}
|
||||
|
||||
_, err = db.Exec(ctx, sql, args...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "executing query")
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/meta"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/mod"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/user"
|
||||
user2 "codeberg.org/pronounscc/pronouns.cc/backend/routes/v2/user"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
|
@ -22,7 +23,6 @@ var openapi string
|
|||
// mountRoutes mounts all API routes on the server's router.
|
||||
// they are all mounted under /v1/
|
||||
func mountRoutes(s *server.Server) {
|
||||
// future-proofing for API versions
|
||||
s.Router.Route("/v1", func(r chi.Router) {
|
||||
auth.Mount(s, r)
|
||||
user.Mount(s, r)
|
||||
|
@ -32,6 +32,10 @@ func mountRoutes(s *server.Server) {
|
|||
mod.Mount(s, r)
|
||||
})
|
||||
|
||||
s.Router.Route("/v2", func(r chi.Router) {
|
||||
user2.Mount(s, r)
|
||||
})
|
||||
|
||||
// API docs
|
||||
s.Router.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
render.HTML(w, r, openapi)
|
||||
|
|
21
backend/routes/v2/user/get_settings.go
Normal file
21
backend/routes/v2/user/get_settings.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/log"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
func (s *Server) GetSettings(w http.ResponseWriter, r *http.Request) (err error) {
|
||||
claims, _ := server.ClaimsFromContext(r.Context())
|
||||
u, err := s.DB.User(r.Context(), claims.UserID)
|
||||
if err != nil {
|
||||
log.Errorf("getting user: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
render.JSON(w, r, u.Settings)
|
||||
return nil
|
||||
}
|
45
backend/routes/v2/user/patch_settings.go
Normal file
45
backend/routes/v2/user/patch_settings.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/aarondl/opt/omitnull"
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
type PatchSettingsRequest struct {
|
||||
ReadChangelog omitnull.Val[string] `json:"read_changelog"`
|
||||
ReadSettingsNotice omitnull.Val[string] `json:"read_settings_notice"`
|
||||
}
|
||||
|
||||
func (s *Server) PatchSettings(w http.ResponseWriter, r *http.Request) (err error) {
|
||||
ctx := r.Context()
|
||||
claims, _ := server.ClaimsFromContext(ctx)
|
||||
u, err := s.DB.User(ctx, claims.UserID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
|
||||
var req PatchSettingsRequest
|
||||
err = render.Decode(r, &req)
|
||||
if err != nil {
|
||||
return server.APIError{Code: server.ErrBadRequest}
|
||||
}
|
||||
|
||||
if !req.ReadChangelog.IsUnset() {
|
||||
u.Settings.ReadChangelog = req.ReadChangelog.GetOrZero()
|
||||
}
|
||||
if !req.ReadSettingsNotice.IsUnset() {
|
||||
u.Settings.ReadSettingsNotice = req.ReadSettingsNotice.GetOrZero()
|
||||
}
|
||||
|
||||
err = s.DB.UpdateUserSettings(ctx, u.ID, u.Settings)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "updating user settings")
|
||||
}
|
||||
|
||||
render.JSON(w, r, u.Settings)
|
||||
return nil
|
||||
}
|
23
backend/routes/v2/user/routes.go
Normal file
23
backend/routes/v2/user/routes.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
*server.Server
|
||||
}
|
||||
|
||||
func Mount(srv *server.Server, r chi.Router) {
|
||||
s := &Server{
|
||||
Server: srv,
|
||||
}
|
||||
|
||||
r.Route("/users", func(r chi.Router) {
|
||||
r.With(server.MustAuth).Group(func(r chi.Router) {
|
||||
r.Get("/@me/settings", server.WrapHandler(s.GetSettings))
|
||||
r.Patch("/@me/settings", server.WrapHandler(s.PatchSettings))
|
||||
})
|
||||
})
|
||||
}
|
2
go.mod
2
go.mod
|
@ -5,6 +5,7 @@ go 1.18
|
|||
require (
|
||||
emperror.dev/errors v0.8.1
|
||||
github.com/Masterminds/squirrel v1.5.4
|
||||
github.com/aarondl/opt v0.0.0-20230313190023-85d93d668fec
|
||||
github.com/bwmarrin/discordgo v0.27.1
|
||||
github.com/davidbyttow/govips/v2 v2.13.0
|
||||
github.com/georgysavva/scany/v2 v2.0.0
|
||||
|
@ -32,6 +33,7 @@ require (
|
|||
require (
|
||||
cloud.google.com/go/compute v1.19.0 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
github.com/aarondl/json v0.0.0-20221020222930-8b0db17ef1bf // indirect
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
|
|
4
go.sum
4
go.sum
|
@ -54,6 +54,10 @@ github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8
|
|||
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/a8m/expect v1.0.0/go.mod h1:4IwSCMumY49ScypDnjNbYEjgVeqy1/U2cEs3Lat96eA=
|
||||
github.com/aarondl/json v0.0.0-20221020222930-8b0db17ef1bf h1:+edM69bH/X6JpYPmJYBRLanAMe1V5yRXYU3hHUovGcE=
|
||||
github.com/aarondl/json v0.0.0-20221020222930-8b0db17ef1bf/go.mod h1:FZqLhJSj2tg0ZN48GB1zvj00+ZYcHPqgsC7yzcgCq6k=
|
||||
github.com/aarondl/opt v0.0.0-20230313190023-85d93d668fec h1:2NFk5fe52cHyRcUnXSs4CSEAqm+rL/hr3AdflBE3VPU=
|
||||
github.com/aarondl/opt v0.0.0-20230313190023-85d93d668fec/go.mod h1:l4/5NZtYd/SIohsFhaJQQe+sPOTG22furpZ5FvcYOzk=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
|
|
9
scripts/migrate/020_settings.sql
Normal file
9
scripts/migrate/020_settings.sql
Normal file
|
@ -0,0 +1,9 @@
|
|||
-- 2023-08-16: Server-side user settings storage (for now, just whether specific notices are dismissed)
|
||||
|
||||
-- +migrate Up
|
||||
|
||||
alter table users add column settings jsonb not null default '{}';
|
||||
|
||||
-- +migrate Down
|
||||
|
||||
alter table users drop column settings;
|
Loading…
Reference in a new issue