245 lines
6.5 KiB
Go
245 lines
6.5 KiB
Go
|
package services
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"ms-auth/internal/lib"
|
||
|
"ms-auth/internal/storage"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
type UserProvider interface {
|
||
|
CreateUser(
|
||
|
ctx context.Context,
|
||
|
username string,
|
||
|
password string,
|
||
|
email *string,
|
||
|
expiresAt *time.Time,
|
||
|
role *int32,
|
||
|
) (*int32, error)
|
||
|
ReadUserByEmail(ctx context.Context, email string) (*storage.User, error)
|
||
|
ReadUserByUsername(ctx context.Context, username string) (*storage.User, error)
|
||
|
ReadUserById(ctx context.Context, id int32) (*storage.User, error)
|
||
|
UpdateUser(
|
||
|
ctx context.Context,
|
||
|
id int32,
|
||
|
username *string,
|
||
|
password *string,
|
||
|
email *string,
|
||
|
expiresAt *time.Time,
|
||
|
role *int32,
|
||
|
) error
|
||
|
DeleteUser(ctx context.Context, id int32) error
|
||
|
}
|
||
|
|
||
|
type ConfirmationProvider interface {
|
||
|
CreateConfirmation(ctx context.Context, conf *storage.Confirmation) error
|
||
|
ReadConfirmation(ctx context.Context, confId string) (*storage.Confirmation, error)
|
||
|
DeleteConfirmation(ctx context.Context, confId string) error
|
||
|
}
|
||
|
|
||
|
type EmailProvider interface {
|
||
|
SendMail(ctx context.Context, to []string, subject string, body string) error
|
||
|
}
|
||
|
|
||
|
// UserService represents a service for managing users.
|
||
|
type UserService struct {
|
||
|
userProvider UserProvider
|
||
|
sessionProvider SessionProvider
|
||
|
confirmationProvider ConfirmationProvider
|
||
|
//emailProvider EmailProvider
|
||
|
cfg *lib.Config
|
||
|
}
|
||
|
|
||
|
// NewUserService creates a new UserService instance.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// - userProvider: The UserProvider implementation used by the UserService.
|
||
|
// - sessionProvider: The SessionProvider implementation used by the UserService.
|
||
|
// - confirmationProvider: The ConfirmationProvider implementation used by the UserService.
|
||
|
// - emailProvider: The EmailProvider implementation used by the UserService.
|
||
|
// - cfg: The lib.Config object used by the UserService.
|
||
|
//
|
||
|
// Returns:
|
||
|
// - *UserService: A pointer to the newly created UserService instance.
|
||
|
func NewUserService(
|
||
|
userProvider UserProvider,
|
||
|
sessionProvider SessionProvider,
|
||
|
confirmationProvider ConfirmationProvider,
|
||
|
//emailProvider EmailProvider,
|
||
|
cfg *lib.Config,
|
||
|
) *UserService {
|
||
|
return &UserService{
|
||
|
userProvider: userProvider,
|
||
|
sessionProvider: sessionProvider,
|
||
|
confirmationProvider: confirmationProvider,
|
||
|
//emailProvider: emailProvider,
|
||
|
cfg: cfg,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// CreateUser creates a new user with the provided information.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// - ctx: The context for the operation.
|
||
|
// - token: The token associated with the session.
|
||
|
// - username: The username of the new user.
|
||
|
// - password: The password of the new user.
|
||
|
// - email: The email of the new user (can be nil).
|
||
|
// - expiresAt: The expiration time for the user account (can be nil).
|
||
|
// - role: The role of the new user.
|
||
|
//
|
||
|
// Returns:
|
||
|
// - *int32: The ID of the created user.
|
||
|
// - error: An error if the operation fails.
|
||
|
func (u *UserService) CreateUser(ctx context.Context, token, username, password string, email *string, expiresAt *time.Time, role *int32) (*int32, error) {
|
||
|
user, err := u.ReadUserBySessionToken(ctx, token)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
canCreate := func() bool {
|
||
|
if !user.IsAdmin() && !user.IsModerator() {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if role != nil && user.IsModerator() {
|
||
|
if lib.IsModerator(*role) || lib.IsAdmin(*role) {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}()
|
||
|
|
||
|
if !canCreate {
|
||
|
return nil, lib.ErrNoPermission
|
||
|
}
|
||
|
|
||
|
return u.userProvider.CreateUser(ctx, username, password, email, expiresAt, role)
|
||
|
}
|
||
|
|
||
|
// ReadUserBySessionToken reads a user by session token.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// - ctx: The context of the request.
|
||
|
// - token: The session token to identify the user.
|
||
|
//
|
||
|
// Returns:
|
||
|
// - *storage.User: The user information.
|
||
|
// - error: An error if the operation fails.
|
||
|
func (u *UserService) ReadUserBySessionToken(ctx context.Context, token string) (*storage.User, error) {
|
||
|
session, err := u.sessionProvider.ReadSessionByToken(ctx, token)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return u.userProvider.ReadUserById(ctx, *session.UserId)
|
||
|
}
|
||
|
|
||
|
// ReadUser reads a user by ID.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// - ctx: The context of the request.
|
||
|
// - token: The session token to identify the user.
|
||
|
// - id: The ID of the user to read.
|
||
|
//
|
||
|
// Returns:
|
||
|
// - *storage.User: The user information.
|
||
|
// - error: An error if the operation fails.
|
||
|
func (u *UserService) ReadUser(ctx context.Context, token string, id int32) (*storage.User, error) {
|
||
|
_, err := u.ReadUserBySessionToken(ctx, token)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return u.userProvider.ReadUserById(ctx, id)
|
||
|
}
|
||
|
|
||
|
// UpdateUser updates a user's information.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// - ctx: The context of the request.
|
||
|
// - token: The session token to identify the user.
|
||
|
// - id: The ID of the user to update.
|
||
|
// - username: The new username (can be nil).
|
||
|
// - password: The new password (can be nil).
|
||
|
// - email: The new email (can be nil).
|
||
|
// - expiresAt: The new expiration time (can be nil).
|
||
|
// - role: The new role (can be nil).
|
||
|
//
|
||
|
// Returns:
|
||
|
// - error: An error if the operation fails.
|
||
|
func (u *UserService) UpdateUser(
|
||
|
ctx context.Context,
|
||
|
token string,
|
||
|
id int32,
|
||
|
username *string,
|
||
|
password *string,
|
||
|
email *string,
|
||
|
expiresAt *time.Time,
|
||
|
role *int32,
|
||
|
) error {
|
||
|
me, err := u.ReadUserBySessionToken(ctx, token)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
user, err := u.userProvider.ReadUserById(ctx, id)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
hasAccess := func() bool {
|
||
|
if me.Id == user.Id {
|
||
|
return false
|
||
|
}
|
||
|
if me.IsAdmin() {
|
||
|
return true
|
||
|
}
|
||
|
if me.IsModerator() && (user.IsParticipant() || user.IsSpectator()) {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}()
|
||
|
|
||
|
if !hasAccess {
|
||
|
return lib.ErrNoPermission
|
||
|
}
|
||
|
|
||
|
return u.userProvider.UpdateUser(ctx, id, username, password, email, expiresAt, role)
|
||
|
}
|
||
|
|
||
|
// DeleteUser deletes a user by id.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// - ctx: The context of the request.
|
||
|
// - token: The session token to identify the authenticated user.
|
||
|
// - id: The ID of the user to delete.
|
||
|
//
|
||
|
// Returns:
|
||
|
// - error: An error if the operation fails.
|
||
|
func (u *UserService) DeleteUser(ctx context.Context, token string, id int32) error {
|
||
|
user, err := u.ReadUserBySessionToken(ctx, token)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if user.Id == id || !user.IsAdmin() {
|
||
|
return lib.ErrNoPermission
|
||
|
}
|
||
|
|
||
|
return u.userProvider.DeleteUser(ctx, id)
|
||
|
}
|
||
|
|
||
|
// ReadUserByEmail reads a user by email.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// - ctx: The context of the request.
|
||
|
// - email: The email of the user to read.
|
||
|
//
|
||
|
// Returns:
|
||
|
// - *storage.User: The user information.
|
||
|
// - error: An error if the operation fails.
|
||
|
func (u *UserService) ReadUserByEmail(ctx context.Context, email string) (*storage.User, error) {
|
||
|
return u.userProvider.ReadUserByEmail(ctx, email)
|
||
|
}
|