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:
+11
-6
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -36,7 +35,7 @@ type ListItem struct {
|
||||
}
|
||||
|
||||
type ListRepository interface {
|
||||
CreateList(ctx context.Context, name string, userIDs []string) (*List, error)
|
||||
CreateList(ctx context.Context, name string) (*List, error)
|
||||
DeleteList(ctx context.Context, listID string) error
|
||||
GetLists(ctx context.Context, userID string) ([]List, error)
|
||||
AddUserToList(ctx context.Context, listID string, userID string) error
|
||||
@@ -58,16 +57,22 @@ func NewListService(r ListRepository) *ListService {
|
||||
return &ListService{repo: r}
|
||||
}
|
||||
|
||||
func (s *ListService) CreateList(ctx context.Context, authUserID string, name string, userIDs []string) (*List, error) {
|
||||
func (s *ListService) CreateList(ctx context.Context, authUserID string, name string) (*List, error) {
|
||||
if name == "" {
|
||||
return nil, ErrListNameEmpty
|
||||
}
|
||||
|
||||
if !slices.Contains(userIDs, authUserID) {
|
||||
userIDs = append(userIDs, authUserID)
|
||||
list, err := s.repo.CreateList(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.repo.CreateList(ctx, name, userIDs)
|
||||
err = s.repo.AddUserToList(ctx, list.ID, authUserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (s *ListService) DeleteList(ctx context.Context, authUserID string, listID string) error {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
type RegistrationService struct {
|
||||
tx Transactor
|
||||
UserService *UserService
|
||||
InviteService *InviteService
|
||||
}
|
||||
|
||||
func NewRegistrationService(tx Transactor, u *UserService, i *InviteService) *RegistrationService {
|
||||
return &RegistrationService{tx: tx, UserService: u, InviteService: i}
|
||||
}
|
||||
|
||||
func (s *RegistrationService) Register(ctx context.Context, inviteCode string, email string, username string, password string) (*User, error) {
|
||||
invite, err := s.InviteService.GetInvite(ctx, inviteCode)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to get invite", slog.Any("error", err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var user *User
|
||||
err = s.tx.WithinTx(ctx, func(ctx context.Context) error {
|
||||
user, err = s.UserService.CreateUser(ctx, email, username, password)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to create user", slog.Any("error", err))
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.InviteService.ConsumeInvite(ctx, invite.ID, user.ID)
|
||||
if err != nil {
|
||||
slog.ErrorContext(ctx, "failed to consume invite", slog.Any("error", err))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
slog.InfoContext(ctx, "user registration complete",
|
||||
slog.String("user_id", user.ID),
|
||||
slog.String("invite_id", invite.ID))
|
||||
return user, nil
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package domain
|
||||
|
||||
import "context"
|
||||
|
||||
type Transactor interface {
|
||||
WithinTx(ctx context.Context, fn func(ctx context.Context) error) error
|
||||
}
|
||||
Reference in New Issue
Block a user