package service import ( "context" "code.nochebuena.dev/go/rbac" "code.nochebuena.dev/go/todo-api/internal/domain" "code.nochebuena.dev/go/todo-api/internal/repository" ) // CreateUserRequest is the input for creating a new user. // CanRead / CanWrite seed the permission bits for the todos resource immediately. type CreateUserRequest struct { Name string `json:"name" validate:"required,min=1,max=100"` Email string `json:"email" validate:"required,email"` CanRead bool `json:"can_read"` CanWrite bool `json:"can_write"` } // UserService handles user business logic. type UserService interface { FindAll(ctx context.Context) ([]domain.User, error) Create(ctx context.Context, req CreateUserRequest) (domain.User, error) } type userService struct { repo repository.UserRepository idGen func() string } // NewUserService returns a UserService. idGen is called to mint new user IDs (e.g. uuid.NewString). func NewUserService(repo repository.UserRepository, idGen func() string) UserService { return &userService{repo: repo, idGen: idGen} } func (s *userService) FindAll(ctx context.Context) ([]domain.User, error) { return s.repo.FindAll(ctx) } func (s *userService) Create(ctx context.Context, req CreateUserRequest) (domain.User, error) { user, err := s.repo.Create(ctx, domain.User{ ID: s.idGen(), Name: req.Name, Email: req.Email, }) if err != nil { return domain.User{}, err } // Build and persist permission mask from the request flags. var mask rbac.PermissionMask if req.CanRead { mask = mask.Grant(domain.PermReadTodo) } if req.CanWrite { mask = mask.Grant(domain.PermWriteTodo) } if mask != 0 { if err := s.repo.SetPermissions(ctx, user.ID, domain.ResourceTodos, mask); err != nil { return domain.User{}, err } } return user, nil }