Files
SciMesh/users/internal/memstore/memstore.go
T
Efremenko Arhip 9a458ec4ef feat(users): admin promote/demote endpoints
POST /users/{id}/promote and /demote set a user's role (admin/user), admin-only
(403 otherwise). Mirrors the verify endpoints: SetRole use case + repo method,
validated role. Unit, admin-flow, and integration tests included.
2026-07-26 21:14:32 +03:00

91 lines
2.0 KiB
Go

// Package memstore provides in-memory implementations of the usecase ports for
// fast, deterministic tests that need no database.
package memstore
import (
"context"
"sync"
"time"
"github.com/google/uuid"
"github.com/emil28092005/SciMesh/users/internal/domain"
"github.com/emil28092005/SciMesh/users/internal/usecase"
)
// UserRepo is an in-memory usecase.UserRepository. It stores copies, so callers
// mutating a returned user cannot corrupt the store.
type UserRepo struct {
mu sync.Mutex
byID map[uuid.UUID]domain.User
byEmail map[string]uuid.UUID
}
func NewUserRepo() *UserRepo {
return &UserRepo{
byID: make(map[uuid.UUID]domain.User),
byEmail: make(map[string]uuid.UUID),
}
}
func (r *UserRepo) Insert(_ context.Context, u *domain.User) error {
r.mu.Lock()
defer r.mu.Unlock()
if _, ok := r.byEmail[u.Email]; ok {
return usecase.ErrEmailExists
}
r.byID[u.ID] = *u
r.byEmail[u.Email] = u.ID
return nil
}
func (r *UserRepo) GetByEmail(_ context.Context, email string) (*domain.User, error) {
r.mu.Lock()
defer r.mu.Unlock()
id, ok := r.byEmail[email]
if !ok {
return nil, usecase.ErrUserNotFound
}
u := r.byID[id]
return &u, nil
}
func (r *UserRepo) GetByID(_ context.Context, id uuid.UUID) (*domain.User, error) {
r.mu.Lock()
defer r.mu.Unlock()
u, ok := r.byID[id]
if !ok {
return nil, usecase.ErrUserNotFound
}
return &u, nil
}
func (r *UserRepo) SetVerified(_ context.Context, id uuid.UUID, verified bool) error {
r.mu.Lock()
defer r.mu.Unlock()
u, ok := r.byID[id]
if !ok {
return usecase.ErrUserNotFound
}
u.Verified = verified
r.byID[id] = u
return nil
}
func (r *UserRepo) SetRole(_ context.Context, id uuid.UUID, role domain.Role) error {
r.mu.Lock()
defer r.mu.Unlock()
u, ok := r.byID[id]
if !ok {
return usecase.ErrUserNotFound
}
u.Role = role
r.byID[id] = u
return nil
}
// Clock is a fixed usecase.Clock for deterministic tests.
type Clock struct{ T time.Time }
func (c Clock) Now() time.Time { return c.T }