[server] Fix db.Handler vs TxHandler

This commit is contained in:
Abhishek Shroff
2025-06-13 01:28:25 +05:30
parent 4e788f3b93
commit 2e892d3740
8 changed files with 71 additions and 78 deletions
+44 -20
View File
@@ -9,6 +9,7 @@ import (
"codeberg.org/shroff/phylum/server/internal/api/v1/responses"
"codeberg.org/shroff/phylum/server/internal/auth"
"codeberg.org/shroff/phylum/server/internal/core"
"codeberg.org/shroff/phylum/server/internal/db"
"codeberg.org/shroff/phylum/server/internal/mail"
"github.com/gin-gonic/gin"
)
@@ -43,20 +44,27 @@ func handlePasswordAuth(c *gin.Context) {
panic(core.NewError(http.StatusBadRequest, "missing_params", "Email or password not specified"))
}
if user, token, err := auth.CreateAccessToken(c.Request.Context(), params.Email, params.Password); err != nil {
if errors.Is(err, auth.ErrCredentialsInvalid) {
err = core.NewError(http.StatusBadRequest, "missing_params", "Username or password invalid")
var token string
var response responses.Bootstrap
if err := db.RunInTx(c.Request.Context(), func(db db.TxHandler) error {
if user, t, err := auth.CreateAccessToken(db, params.Email, params.Password); err != nil {
return err
} else if r, err := my.Bootstrap(c.Request.Context(), user, 0); err != nil {
return err
} else {
token = t
response = r
return nil
}
panic(err)
} else if bootstrap, err := my.Bootstrap(c.Request.Context(), user, 0); err != nil {
}); err != nil {
panic(err)
} else {
c.JSON(200, responses.Login{
AccessToken: token,
Bootstrap: bootstrap,
Bootstrap: response,
})
}
}
}
func handleRequestPasswordReset(c *gin.Context) {
@@ -66,19 +74,24 @@ func handleRequestPasswordReset(c *gin.Context) {
panic(core.NewError(http.StatusBadRequest, "missing_params", "Missing Parameters"))
}
if user, token, err := auth.CreateResetToken(c.Request.Context(), params.Email); err != nil {
// Do not indicate that there was an error if no user was found
if errors.Is(err, core.ErrUserNotFound) {
c.JSON(200, gin.H{})
return
if err := db.RunInTx(c.Request.Context(), func(db db.TxHandler) error {
if user, token, err := auth.CreateResetToken(db, params.Email); err != nil {
// Do not indicate that there was an error if no user was found
if !errors.Is(err, core.ErrUserNotFound) {
return err
}
} else {
// TODO: #jobs #mail
go func() {
mail.SendPasswordResetEmail(user, token)
}()
}
return nil
}); err != nil {
panic(err)
} else {
go func() {
mail.SendPasswordResetEmail(user, token)
}()
c.JSON(http.StatusOK, gin.H{})
}
c.JSON(200, gin.H{})
}
func handleResetPassword(c *gin.Context) {
@@ -88,15 +101,26 @@ func handleResetPassword(c *gin.Context) {
panic(core.NewError(http.StatusBadRequest, "missing_params", "Missing Parameters"))
}
if user, token, err := auth.ResetUserPassword(c.Request.Context(), params.Email, params.Token, params.Password); err != nil {
panic(err)
} else if bootstrap, err := my.Bootstrap(c.Request.Context(), user, 0); err != nil {
var token string
var response responses.Bootstrap
if err := db.RunInTx(c.Request.Context(), func(db db.TxHandler) error {
if user, t, err := auth.ResetUserPassword(db, params.Email, params.Token, params.Password); err != nil {
return err
} else if r, err := my.Bootstrap(c.Request.Context(), user, 0); err != nil {
return err
} else {
token = t
response = r
return nil
}
}); err != nil {
panic(err)
} else {
c.JSON(200, responses.Login{
AccessToken: token,
Bootstrap: bootstrap,
Bootstrap: response,
})
}
}
+15 -6
View File
@@ -33,14 +33,23 @@ func handleInviteRequest(c *gin.Context) {
panic(core.NewError(http.StatusBadRequest, "insufficient_permissions", "You do not have permissions to invite users"))
}
if user, err := core.CreateUser(db.Get(c.Request.Context()), params.Email, params.Name, params.NoCreateHome); err != nil {
var user core.User
if err := db.RunInTx(c.Request.Context(), func(db db.TxHandler) error {
if u, err := core.CreateUser(db, params.Email, params.Name, params.NoCreateHome); err != nil {
return err
} else {
user = u
if !params.NoSendEmail {
// TODO: #jobs #mail
go func() {
mail.SendWelcomeEmail(u)
}()
}
return nil
}
}); err != nil {
panic(err)
} else {
if !params.NoSendEmail {
go func() {
mail.SendWelcomeEmail(user)
}()
}
c.JSON(200, responses.User{ID: user.ID, Email: user.Email, Name: user.Name})
}
}
@@ -17,7 +17,6 @@ func SetupCommand() *cobra.Command {
cmd.AddCommand([]*cobra.Command{
setupListCommand(),
setupInviteCommand(),
setupPwresetResetCommand(),
setupModCommand(),
setupPasswdCommand(),
setupGrantCommand(),
+1 -1
View File
@@ -48,7 +48,7 @@ func setupPasswdCommand() *cobra.Command {
}
}
if err := db.Get(context.Background()).RunInTx(func(db db.TxHandler) error {
if err := db.RunInTx(context.Background(), func(db db.TxHandler) error {
return auth.UpdateUserPassword(db, email, password)
}); err != nil {
fmt.Println("could not change password: " + err.Error())
@@ -1,39 +0,0 @@
package user
import (
"context"
"fmt"
"os"
"codeberg.org/shroff/phylum/server/internal/auth"
"codeberg.org/shroff/phylum/server/internal/mail"
"github.com/spf13/cobra"
)
func setupPwresetResetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "pwreset <email>",
Short: "Send password reset email",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
email := args[0]
if user, token, err := auth.CreateResetToken(context.Background(), email); err != nil {
fmt.Println("unable to create reset token: " + err.Error())
os.Exit(1)
} else {
if b, _ := cmd.Flags().GetBool("no-email"); b {
fmt.Println("Created password reset token: " + token)
} else {
if err := mail.SendPasswordResetEmail(user, token); err != nil {
fmt.Println("unable to send email: " + err.Error())
fmt.Println("Use --no-email print the reset token instead instad of sending it by email")
os.Exit(1)
}
}
}
},
}
cmd.Flags().Bool("no-email", false, "Do not send email")
return cmd
}
+7 -2
View File
@@ -91,8 +91,13 @@ func _readRootID(d db.Handler) (uuid.UUID, error) {
if errors.Is(err, pgx.ErrNoRows) {
const createDir = "INSERT INTO resources(id, name, dir) VALUES ($1::UUID, '', TRUE)"
id, _ := uuid.NewV7()
_, err = d.ExecNoTx(createDir, id)
return id, err
if err := d.RunInTx(func(db db.TxHandler) error {
_, err = db.Exec(createDir, id)
return err
}); err != nil {
return uuid.Nil, err
}
return id, nil
}
return uuid.Nil, err
} else {
+4
View File
@@ -33,6 +33,10 @@ func Get(ctx context.Context) Handler {
}
}
func RunInTx(ctx context.Context, fn func(TxHandler) error) error {
return Get(ctx).RunInTx(fn)
}
// Pool returns the pgx pool
// Only to be used for jobs initialization
func Pool() *pgxpool.Pool {
-9
View File
@@ -10,7 +10,6 @@ import (
type Handler interface {
Query(stmt string, args ...interface{}) (pgx.Rows, error)
QueryRow(stmt string, args ...interface{}) pgx.Row
ExecNoTx(stmt string, args ...interface{}) (pgconn.CommandTag, error)
RunInTx(fn func(TxHandler) error) error
}
@@ -39,9 +38,6 @@ func (h handler) Query(stmt string, args ...interface{}) (pgx.Rows, error) {
func (h handler) QueryRow(stmt string, args ...interface{}) pgx.Row {
return h.tx.QueryRow(h.ctx, stmt, args...)
}
func (h handler) ExecNoTx(stmt string, args ...interface{}) (pgconn.CommandTag, error) {
return h.tx.Exec(h.ctx, stmt, args...)
}
func (h handler) RunInTx(fn func(TxHandler) error) error {
return pgx.BeginFunc(h.ctx, h.tx, func(tx pgx.Tx) error {
@@ -80,11 +76,6 @@ func (h txHandler) Exec(stmt string, args ...interface{}) (pgconn.CommandTag, er
return h.tx.Exec(h.ctx, stmt, args...)
}
// Part of the interface
func (h txHandler) ExecNoTx(stmt string, args ...interface{}) (pgconn.CommandTag, error) {
return h.tx.Exec(h.ctx, stmt, args...)
}
func (h txHandler) CopyFrom(tableName pgx.Identifier, columnNames []string, rowSrc pgx.CopyFromSource) (int64, error) {
return h.tx.CopyFrom(h.ctx, tableName, columnNames, rowSrc)
}