feat: added db transactions abstraction; cleaned up user registration; repos adapted new abstraction: all repos now support transactions, if present in ctx
This commit is contained in:
@@ -47,7 +47,7 @@ func (h *ListHandler) CreateList(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
list, err := h.ListService.CreateList(ctx, authContext.UserID, payload.Name, payload.UserIDs)
|
||||
list, err := h.ListService.CreateList(ctx, authContext.UserID, payload.Name)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to create list", slog.Any("error", err))
|
||||
response.Error(ctx, w, http.StatusInternalServerError, "failed to create list")
|
||||
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
)
|
||||
|
||||
type UserHandler struct {
|
||||
UserService *domain.UserService
|
||||
AuthService *domain.AuthService
|
||||
InviteService *domain.InviteService
|
||||
UserService *domain.UserService
|
||||
AuthService *domain.AuthService
|
||||
RegistrationService *domain.RegistrationService
|
||||
}
|
||||
|
||||
func NewUserHandler(userService *domain.UserService, authService *domain.AuthService, inviteService *domain.InviteService) *UserHandler {
|
||||
return &UserHandler{UserService: userService, AuthService: authService, InviteService: inviteService}
|
||||
func NewUserHandler(userService *domain.UserService, authService *domain.AuthService, registrationService *domain.RegistrationService) *UserHandler {
|
||||
return &UserHandler{UserService: userService, AuthService: authService, RegistrationService: registrationService}
|
||||
}
|
||||
|
||||
// CreateUser handles the creation of a user
|
||||
@@ -42,41 +42,17 @@ func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
invite, err := h.InviteService.GetInvite(ctx, payload.InviteCode)
|
||||
user, err := h.RegistrationService.Register(ctx, payload.InviteCode, payload.Email, payload.Name, payload.Password)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to get invite", slog.Any("error", err))
|
||||
response.Error(ctx, w, http.StatusBadRequest, "invite is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Creating user and consuming the invite must be in a transaction.
|
||||
// The repositories must support tx in context, and the handler must be able to start a transaction
|
||||
user, err := h.UserService.CreateUser(ctx, payload.Email, payload.Name, payload.Password)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to create user", slog.Any("error", err))
|
||||
response.Error(ctx, w, http.StatusInternalServerError, "failed to create user")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.InviteService.ConsumeInvite(ctx, invite.ID, user.ID)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to consume invite", slog.Any("error", err))
|
||||
|
||||
// TODO: This should be a transaction rollback, once we have db transactions in the handler
|
||||
err = h.UserService.DeleteUser(ctx, user.ID)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to delete user again",
|
||||
slog.Any("error", err),
|
||||
slog.String("user_id", user.ID),
|
||||
)
|
||||
}
|
||||
response.Error(ctx, w, http.StatusInternalServerError, "failed to consume invite")
|
||||
slog.ErrorContext(ctx, "failed to register user",
|
||||
slog.Any("error", err),
|
||||
slog.Any("payload", payload))
|
||||
response.Error(ctx, w, http.StatusInternalServerError, "failed to register")
|
||||
return
|
||||
}
|
||||
|
||||
slog.InfoContext(ctx, "created user successfully",
|
||||
slog.String("user_id", user.ID),
|
||||
slog.String("invite_id", invite.ID),
|
||||
)
|
||||
response.JSON(ctx, w, http.StatusCreated, user)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package request
|
||||
|
||||
type CreateListPayload struct {
|
||||
Name string `json:"name"`
|
||||
UserIDs []string `json:"user_ids"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type AddUserToListPayload struct {
|
||||
|
||||
@@ -16,20 +16,17 @@ type Config struct {
|
||||
}
|
||||
|
||||
func NewMux(cfg Config) http.Handler {
|
||||
authRepo := repository.NewAuthRepo(cfg.Database)
|
||||
authService := domain.NewAuthService(authRepo, []byte(cfg.JWTSecret))
|
||||
store := repository.NewStore(cfg.Database)
|
||||
|
||||
authService := domain.NewAuthService(store.Auth, []byte(cfg.JWTSecret))
|
||||
inviteService := domain.NewInviteService(store.Invite)
|
||||
userService := domain.NewUserService(store.User)
|
||||
registrationService := domain.NewRegistrationService(store, userService, inviteService)
|
||||
listService := domain.NewListService(store.List)
|
||||
|
||||
authHandler := handler.NewAuthHandler(authService)
|
||||
|
||||
inviteRepo := repository.NewInviteRepo(cfg.Database)
|
||||
inviteService := domain.NewInviteService(inviteRepo)
|
||||
inviteHandler := handler.NewInviteHandler(inviteService)
|
||||
|
||||
userRepo := repository.NewUserRepo(cfg.Database)
|
||||
userService := domain.NewUserService(userRepo)
|
||||
userHandler := handler.NewUserHandler(userService, authService, inviteService)
|
||||
|
||||
listRepo := repository.NewListRepo(cfg.Database)
|
||||
listService := domain.NewListService(listRepo)
|
||||
userHandler := handler.NewUserHandler(userService, authService, registrationService)
|
||||
listHandler := handler.NewListHandler(listService, userService)
|
||||
|
||||
protected := middleware.WithJWT(authService)
|
||||
|
||||
Reference in New Issue
Block a user