feat: 定义用户模块 User 模型与 Repository 层 #94
120
backend/internal/store/user_mem.go
Normal file
120
backend/internal/store/user_mem.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// MemUserRepository 基于内存的 UserRepository 实现(测试用)。
|
||||
type MemUserRepository struct {
|
||||
mu sync.RWMutex
|
||||
users map[string]*User // id -> user
|
||||
byUsername map[string]string // username -> id
|
||||
refreshTokens map[string]string // tokenHash -> userID
|
||||
tokenExpiry map[string]time.Time // tokenHash -> expiresAt
|
||||
}
|
||||
|
||||
// NewMemUserRepository 创建 MemUserRepository。
|
||||
func NewMemUserRepository() *MemUserRepository {
|
||||
return &MemUserRepository{
|
||||
users: make(map[string]*User),
|
||||
byUsername: make(map[string]string),
|
||||
refreshTokens: make(map[string]string),
|
||||
tokenExpiry: make(map[string]time.Time),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MemUserRepository) Create(_ context.Context, username, passwordHash string) (string, error) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
if _, exists := r.byUsername[username]; exists {
|
||||
return "", ErrUsernameTaken
|
||||
}
|
||||
|
||||
id := uuid.New().String()
|
||||
now := time.Now()
|
||||
user := &User{
|
||||
ID: id,
|
||||
Username: username,
|
||||
PasswordHash: passwordHash,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
r.users[id] = user
|
||||
r.byUsername[username] = id
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (r *MemUserRepository) FindByUsername(_ context.Context, username string) (*User, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
id, ok := r.byUsername[username]
|
||||
if !ok {
|
||||
return nil, ErrUserNotFound
|
||||
}
|
||||
u := r.users[id]
|
||||
copy := *u
|
||||
return ©, nil
|
||||
}
|
||||
|
||||
func (r *MemUserRepository) FindByID(_ context.Context, id string) (*User, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
u, ok := r.users[id]
|
||||
if !ok {
|
||||
return nil, ErrUserNotFound
|
||||
}
|
||||
copy := *u
|
||||
return ©, nil
|
||||
}
|
||||
|
||||
func (r *MemUserRepository) SaveRefreshToken(_ context.Context, userID, tokenHash string, expiresAt time.Time) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
r.refreshTokens[tokenHash] = userID
|
||||
r.tokenExpiry[tokenHash] = expiresAt
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *MemUserRepository) FindRefreshToken(_ context.Context, tokenHash string) (string, error) {
|
||||
r.mu.RLock()
|
||||
defer r.mu.RUnlock()
|
||||
|
||||
userID, ok := r.refreshTokens[tokenHash]
|
||||
if !ok {
|
||||
return "", ErrRefreshTokenNotFound
|
||||
}
|
||||
if time.Now().After(r.tokenExpiry[tokenHash]) {
|
||||
return "", ErrRefreshTokenNotFound
|
||||
}
|
||||
return userID, nil
|
||||
}
|
||||
|
||||
func (r *MemUserRepository) DeleteRefreshToken(_ context.Context, tokenHash string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
delete(r.refreshTokens, tokenHash)
|
||||
delete(r.tokenExpiry, tokenHash)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *MemUserRepository) DeleteUserRefreshTokens(_ context.Context, userID string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
for hash, uid := range r.refreshTokens {
|
||||
if uid == userID {
|
||||
delete(r.refreshTokens, hash)
|
||||
delete(r.tokenExpiry, hash)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user