diff --git a/internal/api/handler/user.go b/internal/api/handler/user.go index f281090..d3be142 100644 --- a/internal/api/handler/user.go +++ b/internal/api/handler/user.go @@ -61,11 +61,23 @@ func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) { err = h.InviteService.ConsumeInvite(ctx, invite.ID, user.ID) if err != nil { slog.ErrorContext(ctx, "failed to consume invite", slog.Any("error", err)) - // TODO: As long as this is not executed within a transaction, the user will still be created, - // so we can actually return the success JSON + + // 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") + return } - slog.InfoContext(ctx, "created user successfully", slog.Any("user_id", user.ID)) + 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) } diff --git a/internal/domain/user.go b/internal/domain/user.go index d61d871..852a565 100644 --- a/internal/domain/user.go +++ b/internal/domain/user.go @@ -24,6 +24,7 @@ type User struct { type UserRepository interface { CreateUser(ctx context.Context, email string, name string, passwordHash string) (*User, error) + DeleteUser(ctx context.Context, userID string) error ChangePassword(ctx context.Context, userID string, passwordHash string) error GetUserByEmail(ctx context.Context, email string) (*User, error) } @@ -55,6 +56,14 @@ func (s *UserService) CreateUser(ctx context.Context, email string, name string, return s.repo.CreateUser(ctx, email, name, string(hash)) } +func (s *UserService) DeleteUser(ctx context.Context, userID string) error { + if len(userID) == 0 { + return ErrUserIDMissing + } + + return s.repo.DeleteUser(ctx, userID) +} + func (s *UserService) ChangePassword(ctx context.Context, userID string, password string) error { if len(userID) == 0 { return ErrUserIDMissing diff --git a/internal/repository/user.go b/internal/repository/user.go index eff6efe..e385fb1 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -40,6 +40,18 @@ func (r *UserRepo) CreateUser(ctx context.Context, email string, name string, pa return user, nil } +func (r *UserRepo) DeleteUser(ctx context.Context, userID string) error { + _, err := r.db.ExecContext(ctx, + "DELETE FROM users WHERE id = $1", + userID, + ) + if err != nil { + return fmt.Errorf("failed to delete user: %w", err) + } + + return nil +} + func (r *UserRepo) ChangePassword(ctx context.Context, userID string, passwordHash string) error { _, err := r.db.ExecContext(ctx, "UPDATE users SET password_hash = $1 WHERE id = $2",