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) }