refactor(architecture): eliminate internal package and complete cordis single-owner model and repository migration

- Physically purged all legacy internal/ packages, centralized pkg/model/ and pkg/repository/
- Migrated domain models and database repositories into self-contained owner plugins (user, auth, message_gateway, admin, upload, risk_control)
- Decoupled cross-plugin interactions via pure core/contracts and typed EventBus
- Ensured 100% test coverage pass, zero data races (-race clean), and 0 lint issues in make code-check
This commit is contained in:
ryan
2026-08-28 08:40:43 +08:00
parent 1f348fd425
commit fb6a3edb89
323 changed files with 8222 additions and 17693 deletions
+93 -21
View File
@@ -1,20 +1,24 @@
// Copyright 2026 Arctel.net
// SPDX-License-Identifier: Apache-2.0
// Package user provides user profiles, credentials, role management, and access token domain services.
package user
import (
"context"
"errors"
"fmt"
"strings"
"time"
"github.com/Rain-kl/Wavelet/core/contracts"
"github.com/Rain-kl/Wavelet/internal/infra/persistence"
"github.com/Rain-kl/Wavelet/internal/infra/persistence/idgen"
"github.com/Rain-kl/Wavelet/internal/model"
"github.com/Rain-kl/Wavelet/internal/repository"
db "github.com/Rain-kl/Wavelet/pkg/persistence"
"github.com/Rain-kl/Wavelet/pkg/persistence/idgen"
pkgu "github.com/Rain-kl/Wavelet/pkg/util"
)
func toUserDTO(u *model.User) *contracts.UserDTO {
func toUserDTO(u *User) *contracts.UserDTO {
if u == nil {
return nil
}
@@ -44,23 +48,23 @@ func newUserService() contracts.UserService {
}
func (s *userServiceImpl) GetUserByID(ctx context.Context, id uint64) (*contracts.UserDTO, error) {
u, err := repository.GetUserByID(ctx, id)
u, err := GetUserByID(ctx, id)
if err != nil {
return nil, err
}
return toUserDTO(&u), nil
return toUserDTO(u), nil
}
func (s *userServiceImpl) GetUserByUsername(ctx context.Context, username string) (*contracts.UserDTO, error) {
u, err := repository.GetUserByUsername(ctx, username)
u, err := GetUserByUsername(ctx, username)
if err != nil {
return nil, err
}
return toUserDTO(&u), nil
return toUserDTO(u), nil
}
func (s *userServiceImpl) GetUserByEmail(ctx context.Context, email string) (*contracts.UserDTO, error) {
var u model.User
var u User
if err := db.DB(ctx).Where("email = ?", email).First(&u).Error; err != nil {
return nil, err
}
@@ -72,7 +76,7 @@ func (s *userServiceImpl) CreateUser(ctx context.Context, req contracts.CreateUs
return nil, errors.New("user: username cannot be empty")
}
user := model.User{
user := User{
ID: idgen.NextUint64ID(),
Username: req.Username,
Nickname: req.Nickname,
@@ -94,7 +98,7 @@ func (s *userServiceImpl) CreateUser(ctx context.Context, req contracts.CreateUs
}
}
if err := repository.CreateUser(ctx, &user); err != nil {
if err := CreateUser(ctx, &user); err != nil {
return nil, err
}
@@ -129,7 +133,7 @@ func (s *userServiceImpl) UpdateProfile(ctx context.Context, id uint64, req cont
}
updates["updated_at"] = time.Now()
if err := db.DB(ctx).Model(&model.User{}).Where("id = ?", id).Updates(updates).Error; err != nil {
if err := db.DB(ctx).Model(&User{}).Where("id = ?", id).Updates(updates).Error; err != nil {
return nil, err
}
@@ -137,7 +141,7 @@ func (s *userServiceImpl) UpdateProfile(ctx context.Context, id uint64, req cont
}
func (s *userServiceImpl) UpdatePassword(ctx context.Context, id uint64, oldPassword, newPassword string) error {
var user model.User
var user User
if err := db.DB(ctx).Where("id = ?", id).First(&user).Error; err != nil {
return err
}
@@ -150,7 +154,7 @@ func (s *userServiceImpl) UpdatePassword(ctx context.Context, id uint64, oldPass
return err
}
return db.DB(ctx).Model(&model.User{}).Where("id = ?", id).
return db.DB(ctx).Model(&User{}).Where("id = ?", id).
Updates(map[string]any{
"password": user.Password,
"updated_at": time.Now(),
@@ -158,7 +162,7 @@ func (s *userServiceImpl) UpdatePassword(ctx context.Context, id uint64, oldPass
}
func (s *userServiceImpl) VerifyPassword(ctx context.Context, id uint64, password string) bool {
var user model.User
var user User
if err := db.DB(ctx).Where("id = ?", id).First(&user).Error; err != nil {
pkgu.DummyCheckPassword(password)
return false
@@ -167,7 +171,7 @@ func (s *userServiceImpl) VerifyPassword(ctx context.Context, id uint64, passwor
}
func (s *userServiceImpl) UpdateLastLogin(ctx context.Context, id uint64, _ string) error {
return db.DB(ctx).Model(&model.User{}).Where("id = ?", id).
return db.DB(ctx).Model(&User{}).Where("id = ?", id).
Updates(map[string]any{
"last_login_at": time.Now(),
"updated_at": time.Now(),
@@ -182,13 +186,13 @@ func (s *userServiceImpl) ListUsers(ctx context.Context, page, pageSize int, key
pageSize = 20
}
filter := repository.AdminUserListFilter{
filter := AdminUserListFilter{
Username: keyword,
Page: page,
PageSize: pageSize,
}
total, users, err := repository.ListAdminUsers(ctx, filter)
total, users, err := ListAdminUsers(ctx, filter)
if err != nil {
return nil, 0, err
}
@@ -202,9 +206,77 @@ func (s *userServiceImpl) ListUsers(ctx context.Context, page, pageSize int, key
}
func (s *userServiceImpl) SetUserActive(ctx context.Context, id uint64, active bool) error {
return repository.UpdateUserActive(ctx, id, active)
return UpdateUserActive(ctx, id, active)
}
func (s *userServiceImpl) SetUserAdmin(ctx context.Context, id uint64, admin bool) error {
return db.DB(ctx).Model(&model.User{}).Where("id = ?", id).Update("is_admin", admin).Error
return db.DB(ctx).Model(&User{}).Where("id = ?", id).Update("is_admin", admin).Error
}
func (s *userServiceImpl) VerifyAccessToken(ctx context.Context, tokenHash string) (*contracts.UserDTO, bool, error) {
tokenRecord, err := GetAccessTokenByHash(ctx, tokenHash)
if err != nil {
return nil, false, err
}
user, err := GetActiveUserByID(ctx, tokenRecord.UserID)
if err != nil {
return nil, false, err
}
return toUserDTO(user), tokenRecord.IsAdmin, nil
}
func (s *userServiceImpl) DeleteUser(ctx context.Context, id uint64) error {
return DeleteUserWithRelations(ctx, id)
}
func (s *userServiceImpl) CountUsers(ctx context.Context) (int64, error) {
var count int64
err := db.DB(ctx).Model(&User{}).Count(&count).Error
return count, err
}
func (s *userServiceImpl) CountActiveUsers(ctx context.Context) (int64, error) {
var count int64
err := db.DB(ctx).Model(&User{}).Where("is_active = ?", true).Count(&count).Error
return count, err
}
func (s *userServiceImpl) GetFirstAdminUser(ctx context.Context) (*contracts.UserDTO, error) {
u, err := GetFirstAdminUser(ctx)
if err != nil {
return nil, err
}
return toUserDTO(u), nil
}
func (s *userServiceImpl) UniqueUsername(ctx context.Context, base string) (string, error) {
base = strings.TrimSpace(base)
if base == "" {
base = PluginName
}
existingUsernames, err := ListUsernamesMatchingBase(ctx, base)
if err != nil {
return "", err
}
exists := make(map[string]bool, len(existingUsernames))
for _, u := range existingUsernames {
exists[strings.ToLower(u)] = true
}
if !exists[strings.ToLower(base)] {
return base, nil
}
for i := 1; i <= 1000; i++ {
candidate := fmt.Sprintf("%s-%d", base, i)
if !exists[strings.ToLower(candidate)] {
return candidate, nil
}
}
return "", errors.New("failed to generate unique username")
}