Files
backend/internal/dto/user_converter.go
lan cf36b1350d refactor: introduce Wire dependency injection and interface-based architecture
- Add Google Wire for compile-time dependency injection
- Replace concrete service types with interfaces across handlers
- Remove global state (DB, cache) in favor of constructor injection
- Split monolithic files into focused modules:
  - config: separate files for each config domain
  - dto: converters split by domain (user, post, message, group)
  - cache: separate metrics.go and redis_cache.go
- Introduce unified apperrors package with string-based error codes
- Add transaction support with context-aware repository methods
- Upgrade golang.org/x/crypto from 0.17.0 to 0.26.0
2026-03-13 09:38:18 +08:00

236 lines
7.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package dto
import (
"carrot_bbs/internal/model"
"carrot_bbs/internal/pkg/utils"
)
// ==================== User 转换 ====================
// getAvatarOrDefault 获取头像URL如果为空则返回在线头像生成服务的URL
func getAvatarOrDefault(user *model.User) string {
return utils.GetAvatarOrDefault(user.Username, user.Nickname, user.Avatar)
}
// ConvertUserToResponse 将User转换为UserResponse
func ConvertUserToResponse(user *model.User) *UserResponse {
if user == nil {
return nil
}
return &UserResponse{
ID: user.ID,
Username: user.Username,
Nickname: user.Nickname,
Email: user.Email,
Phone: user.Phone,
EmailVerified: user.EmailVerified,
Avatar: getAvatarOrDefault(user),
CoverURL: user.CoverURL,
Bio: user.Bio,
Website: user.Website,
Location: user.Location,
PostsCount: user.PostsCount,
FollowersCount: user.FollowersCount,
FollowingCount: user.FollowingCount,
CreatedAt: FormatTime(user.CreatedAt),
}
}
// ConvertUserToResponseWithFollowing 将User转换为UserResponse包含关注状态
func ConvertUserToResponseWithFollowing(user *model.User, isFollowing bool) *UserResponse {
if user == nil {
return nil
}
return &UserResponse{
ID: user.ID,
Username: user.Username,
Nickname: user.Nickname,
Email: user.Email,
Phone: user.Phone,
EmailVerified: user.EmailVerified,
Avatar: getAvatarOrDefault(user),
CoverURL: user.CoverURL,
Bio: user.Bio,
Website: user.Website,
Location: user.Location,
PostsCount: user.PostsCount,
FollowersCount: user.FollowersCount,
FollowingCount: user.FollowingCount,
IsFollowing: isFollowing,
IsFollowingMe: false, // 默认false需要单独计算
CreatedAt: FormatTime(user.CreatedAt),
}
}
// ConvertUserToResponseWithPostsCount 将User转换为UserResponse使用实时计算的帖子数量
func ConvertUserToResponseWithPostsCount(user *model.User, postsCount int) *UserResponse {
if user == nil {
return nil
}
return &UserResponse{
ID: user.ID,
Username: user.Username,
Nickname: user.Nickname,
Email: user.Email,
Phone: user.Phone,
EmailVerified: user.EmailVerified,
Avatar: getAvatarOrDefault(user),
CoverURL: user.CoverURL,
Bio: user.Bio,
Website: user.Website,
Location: user.Location,
PostsCount: postsCount,
FollowersCount: user.FollowersCount,
FollowingCount: user.FollowingCount,
CreatedAt: FormatTime(user.CreatedAt),
}
}
// ConvertUserToResponseWithMutualFollow 将User转换为UserResponse包含双向关注状态
func ConvertUserToResponseWithMutualFollow(user *model.User, isFollowing, isFollowingMe bool) *UserResponse {
if user == nil {
return nil
}
return &UserResponse{
ID: user.ID,
Username: user.Username,
Nickname: user.Nickname,
Email: user.Email,
Phone: user.Phone,
EmailVerified: user.EmailVerified,
Avatar: getAvatarOrDefault(user),
CoverURL: user.CoverURL,
Bio: user.Bio,
Website: user.Website,
Location: user.Location,
PostsCount: user.PostsCount,
FollowersCount: user.FollowersCount,
FollowingCount: user.FollowingCount,
IsFollowing: isFollowing,
IsFollowingMe: isFollowingMe,
CreatedAt: FormatTime(user.CreatedAt),
}
}
// ConvertUserToResponseWithMutualFollowAndPostsCount 将User转换为UserResponse包含双向关注状态和实时计算的帖子数量
func ConvertUserToResponseWithMutualFollowAndPostsCount(user *model.User, isFollowing, isFollowingMe bool, postsCount int) *UserResponse {
if user == nil {
return nil
}
return &UserResponse{
ID: user.ID,
Username: user.Username,
Nickname: user.Nickname,
Email: user.Email,
Phone: user.Phone,
EmailVerified: user.EmailVerified,
Avatar: getAvatarOrDefault(user),
CoverURL: user.CoverURL,
Bio: user.Bio,
Website: user.Website,
Location: user.Location,
PostsCount: postsCount,
FollowersCount: user.FollowersCount,
FollowingCount: user.FollowingCount,
IsFollowing: isFollowing,
IsFollowingMe: isFollowingMe,
CreatedAt: FormatTime(user.CreatedAt),
}
}
// ConvertUserToDetailResponse 将User转换为UserDetailResponse
func ConvertUserToDetailResponse(user *model.User) *UserDetailResponse {
if user == nil {
return nil
}
return &UserDetailResponse{
ID: user.ID,
Username: user.Username,
Nickname: user.Nickname,
Email: user.Email,
EmailVerified: user.EmailVerified,
Avatar: getAvatarOrDefault(user),
CoverURL: user.CoverURL,
Bio: user.Bio,
Website: user.Website,
Location: user.Location,
PostsCount: user.PostsCount,
FollowersCount: user.FollowersCount,
FollowingCount: user.FollowingCount,
IsVerified: user.IsVerified,
CreatedAt: FormatTime(user.CreatedAt),
}
}
// ConvertUserToDetailResponseWithPostsCount 将User转换为UserDetailResponse使用实时计算的帖子数量
func ConvertUserToDetailResponseWithPostsCount(user *model.User, postsCount int) *UserDetailResponse {
if user == nil {
return nil
}
return &UserDetailResponse{
ID: user.ID,
Username: user.Username,
Nickname: user.Nickname,
Email: user.Email,
EmailVerified: user.EmailVerified,
Phone: user.Phone, // 仅当前用户自己可见
Avatar: getAvatarOrDefault(user),
CoverURL: user.CoverURL,
Bio: user.Bio,
Website: user.Website,
Location: user.Location,
PostsCount: postsCount,
FollowersCount: user.FollowersCount,
FollowingCount: user.FollowingCount,
IsVerified: user.IsVerified,
CreatedAt: FormatTime(user.CreatedAt),
}
}
// ConvertUsersToResponse 将User列表转换为响应列表
func ConvertUsersToResponse(users []*model.User) []*UserResponse {
result := make([]*UserResponse, 0, len(users))
for _, user := range users {
result = append(result, ConvertUserToResponse(user))
}
return result
}
// ConvertUsersToResponseWithMutualFollow 将User列表转换为响应列表包含双向关注状态
// followingStatusMap: key是用户IDvalue是[isFollowing, isFollowingMe]
func ConvertUsersToResponseWithMutualFollow(users []*model.User, followingStatusMap map[string][2]bool) []*UserResponse {
result := make([]*UserResponse, 0, len(users))
for _, user := range users {
status, ok := followingStatusMap[user.ID]
if ok {
result = append(result, ConvertUserToResponseWithMutualFollow(user, status[0], status[1]))
} else {
result = append(result, ConvertUserToResponse(user))
}
}
return result
}
// ConvertUsersToResponseWithMutualFollowAndPostsCount 将User列表转换为响应列表包含双向关注状态和实时计算的帖子数量
// followingStatusMap: key是用户IDvalue是[isFollowing, isFollowingMe]
// postsCountMap: key是用户IDvalue是帖子数量
func ConvertUsersToResponseWithMutualFollowAndPostsCount(users []*model.User, followingStatusMap map[string][2]bool, postsCountMap map[string]int64) []*UserResponse {
result := make([]*UserResponse, 0, len(users))
for _, user := range users {
status, hasStatus := followingStatusMap[user.ID]
postsCount, hasPostsCount := postsCountMap[user.ID]
// 如果没有帖子数量,使用数据库中的值
if !hasPostsCount {
postsCount = int64(user.PostsCount)
}
if hasStatus {
result = append(result, ConvertUserToResponseWithMutualFollowAndPostsCount(user, status[0], status[1], int(postsCount)))
} else {
result = append(result, ConvertUserToResponseWithPostsCount(user, int(postsCount)))
}
}
return result
}