Merge remote-tracking branch 'origin/stable'
This commit is contained in:
commit
7a4518184b
|
@ -0,0 +1,13 @@
|
|||
when:
|
||||
branch:
|
||||
exclude: stable
|
||||
|
||||
steps:
|
||||
check:
|
||||
image: golang:alpine
|
||||
commands:
|
||||
- apk update && apk add curl vips-dev build-base
|
||||
- make backend
|
||||
# Install golangci-lint
|
||||
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.55.2
|
||||
- golangci-lint run
|
|
@ -0,0 +1,20 @@
|
|||
when:
|
||||
branch:
|
||||
exclude: stable
|
||||
|
||||
steps:
|
||||
check:
|
||||
image: node
|
||||
directory: frontend
|
||||
environment: # SvelteKit expects these in the environment during build time.
|
||||
- PRIVATE_SENTRY_DSN=
|
||||
- PUBLIC_BASE_URL=http://pronouns.localhost
|
||||
- PUBLIC_MEDIA_URL=http://pronouns.localhost/media
|
||||
- PUBLIC_SHORT_BASE=http://prns.localhost
|
||||
- PUBLIC_HCAPTCHA_SITEKEY=non_existent_sitekey
|
||||
commands:
|
||||
- corepack enable
|
||||
- pnpm install
|
||||
- pnpm check
|
||||
- pnpm lint
|
||||
- pnpm build
|
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@ all: generate backend frontend
|
|||
|
||||
.PHONY: backend
|
||||
backend:
|
||||
go build -v -o pronouns -ldflags="-buildid= -X codeberg.org/pronounscc/pronouns.cc/backend/server.Revision=`git rev-parse --short HEAD` -X codeberg.org/pronounscc/pronouns.cc/backend/server.Tag=`git describe --tags --long`" .
|
||||
go build -v -o pronouns -ldflags="-buildid= -X codeberg.org/pronounscc/pronouns.cc/backend/server.Revision=`git rev-parse --short HEAD` -X codeberg.org/pronounscc/pronouns.cc/backend/server.Tag=`git describe --tags --long --always`" .
|
||||
|
||||
.PHONY: generate
|
||||
generate:
|
||||
|
|
|
@ -79,7 +79,7 @@ func (db *DB) CreateExport(ctx context.Context, userID xid.ID, filename string,
|
|||
return de, errors.Wrap(err, "building query")
|
||||
}
|
||||
|
||||
pgxscan.Get(ctx, db, &de, sql, args...)
|
||||
err = pgxscan.Get(ctx, db, &de, sql, args...)
|
||||
if err != nil {
|
||||
return de, errors.Wrap(err, "executing sql")
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"encoding/base64"
|
||||
"time"
|
||||
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/log"
|
||||
"emperror.dev/errors"
|
||||
"github.com/georgysavva/scany/v2/pgxscan"
|
||||
"github.com/jackc/pgx/v5"
|
||||
|
@ -43,7 +44,12 @@ func (db *DB) CreateInvite(ctx context.Context, userID xid.ID) (i Invite, err er
|
|||
if err != nil {
|
||||
return i, errors.Wrap(err, "beginning transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var maxInvites, inviteCount int
|
||||
err = tx.QueryRow(ctx, "SELECT max_invites FROM users WHERE id = $1", userID).Scan(&maxInvites)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/common"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/log"
|
||||
"emperror.dev/errors"
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/georgysavva/scany/v2/pgxscan"
|
||||
|
@ -41,12 +42,14 @@ const (
|
|||
)
|
||||
|
||||
// member names must match this regex
|
||||
var memberNameRegex = regexp.MustCompile("^[^@\\?!#/\\\\[\\]\"\\{\\}'$%&()+<=>^|~`,]{1,100}$")
|
||||
var memberNameRegex = regexp.MustCompile("^[^@\\?!#/\\\\[\\]\"\\{\\}'$%&()+<=>^|~`,\\*]{1,100}$")
|
||||
|
||||
// List of member names that cannot be used because they would break routing or be inaccessible due to page conflicts.
|
||||
var invalidMemberNames = []string{
|
||||
// these break routing outright
|
||||
".",
|
||||
"..",
|
||||
// the user edit page lives at `/@{username}/edit`, so a member named "edit" would be inaccessible
|
||||
"edit",
|
||||
}
|
||||
|
||||
|
@ -285,7 +288,12 @@ func (db *DB) RerollMemberSID(ctx context.Context, userID, memberID xid.ID) (new
|
|||
if err != nil {
|
||||
return "", errors.Wrap(err, "beginning transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
sql, args, err := sq.Update("members").
|
||||
Set("sid", squirrel.Expr("find_free_member_sid()")).
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
|
||||
"github.com/davidbyttow/govips/v2/vips"
|
||||
"github.com/getsentry/sentry-go"
|
||||
"github.com/go-chi/render"
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
@ -23,6 +24,19 @@ var Command = &cli.Command{
|
|||
}
|
||||
|
||||
func run(c *cli.Context) error {
|
||||
// initialize sentry
|
||||
if dsn := os.Getenv("SENTRY_DSN"); dsn != "" {
|
||||
// We don't need to check the error here--it's fine if no DSN is set.
|
||||
_ = sentry.Init(sentry.ClientOptions{
|
||||
Dsn: dsn,
|
||||
Debug: os.Getenv("DEBUG") == "true",
|
||||
Release: server.Tag,
|
||||
EnableTracing: os.Getenv("SENTRY_TRACING") == "true",
|
||||
TracesSampleRate: 0.05,
|
||||
ProfilesSampleRate: 0.05,
|
||||
})
|
||||
}
|
||||
|
||||
// set vips log level to WARN, else it will spam logs on info level
|
||||
vips.LoggingSettings(nil, vips.LogLevelWarning)
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package backend
|
|||
|
||||
import (
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/auth"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/bot"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/member"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/meta"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/routes/v1/mod"
|
||||
|
@ -21,7 +20,6 @@ func mountRoutes(s *server.Server) {
|
|||
auth.Mount(s, r)
|
||||
user.Mount(s, r)
|
||||
member.Mount(s, r)
|
||||
bot.Mount(s, r)
|
||||
meta.Mount(s, r)
|
||||
mod.Mount(s, r)
|
||||
})
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"emperror.dev/errors"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/mediocregopher/radix/v4"
|
||||
"github.com/rs/xid"
|
||||
"golang.org/x/oauth2"
|
||||
|
@ -61,7 +62,7 @@ func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
// if the state can't be validated, return
|
||||
if valid, err := s.validateCSRFState(ctx, decoded.State); !valid {
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "validating state")
|
||||
}
|
||||
|
||||
return server.APIError{Code: server.ErrInvalidState}
|
||||
|
@ -79,7 +80,7 @@ func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
dg, _ := discordgo.New(token.Type() + " " + token.AccessToken)
|
||||
du, err := dg.User("@me")
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting discord user")
|
||||
}
|
||||
|
||||
u, err := s.DB.DiscordUser(ctx, du.ID)
|
||||
|
@ -90,7 +91,7 @@ func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.saveUndeleteToken(ctx, u.ID, token)
|
||||
if err != nil {
|
||||
log.Errorf("saving undelete token: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "saving undelete token")
|
||||
}
|
||||
|
||||
render.JSON(w, r, discordCallbackResponse{
|
||||
|
@ -114,7 +115,7 @@ func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
tokenID := xid.New()
|
||||
token, err := s.Auth.CreateToken(u.ID, tokenID, u.IsAdmin, false, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "creating token")
|
||||
}
|
||||
|
||||
// save token to database
|
||||
|
@ -137,7 +138,7 @@ func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
return nil
|
||||
|
||||
} else if err != db.ErrUserNotFound { // internal error
|
||||
return err
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
|
||||
// no user found, so save a ticket + save their Discord info in Redis
|
||||
|
@ -145,7 +146,7 @@ func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.DB.SetJSON(ctx, "discord:"+ticket, du, "EX", "600")
|
||||
if err != nil {
|
||||
log.Errorf("setting Discord user for ticket %q: %v", ticket, err)
|
||||
return err
|
||||
return errors.Wrap(err, "caching discord user for ticket")
|
||||
}
|
||||
|
||||
render.JSON(w, r, discordCallbackResponse{
|
||||
|
@ -278,7 +279,7 @@ func (s *Server) discordSignup(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
valid, taken, err := s.DB.UsernameTaken(ctx, req.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "checking if username is taken")
|
||||
}
|
||||
if !valid {
|
||||
return server.APIError{Code: server.ErrInvalidUsername}
|
||||
|
@ -291,7 +292,12 @@ func (s *Server) discordSignup(w http.ResponseWriter, r *http.Request) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "beginning transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
du := new(discordgo.User)
|
||||
err = s.DB.GetJSON(ctx, "discord:"+req.Ticket, &du)
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/mediocregopher/radix/v4"
|
||||
"github.com/rs/xid"
|
||||
)
|
||||
|
@ -54,7 +55,7 @@ func (s *Server) mastodonCallback(w http.ResponseWriter, r *http.Request) error
|
|||
// if the state can't be validated, return
|
||||
if valid, err := s.validateCSRFState(ctx, decoded.State); !valid {
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "validating state")
|
||||
}
|
||||
|
||||
return server.APIError{Code: server.ErrInvalidState}
|
||||
|
@ -111,7 +112,7 @@ func (s *Server) mastodonCallback(w http.ResponseWriter, r *http.Request) error
|
|||
err = s.saveUndeleteToken(ctx, u.ID, token)
|
||||
if err != nil {
|
||||
log.Errorf("saving undelete token: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "saving undelete token")
|
||||
}
|
||||
|
||||
render.JSON(w, r, fediCallbackResponse{
|
||||
|
@ -135,7 +136,7 @@ func (s *Server) mastodonCallback(w http.ResponseWriter, r *http.Request) error
|
|||
tokenID := xid.New()
|
||||
token, err := s.Auth.CreateToken(u.ID, tokenID, u.IsAdmin, false, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "creating token")
|
||||
}
|
||||
|
||||
// save token to database
|
||||
|
@ -158,7 +159,7 @@ func (s *Server) mastodonCallback(w http.ResponseWriter, r *http.Request) error
|
|||
return nil
|
||||
|
||||
} else if err != db.ErrUserNotFound { // internal error
|
||||
return err
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
|
||||
// no user found, so save a ticket + save their Mastodon info in Redis
|
||||
|
@ -166,7 +167,7 @@ func (s *Server) mastodonCallback(w http.ResponseWriter, r *http.Request) error
|
|||
err = s.DB.SetJSON(ctx, "mastodon:"+ticket, mu, "EX", "600")
|
||||
if err != nil {
|
||||
log.Errorf("setting mastoAPI user for ticket %q: %v", ticket, err)
|
||||
return err
|
||||
return errors.Wrap(err, "setting user for ticket")
|
||||
}
|
||||
|
||||
render.JSON(w, r, fediCallbackResponse{
|
||||
|
@ -306,7 +307,7 @@ func (s *Server) mastodonSignup(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
valid, taken, err := s.DB.UsernameTaken(ctx, req.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "checking if username is taken")
|
||||
}
|
||||
if !valid {
|
||||
return server.APIError{Code: server.ErrInvalidUsername}
|
||||
|
@ -319,7 +320,12 @@ func (s *Server) mastodonSignup(w http.ResponseWriter, r *http.Request) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "beginning transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
mu := new(partialMastodonAccount)
|
||||
err = s.DB.GetJSON(ctx, "mastodon:"+req.Ticket, &mu)
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/mediocregopher/radix/v4"
|
||||
"github.com/rs/xid"
|
||||
)
|
||||
|
@ -90,7 +91,7 @@ func (s *Server) misskeyCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.saveUndeleteToken(ctx, u.ID, token)
|
||||
if err != nil {
|
||||
log.Errorf("saving undelete token: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "saving undelete token")
|
||||
}
|
||||
|
||||
render.JSON(w, r, fediCallbackResponse{
|
||||
|
@ -114,7 +115,7 @@ func (s *Server) misskeyCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
tokenID := xid.New()
|
||||
token, err := s.Auth.CreateToken(u.ID, tokenID, u.IsAdmin, false, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "creating token")
|
||||
}
|
||||
|
||||
// save token to database
|
||||
|
@ -137,7 +138,7 @@ func (s *Server) misskeyCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
return nil
|
||||
|
||||
} else if err != db.ErrUserNotFound { // internal error
|
||||
return err
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
|
||||
// no user found, so save a ticket + save their Misskey info in Redis
|
||||
|
@ -145,7 +146,7 @@ func (s *Server) misskeyCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.DB.SetJSON(ctx, "misskey:"+ticket, mu.User, "EX", "600")
|
||||
if err != nil {
|
||||
log.Errorf("setting misskey user for ticket %q: %v", ticket, err)
|
||||
return err
|
||||
return errors.Wrap(err, "setting user for ticket")
|
||||
}
|
||||
|
||||
render.JSON(w, r, fediCallbackResponse{
|
||||
|
@ -234,7 +235,7 @@ func (s *Server) misskeySignup(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
valid, taken, err := s.DB.UsernameTaken(ctx, req.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "checking if username is taken")
|
||||
}
|
||||
if !valid {
|
||||
return server.APIError{Code: server.ErrInvalidUsername}
|
||||
|
@ -247,7 +248,12 @@ func (s *Server) misskeySignup(w http.ResponseWriter, r *http.Request) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "beginning transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
mu := new(partialMisskeyAccount)
|
||||
err = s.DB.GetJSON(ctx, "misskey:"+req.Ticket, &mu)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/mediocregopher/radix/v4"
|
||||
"github.com/rs/xid"
|
||||
"golang.org/x/oauth2"
|
||||
|
@ -60,7 +61,7 @@ func (s *Server) googleCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
// if the state can't be validated, return
|
||||
if valid, err := s.validateCSRFState(ctx, decoded.State); !valid {
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "validating state")
|
||||
}
|
||||
|
||||
return server.APIError{Code: server.ErrInvalidState}
|
||||
|
@ -109,7 +110,7 @@ func (s *Server) googleCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.saveUndeleteToken(ctx, u.ID, token)
|
||||
if err != nil {
|
||||
log.Errorf("saving undelete token: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "saving undelete token")
|
||||
}
|
||||
|
||||
render.JSON(w, r, googleCallbackResponse{
|
||||
|
@ -133,7 +134,7 @@ func (s *Server) googleCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
tokenID := xid.New()
|
||||
token, err := s.Auth.CreateToken(u.ID, tokenID, u.IsAdmin, false, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "creating token")
|
||||
}
|
||||
|
||||
// save token to database
|
||||
|
@ -156,7 +157,7 @@ func (s *Server) googleCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
return nil
|
||||
|
||||
} else if err != db.ErrUserNotFound { // internal error
|
||||
return err
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
|
||||
// no user found, so save a ticket + save their Google info in Redis
|
||||
|
@ -164,7 +165,7 @@ func (s *Server) googleCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.DB.SetJSON(ctx, "google:"+ticket, partialGoogleUser{ID: googleID, Email: googleUsername}, "EX", "600")
|
||||
if err != nil {
|
||||
log.Errorf("setting Google user for ticket %q: %v", ticket, err)
|
||||
return err
|
||||
return errors.Wrap(err, "setting user for ticket")
|
||||
}
|
||||
|
||||
render.JSON(w, r, googleCallbackResponse{
|
||||
|
@ -281,7 +282,7 @@ func (s *Server) googleSignup(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
valid, taken, err := s.DB.UsernameTaken(ctx, req.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "checking if username is taken")
|
||||
}
|
||||
if !valid {
|
||||
return server.APIError{Code: server.ErrInvalidUsername}
|
||||
|
@ -294,7 +295,12 @@ func (s *Server) googleSignup(w http.ResponseWriter, r *http.Request) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "beginning transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
gu := new(partialGoogleUser)
|
||||
err = s.DB.GetJSON(ctx, "google:"+req.Ticket, &gu)
|
||||
|
|
|
@ -185,7 +185,7 @@ func (s *Server) oauthURLs(w http.ResponseWriter, r *http.Request) error {
|
|||
if googleOAuthConfig.ClientID != "" {
|
||||
googleCfg := googleOAuthConfig
|
||||
googleCfg.RedirectURL = req.CallbackDomain + "/auth/login/google"
|
||||
resp.Google = googleCfg.AuthCodeURL(state)
|
||||
resp.Google = googleCfg.AuthCodeURL(state) + "&prompt=select_account"
|
||||
}
|
||||
|
||||
render.JSON(w, r, resp)
|
||||
|
|
|
@ -5,9 +5,11 @@ import (
|
|||
"time"
|
||||
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/db"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/log"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/rs/xid"
|
||||
)
|
||||
|
||||
|
@ -63,7 +65,12 @@ func (s *Server) deleteToken(w http.ResponseWriter, r *http.Request) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "beginning transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = s.DB.InvalidateAllTokens(ctx, tx, claims.UserID)
|
||||
if err != nil {
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/mediocregopher/radix/v4"
|
||||
"github.com/rs/xid"
|
||||
"golang.org/x/oauth2"
|
||||
|
@ -77,7 +78,7 @@ func (s *Server) tumblrCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
// if the state can't be validated, return
|
||||
if valid, err := s.validateCSRFState(ctx, decoded.State); !valid {
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "validating state")
|
||||
}
|
||||
|
||||
return server.APIError{Code: server.ErrInvalidState}
|
||||
|
@ -142,7 +143,7 @@ func (s *Server) tumblrCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.saveUndeleteToken(ctx, u.ID, token)
|
||||
if err != nil {
|
||||
log.Errorf("saving undelete token: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "saving undelete token")
|
||||
}
|
||||
|
||||
render.JSON(w, r, tumblrCallbackResponse{
|
||||
|
@ -166,7 +167,7 @@ func (s *Server) tumblrCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
tokenID := xid.New()
|
||||
token, err := s.Auth.CreateToken(u.ID, tokenID, u.IsAdmin, false, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "creating token")
|
||||
}
|
||||
|
||||
// save token to database
|
||||
|
@ -189,7 +190,7 @@ func (s *Server) tumblrCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
return nil
|
||||
|
||||
} else if err != db.ErrUserNotFound { // internal error
|
||||
return err
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
|
||||
// no user found, so save a ticket + save their Tumblr info in Redis
|
||||
|
@ -197,7 +198,7 @@ func (s *Server) tumblrCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.DB.SetJSON(ctx, "tumblr:"+ticket, tumblrUserInfo{ID: tumblrID, Name: tumblrName}, "EX", "600")
|
||||
if err != nil {
|
||||
log.Errorf("setting Tumblr user for ticket %q: %v", ticket, err)
|
||||
return err
|
||||
return errors.Wrap(err, "setting user for ticket")
|
||||
}
|
||||
|
||||
render.JSON(w, r, tumblrCallbackResponse{
|
||||
|
@ -314,7 +315,7 @@ func (s *Server) tumblrSignup(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
valid, taken, err := s.DB.UsernameTaken(ctx, req.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "checking if username is taken")
|
||||
}
|
||||
if !valid {
|
||||
return server.APIError{Code: server.ErrInvalidUsername}
|
||||
|
@ -327,7 +328,12 @@ func (s *Server) tumblrSignup(w http.ResponseWriter, r *http.Request) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "beginning transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
tui := new(tumblrUserInfo)
|
||||
err = s.DB.GetJSON(ctx, "tumblr:"+req.Ticket, &tui)
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
package bot
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/db"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/log"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
type Bot struct {
|
||||
*server.Server
|
||||
|
||||
publicKey ed25519.PublicKey
|
||||
baseURL string
|
||||
}
|
||||
|
||||
func (bot *Bot) UserAvatarURL(u db.User) string {
|
||||
if u.Avatar == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return bot.baseURL + "/media/users/" + u.ID.String() + "/" + *u.Avatar + ".webp"
|
||||
}
|
||||
|
||||
func Mount(srv *server.Server, r chi.Router) {
|
||||
publicKey, err := hex.DecodeString(os.Getenv("DISCORD_PUBLIC_KEY"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b := &Bot{
|
||||
Server: srv,
|
||||
publicKey: publicKey,
|
||||
baseURL: os.Getenv("BASE_URL"),
|
||||
}
|
||||
|
||||
r.HandleFunc("/interactions", b.handle)
|
||||
}
|
||||
|
||||
func (bot *Bot) handle(w http.ResponseWriter, r *http.Request) {
|
||||
if !discordgo.VerifyInteraction(r, bot.publicKey) {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var ev *discordgo.InteractionCreate
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&ev); err != nil {
|
||||
http.Error(w, "Bad Request", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
// we can always respond to ping with pong
|
||||
if ev.Type == discordgo.InteractionPing {
|
||||
log.Debug("received ping interaction")
|
||||
render.JSON(w, r, discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponsePong,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if ev.Type != discordgo.InteractionApplicationCommand {
|
||||
return
|
||||
}
|
||||
data := ev.ApplicationCommandData()
|
||||
|
||||
switch data.Name {
|
||||
case "Show user's pronouns":
|
||||
bot.userPronouns(w, r, ev)
|
||||
case "Show author's pronouns":
|
||||
}
|
||||
}
|
||||
|
||||
func (bot *Bot) userPronouns(w http.ResponseWriter, r *http.Request, ev *discordgo.InteractionCreate) {
|
||||
ctx := r.Context()
|
||||
|
||||
var du *discordgo.User
|
||||
for _, user := range ev.ApplicationCommandData().Resolved.Users {
|
||||
du = user
|
||||
break
|
||||
}
|
||||
if du == nil {
|
||||
return
|
||||
}
|
||||
|
||||
u, err := bot.DB.DiscordUser(ctx, du.ID)
|
||||
if err != nil {
|
||||
if err == db.ErrUserNotFound {
|
||||
respond(w, r, &discordgo.MessageEmbed{
|
||||
Description: du.String() + " does not have any pronouns set.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
log.Errorf("getting discord user: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
avatarURL := du.AvatarURL("")
|
||||
if url := bot.UserAvatarURL(u); url != "" {
|
||||
avatarURL = url
|
||||
}
|
||||
name := u.Username
|
||||
if u.DisplayName != nil {
|
||||
name = fmt.Sprintf("%s (%s)", *u.DisplayName, u.Username)
|
||||
}
|
||||
url := bot.baseURL
|
||||
if url != "" {
|
||||
url += "/@" + u.Username
|
||||
}
|
||||
|
||||
e := &discordgo.MessageEmbed{
|
||||
Author: &discordgo.MessageEmbedAuthor{
|
||||
Name: name,
|
||||
IconURL: avatarURL,
|
||||
URL: url,
|
||||
},
|
||||
}
|
||||
|
||||
if u.Bio != nil {
|
||||
e.Fields = append(e.Fields, &discordgo.MessageEmbedField{
|
||||
Name: "Bio",
|
||||
Value: *u.Bio,
|
||||
})
|
||||
}
|
||||
|
||||
fields, err := bot.DB.UserFields(ctx, u.ID)
|
||||
if err != nil {
|
||||
respond(w, r, e)
|
||||
|
||||
log.Errorf("getting user fields: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
var favs []db.FieldEntry
|
||||
|
||||
for _, e := range field.Entries {
|
||||
if e.Status == "favourite" {
|
||||
favs = append(favs, e)
|
||||
}
|
||||
}
|
||||
|
||||
if len(favs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var value string
|
||||
for _, fav := range favs {
|
||||
if len(fav.Value) > 500 {
|
||||
break
|
||||
}
|
||||
|
||||
value += fav.Value + "\n"
|
||||
}
|
||||
|
||||
e.Fields = append(e.Fields, &discordgo.MessageEmbedField{
|
||||
Name: field.Name,
|
||||
Value: value,
|
||||
Inline: true,
|
||||
})
|
||||
}
|
||||
|
||||
respond(w, r, e)
|
||||
}
|
||||
|
||||
func respond(w http.ResponseWriter, r *http.Request, embeds ...*discordgo.MessageEmbed) {
|
||||
render.JSON(w, r, discordgo.InteractionResponse{
|
||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||
Data: &discordgo.InteractionResponseData{
|
||||
Embeds: embeds,
|
||||
Flags: discordgo.MessageFlagsEphemeral,
|
||||
},
|
||||
})
|
||||
}
|
|
@ -11,6 +11,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
type CreateMemberRequest struct {
|
||||
|
@ -119,7 +120,12 @@ func (s *Server) createMember(w http.ResponseWriter, r *http.Request) (err error
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "starting transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
m, err := s.DB.CreateMember(ctx, tx, claims.UserID, cmr.Name, cmr.DisplayName, cmr.Bio, cmr.Links)
|
||||
if err != nil {
|
||||
|
@ -127,14 +133,14 @@ func (s *Server) createMember(w http.ResponseWriter, r *http.Request) (err error
|
|||
return server.APIError{Code: server.ErrMemberNameInUse}
|
||||
}
|
||||
|
||||
return err
|
||||
return errors.Wrap(err, "creating member")
|
||||
}
|
||||
|
||||
// set names, pronouns, fields
|
||||
err = s.DB.SetMemberNamesPronouns(ctx, tx, m.ID, db.NotNull(cmr.Names), db.NotNull(cmr.Pronouns))
|
||||
if err != nil {
|
||||
log.Errorf("setting names and pronouns for member %v: %v", m.ID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "setting names/pronouns")
|
||||
}
|
||||
m.Names = cmr.Names
|
||||
m.Pronouns = cmr.Pronouns
|
||||
|
@ -142,7 +148,7 @@ func (s *Server) createMember(w http.ResponseWriter, r *http.Request) (err error
|
|||
err = s.DB.SetMemberFields(ctx, tx, m.ID, cmr.Fields)
|
||||
if err != nil {
|
||||
log.Errorf("setting fields for member %v: %v", m.ID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "setting fields")
|
||||
}
|
||||
|
||||
if cmr.Avatar != "" {
|
||||
|
@ -161,13 +167,13 @@ func (s *Server) createMember(w http.ResponseWriter, r *http.Request) (err error
|
|||
}
|
||||
|
||||
log.Errorf("converting member avatar: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "converting avatar")
|
||||
}
|
||||
|
||||
hash, err := s.DB.WriteMemberAvatar(ctx, m.ID, webp, jpg)
|
||||
if err != nil {
|
||||
log.Errorf("uploading member avatar: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "uploading avatar")
|
||||
}
|
||||
|
||||
err = tx.QueryRow(ctx, "UPDATE members SET avatar = $1 WHERE id = $2", hash, m.ID).Scan(&m.Avatar)
|
||||
|
@ -180,7 +186,7 @@ func (s *Server) createMember(w http.ResponseWriter, r *http.Request) (err error
|
|||
err = s.DB.UpdateActiveTime(ctx, tx, claims.UserID)
|
||||
if err != nil {
|
||||
log.Errorf("updating last active time for user %v: %v", claims.UserID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "updating last active time")
|
||||
}
|
||||
|
||||
err = tx.Commit(ctx)
|
||||
|
|
|
@ -66,7 +66,7 @@ func (s *Server) deleteMember(w http.ResponseWriter, r *http.Request) (err error
|
|||
err = s.DB.UpdateActiveTime(ctx, s.DB, claims.UserID)
|
||||
if err != nil {
|
||||
log.Errorf("updating last active time for user %v: %v", claims.UserID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "updating last active time")
|
||||
}
|
||||
|
||||
render.NoContent(w, r)
|
||||
|
|
|
@ -105,7 +105,7 @@ func (s *Server) getMember(w http.ResponseWriter, r *http.Request) (err error) {
|
|||
|
||||
u, err := s.DB.User(ctx, m.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
|
||||
if u.DeletedAt != nil {
|
||||
|
@ -119,12 +119,12 @@ func (s *Server) getMember(w http.ResponseWriter, r *http.Request) (err error) {
|
|||
|
||||
fields, err := s.DB.MemberFields(ctx, m.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting member fields")
|
||||
}
|
||||
|
||||
flags, err := s.DB.MemberFlags(ctx, m.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting member flags")
|
||||
}
|
||||
|
||||
render.JSON(w, r, dbMemberToMember(u, m, fields, flags, isOwnMember))
|
||||
|
@ -159,12 +159,12 @@ func (s *Server) getUserMember(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
fields, err := s.DB.MemberFields(ctx, m.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting member fields")
|
||||
}
|
||||
|
||||
flags, err := s.DB.MemberFlags(ctx, m.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting member flags")
|
||||
}
|
||||
|
||||
render.JSON(w, r, dbMemberToMember(u, m, fields, flags, isOwnMember))
|
||||
|
@ -189,12 +189,12 @@ func (s *Server) getMeMember(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
fields, err := s.DB.MemberFields(ctx, m.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting member fields")
|
||||
}
|
||||
|
||||
flags, err := s.DB.MemberFlags(ctx, m.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting member flags")
|
||||
}
|
||||
|
||||
render.JSON(w, r, dbMemberToMember(u, m, fields, flags, true))
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/common"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/db"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/rs/xid"
|
||||
|
@ -74,7 +75,7 @@ func (s *Server) getUserMembers(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
ms, err := s.DB.UserMembers(ctx, u.ID, isSelf)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting members")
|
||||
}
|
||||
|
||||
render.JSON(w, r, membersToMemberList(ms, isSelf))
|
||||
|
@ -87,7 +88,7 @@ func (s *Server) getMeMembers(w http.ResponseWriter, r *http.Request) error {
|
|||
|
||||
ms, err := s.DB.UserMembers(ctx, claims.UserID, true)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "getting members")
|
||||
}
|
||||
|
||||
render.JSON(w, r, membersToMemberList(ms, true))
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"emperror.dev/errors"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/rs/xid"
|
||||
)
|
||||
|
||||
|
@ -220,13 +221,13 @@ func (s *Server) patchMember(w http.ResponseWriter, r *http.Request) error {
|
|||
}
|
||||
|
||||
log.Errorf("converting member avatar: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "converting member avatar")
|
||||
}
|
||||
|
||||
hash, err := s.DB.WriteMemberAvatar(ctx, m.ID, webp, jpg)
|
||||
if err != nil {
|
||||
log.Errorf("uploading member avatar: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "writing member avatar")
|
||||
}
|
||||
avatarHash = &hash
|
||||
|
||||
|
@ -244,9 +245,14 @@ func (s *Server) patchMember(w http.ResponseWriter, r *http.Request) error {
|
|||
tx, err := s.DB.Begin(ctx)
|
||||
if err != nil {
|
||||
log.Errorf("creating transaction: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "creating transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
m, err = s.DB.UpdateMember(ctx, tx, m.ID, req.Name, req.DisplayName, req.Bio, req.Unlisted, req.Links, avatarHash)
|
||||
if err != nil {
|
||||
|
@ -275,7 +281,7 @@ func (s *Server) patchMember(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.DB.SetMemberNamesPronouns(ctx, tx, m.ID, names, pronouns)
|
||||
if err != nil {
|
||||
log.Errorf("setting names for member %v: %v", m.ID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "setting names/pronouns")
|
||||
}
|
||||
m.Names = names
|
||||
m.Pronouns = pronouns
|
||||
|
@ -286,14 +292,14 @@ func (s *Server) patchMember(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.DB.SetMemberFields(ctx, tx, m.ID, *req.Fields)
|
||||
if err != nil {
|
||||
log.Errorf("setting fields for member %v: %v", m.ID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "setting fields")
|
||||
}
|
||||
fields = *req.Fields
|
||||
} else {
|
||||
fields, err = s.DB.MemberFields(ctx, m.ID)
|
||||
if err != nil {
|
||||
log.Errorf("getting fields for member %v: %v", m.ID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "getting fields")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -306,7 +312,7 @@ func (s *Server) patchMember(w http.ResponseWriter, r *http.Request) error {
|
|||
}
|
||||
|
||||
log.Errorf("updating flags for member %v: %v", m.ID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "updating flags")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,20 +320,20 @@ func (s *Server) patchMember(w http.ResponseWriter, r *http.Request) error {
|
|||
err = s.DB.UpdateActiveTime(ctx, tx, claims.UserID)
|
||||
if err != nil {
|
||||
log.Errorf("updating last active time for user %v: %v", claims.UserID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "updating last active time")
|
||||
}
|
||||
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
log.Errorf("committing transaction: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "committing transaction")
|
||||
}
|
||||
|
||||
// get flags to return (we need to return full flag objects, not the array of IDs in the request body)
|
||||
flags, err := s.DB.MemberFlags(ctx, m.ID)
|
||||
if err != nil {
|
||||
log.Errorf("getting user flags: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "getting flags")
|
||||
}
|
||||
|
||||
// echo the updated member back on success
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"emperror.dev/errors"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
type resolveReportRequest struct {
|
||||
|
@ -43,7 +44,12 @@ func (s *Server) resolveReport(w http.ResponseWriter, r *http.Request) error {
|
|||
log.Errorf("creating transaction: %v", err)
|
||||
return errors.Wrap(err, "creating transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
report, err := s.DB.Report(ctx, tx, id)
|
||||
if err != nil {
|
||||
|
|
|
@ -3,9 +3,11 @@ package user
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/log"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
func (s *Server) deleteUser(w http.ResponseWriter, r *http.Request) error {
|
||||
|
@ -20,7 +22,12 @@ func (s *Server) deleteUser(w http.ResponseWriter, r *http.Request) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "creating transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
err = s.DB.DeleteUser(ctx, tx, claims.UserID, true, "")
|
||||
if err != nil {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/db"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/log"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
|
@ -71,7 +72,7 @@ func (s *Server) getExport(w http.ResponseWriter, r *http.Request) error {
|
|||
}
|
||||
|
||||
log.Errorf("getting export for user %v: %v", claims.UserID, err)
|
||||
return err
|
||||
return errors.Wrap(err, "getting export")
|
||||
}
|
||||
|
||||
render.JSON(w, r, dataExportResponse{
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"emperror.dev/errors"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/rs/xid"
|
||||
)
|
||||
|
||||
|
@ -80,7 +81,12 @@ func (s *Server) postUserFlag(w http.ResponseWriter, r *http.Request) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "starting transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
flag, err := s.DB.CreateFlag(ctx, tx, claims.UserID, req.Name, req.Description)
|
||||
if err != nil {
|
||||
|
@ -192,7 +198,12 @@ func (s *Server) patchUserFlag(w http.ResponseWriter, r *http.Request) error {
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "beginning transaction")
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
defer func() {
|
||||
err := tx.Rollback(ctx)
|
||||
if err != nil && !errors.Is(err, pgx.ErrTxClosed) {
|
||||
log.Error("rolling back transaction:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
flag, err = s.DB.EditFlag(ctx, tx, flag.ID, req.Name, req.Description, nil)
|
||||
if err != nil {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"codeberg.org/pronounscc/pronouns.cc/backend/db"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/log"
|
||||
"codeberg.org/pronounscc/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/rs/xid"
|
||||
|
@ -146,7 +147,7 @@ func (s *Server) getUser(w http.ResponseWriter, r *http.Request) (err error) {
|
|||
}
|
||||
} else if err != nil {
|
||||
log.Errorf("Error getting user by username: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "getting user")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,13 +163,13 @@ func (s *Server) getUser(w http.ResponseWriter, r *http.Request) (err error) {
|
|||
fields, err := s.DB.UserFields(ctx, u.ID)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting user fields: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "getting fields")
|
||||
}
|
||||
|
||||
flags, err := s.DB.UserFlags(ctx, u.ID)
|
||||
if err != nil {
|
||||
log.Errorf("getting user flags: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "getting flags")
|
||||
}
|
||||
|
||||
var members []db.Member
|
||||
|
@ -176,7 +177,7 @@ func (s *Server) getUser(w http.ResponseWriter, r *http.Request) (err error) {
|
|||
members, err = s.DB.UserMembers(ctx, u.ID, isSelf)
|
||||
if err != nil {
|
||||
log.Errorf("Error getting user members: %v", err)
|
||||
return err
|
||||
return errors.Wrap(err, "getting user members")
|
||||
}
|
||||