refactor(server): decouple services and improve architecture
- Introduce interfaces for all major services (JWT, PostAI, Comment, Message, Notification, QRCodeLogin, Upload, Vote, etc.) to support dependency inversion. - Move query parameters from `internal/dto` to a new `internal/query` package to separate request payloads from data transfer objects. - Refactor `internal/router` to use embedded `RouterDeps` for cleaner dependency management. - Decouple handlers from repositories by injecting services instead of direct repository access, ensuring proper layering. - Improve database initialization by moving it from `internal/model` to `internal/database`. - Optimize message decryption by implementing a more efficient `BatchDecrypt` method in `MessageEncryptor` using a worker pool. - Enhance error handling and security by implementing fail-fast checks for encryption key length during startup. - Clean up unused code, including the `avatar` package and several unused DTOs.
This commit is contained in:
@@ -4,8 +4,8 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"with_you/internal/dto"
|
||||
"with_you/internal/pkg/response"
|
||||
"with_you/internal/query"
|
||||
"with_you/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -37,7 +37,7 @@ func (h *AdminLogHandler) GetOperationLogs(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
|
||||
filters := dto.LogFilter{
|
||||
filters := query.LogFilter{
|
||||
UserID: c.Query("user_id"),
|
||||
Operation: c.Query("operation"),
|
||||
TargetType: c.Query("target_type"),
|
||||
@@ -70,7 +70,7 @@ func (h *AdminLogHandler) GetLoginLogs(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
|
||||
filters := dto.LoginFilter{
|
||||
filters := query.LoginFilter{
|
||||
UserID: c.Query("user_id"),
|
||||
Event: c.Query("event"),
|
||||
Result: c.Query("result"),
|
||||
@@ -113,7 +113,7 @@ func (h *AdminLogHandler) GetDataChangeLogs(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
|
||||
filters := dto.DataChangeFilter{
|
||||
filters := query.DataChangeFilter{
|
||||
UserID: c.Query("user_id"),
|
||||
OperatorID: c.Query("operator_id"),
|
||||
ChangeType: c.Query("change_type"),
|
||||
@@ -190,7 +190,7 @@ func (h *AdminLogHandler) ExportLogs(c *gin.Context) {
|
||||
"logs": logs,
|
||||
})
|
||||
case "login":
|
||||
logs, _, err := h.loginLogService.GetLoginLogs(c.Request.Context(), dto.LoginFilter{}, 1, 10000)
|
||||
logs, _, err := h.loginLogService.GetLoginLogs(c.Request.Context(), query.LoginFilter{}, 1, 10000)
|
||||
if err != nil {
|
||||
response.HandleError(c, err, "failed to export login logs")
|
||||
return
|
||||
@@ -200,7 +200,7 @@ func (h *AdminLogHandler) ExportLogs(c *gin.Context) {
|
||||
"log": logs,
|
||||
})
|
||||
case "data_change":
|
||||
logs, _, err := h.dataChangeLogService.GetDataChangeLogs(c.Request.Context(), dto.DataChangeFilter{}, 1, 10000)
|
||||
logs, _, err := h.dataChangeLogService.GetDataChangeLogs(c.Request.Context(), query.DataChangeFilter{}, 1, 10000)
|
||||
if err != nil {
|
||||
response.HandleError(c, err, "failed to export data change logs")
|
||||
return
|
||||
|
||||
@@ -3,6 +3,7 @@ package handler
|
||||
import (
|
||||
"with_you/internal/dto"
|
||||
"with_you/internal/pkg/response"
|
||||
"with_you/internal/query"
|
||||
"with_you/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -24,7 +25,7 @@ func NewAdminReportHandler(adminReportService service.AdminReportService) *Admin
|
||||
// List 获取举报列表
|
||||
func (h *AdminReportHandler) List(c *gin.Context) {
|
||||
// 解析查询参数
|
||||
var query dto.AdminReportListQuery
|
||||
var query query.AdminReportListQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
response.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
@@ -136,4 +137,3 @@ func (h *AdminReportHandler) BatchHandle(c *gin.Context) {
|
||||
|
||||
response.Success(c, result)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"with_you/internal/dto"
|
||||
"with_you/internal/model"
|
||||
"with_you/internal/pkg/response"
|
||||
"with_you/internal/repository"
|
||||
"with_you/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -14,16 +14,16 @@ import (
|
||||
|
||||
type AdminVerificationHandler struct {
|
||||
adminVerificationService service.AdminVerificationService
|
||||
userRepo repository.UserRepository
|
||||
userService service.UserService
|
||||
}
|
||||
|
||||
func NewAdminVerificationHandler(
|
||||
adminVerificationService service.AdminVerificationService,
|
||||
userRepo repository.UserRepository,
|
||||
userService service.UserService,
|
||||
) *AdminVerificationHandler {
|
||||
return &AdminVerificationHandler{
|
||||
adminVerificationService: adminVerificationService,
|
||||
userRepo: userRepo,
|
||||
userService: userService,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func (h *AdminVerificationHandler) ListVerifications(c *gin.Context) {
|
||||
|
||||
responses := make([]*dto.AdminVerificationListResponse, len(records))
|
||||
for i, record := range records {
|
||||
responses[i] = h.convertToAdminListResponse(record)
|
||||
responses[i] = h.convertToAdminListResponse(c.Request.Context(), record)
|
||||
}
|
||||
|
||||
response.Paginated(c, responses, total, page, pageSize)
|
||||
@@ -74,7 +74,7 @@ func (h *AdminVerificationHandler) GetVerificationDetail(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, h.convertToAdminDetailResponse(record))
|
||||
response.Success(c, h.convertToAdminDetailResponse(c.Request.Context(), record))
|
||||
}
|
||||
|
||||
func (h *AdminVerificationHandler) ReviewVerification(c *gin.Context) {
|
||||
@@ -113,10 +113,10 @@ func (h *AdminVerificationHandler) ReviewVerification(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
response.Success(c, h.convertToAdminDetailResponse(record))
|
||||
response.Success(c, h.convertToAdminDetailResponse(c.Request.Context(), record))
|
||||
}
|
||||
|
||||
func (h *AdminVerificationHandler) convertToAdminListResponse(record *model.VerificationRecord) *dto.AdminVerificationListResponse {
|
||||
func (h *AdminVerificationHandler) convertToAdminListResponse(ctx context.Context, record *model.VerificationRecord) *dto.AdminVerificationListResponse {
|
||||
resp := &dto.AdminVerificationListResponse{
|
||||
ID: record.ID,
|
||||
UserID: record.UserID,
|
||||
@@ -129,7 +129,7 @@ func (h *AdminVerificationHandler) convertToAdminListResponse(record *model.Veri
|
||||
CreatedAt: dto.FormatTime(record.CreatedAt),
|
||||
}
|
||||
|
||||
user, err := h.userRepo.GetByID(record.UserID)
|
||||
user, err := h.userService.GetUserByID(ctx, record.UserID)
|
||||
if err == nil && user != nil {
|
||||
resp.Username = user.Username
|
||||
resp.Nickname = user.Nickname
|
||||
@@ -139,7 +139,7 @@ func (h *AdminVerificationHandler) convertToAdminListResponse(record *model.Veri
|
||||
if record.ReviewedAt != nil {
|
||||
resp.ReviewedAt = dto.FormatTime(*record.ReviewedAt)
|
||||
if record.ReviewedBy != nil {
|
||||
reviewer, err := h.userRepo.GetByID(*record.ReviewedBy)
|
||||
reviewer, err := h.userService.GetUserByID(ctx, *record.ReviewedBy)
|
||||
if err == nil && reviewer != nil {
|
||||
resp.ReviewerName = reviewer.Nickname
|
||||
}
|
||||
@@ -149,7 +149,7 @@ func (h *AdminVerificationHandler) convertToAdminListResponse(record *model.Veri
|
||||
return resp
|
||||
}
|
||||
|
||||
func (h *AdminVerificationHandler) convertToAdminDetailResponse(record *model.VerificationRecord) *dto.AdminVerificationDetailResponse {
|
||||
func (h *AdminVerificationHandler) convertToAdminDetailResponse(ctx context.Context, record *model.VerificationRecord) *dto.AdminVerificationDetailResponse {
|
||||
resp := &dto.AdminVerificationDetailResponse{
|
||||
ID: record.ID,
|
||||
UserID: record.UserID,
|
||||
@@ -163,7 +163,7 @@ func (h *AdminVerificationHandler) convertToAdminDetailResponse(record *model.Ve
|
||||
CreatedAt: dto.FormatTime(record.CreatedAt),
|
||||
}
|
||||
|
||||
user, err := h.userRepo.GetByID(record.UserID)
|
||||
user, err := h.userService.GetUserByID(ctx, record.UserID)
|
||||
if err == nil && user != nil {
|
||||
resp.Username = user.Username
|
||||
resp.Nickname = user.Nickname
|
||||
@@ -175,7 +175,7 @@ func (h *AdminVerificationHandler) convertToAdminDetailResponse(record *model.Ve
|
||||
}
|
||||
if record.ReviewedBy != nil {
|
||||
resp.ReviewedBy = *record.ReviewedBy
|
||||
if reviewer, err := h.userRepo.GetByID(*record.ReviewedBy); err == nil && reviewer != nil {
|
||||
if reviewer, err := h.userService.GetUserByID(ctx, *record.ReviewedBy); err == nil && reviewer != nil {
|
||||
resp.ReviewerName = reviewer.Nickname
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@ import (
|
||||
|
||||
// CommentHandler 评论处理器
|
||||
type CommentHandler struct {
|
||||
commentService *service.CommentService
|
||||
commentService service.CommentService
|
||||
}
|
||||
|
||||
// NewCommentHandler 创建评论处理器
|
||||
func NewCommentHandler(commentService *service.CommentService) *CommentHandler {
|
||||
func NewCommentHandler(commentService service.CommentService) *CommentHandler {
|
||||
return &CommentHandler{
|
||||
commentService: commentService,
|
||||
}
|
||||
|
||||
@@ -4,22 +4,18 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"with_you/internal/pkg/response"
|
||||
"with_you/internal/repository"
|
||||
"with_you/internal/service"
|
||||
)
|
||||
|
||||
type EmptyClassroomHandler struct {
|
||||
classroomSyncService service.EmptyClassroomSyncService
|
||||
classroomRepo repository.EmptyClassroomRepository
|
||||
}
|
||||
|
||||
func NewEmptyClassroomHandler(
|
||||
classroomSyncService service.EmptyClassroomSyncService,
|
||||
classroomRepo repository.EmptyClassroomRepository,
|
||||
) *EmptyClassroomHandler {
|
||||
return &EmptyClassroomHandler{
|
||||
classroomSyncService: classroomSyncService,
|
||||
classroomRepo: classroomRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +73,7 @@ func (h *EmptyClassroomHandler) ListEmptyClassrooms(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
classrooms, err := h.classroomRepo.ListByUserAndSemester(userID, semester)
|
||||
classrooms, err := h.classroomSyncService.ListClassrooms(userID, semester)
|
||||
if err != nil {
|
||||
response.HandleError(c, err, "failed to list empty classrooms")
|
||||
return
|
||||
|
||||
@@ -4,19 +4,16 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"with_you/internal/pkg/response"
|
||||
"with_you/internal/repository"
|
||||
"with_you/internal/service"
|
||||
)
|
||||
|
||||
type ExamHandler struct {
|
||||
examSyncService service.ExamSyncService
|
||||
examRepo repository.ExamRepository
|
||||
}
|
||||
|
||||
func NewExamHandler(examSyncService service.ExamSyncService, examRepo repository.ExamRepository) *ExamHandler {
|
||||
func NewExamHandler(examSyncService service.ExamSyncService) *ExamHandler {
|
||||
return &ExamHandler{
|
||||
examSyncService: examSyncService,
|
||||
examRepo: examRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +65,7 @@ func (h *ExamHandler) ListExams(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
exams, err := h.examRepo.ListByUserAndSemester(userID, semester)
|
||||
exams, err := h.examSyncService.ListExams(userID, semester)
|
||||
if err != nil {
|
||||
response.HandleError(c, err, "failed to list exams")
|
||||
return
|
||||
|
||||
@@ -4,19 +4,16 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"with_you/internal/pkg/response"
|
||||
"with_you/internal/repository"
|
||||
"with_you/internal/service"
|
||||
)
|
||||
|
||||
type GradeHandler struct {
|
||||
gradeSyncService service.GradeSyncService
|
||||
gradeRepo repository.GradeRepository
|
||||
}
|
||||
|
||||
func NewGradeHandler(gradeSyncService service.GradeSyncService, gradeRepo repository.GradeRepository) *GradeHandler {
|
||||
func NewGradeHandler(gradeSyncService service.GradeSyncService) *GradeHandler {
|
||||
return &GradeHandler{
|
||||
gradeSyncService: gradeSyncService,
|
||||
gradeRepo: gradeRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,16 +60,14 @@ func (h *GradeHandler) ListGrades(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
grades, err := h.gradeRepo.ListByUser(userID)
|
||||
summary, err := h.gradeSyncService.ListGradesWithSummary(userID)
|
||||
if err != nil {
|
||||
response.HandleError(c, err, "failed to list grades")
|
||||
return
|
||||
}
|
||||
|
||||
gpaSummary, _ := h.gradeRepo.GetLatestGpaSummary(userID)
|
||||
|
||||
response.Success(c, gin.H{
|
||||
"grades": grades,
|
||||
"gpa_summary": gpaSummary,
|
||||
"grades": summary.Grades,
|
||||
"gpa_summary": summary.GpaSummary,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ func NewLiveKitHandler(
|
||||
liveKitService: liveKitService,
|
||||
callService: callService,
|
||||
config: &cfg.LiveKit,
|
||||
logger: logger,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,4 +163,4 @@ func (h *LiveKitHandler) handleRoomFinished(ctx context.Context, event *livekit.
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"with_you/internal/dto"
|
||||
"with_you/internal/model"
|
||||
"with_you/internal/pkg/response"
|
||||
"with_you/internal/query"
|
||||
"with_you/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -148,7 +148,7 @@ func (h *MaterialHandler) ListMaterials(c *gin.Context) {
|
||||
fileType := c.Query("file_type")
|
||||
keyword := c.Query("keyword")
|
||||
|
||||
params := dto.MaterialFileQueryParams{
|
||||
params := query.MaterialFileQueryParams{
|
||||
SubjectID: subjectID,
|
||||
FileType: fileType,
|
||||
Keyword: keyword,
|
||||
@@ -329,7 +329,7 @@ func (h *MaterialHandler) AdminListMaterials(c *gin.Context) {
|
||||
status := c.Query("status")
|
||||
keyword := c.Query("keyword")
|
||||
|
||||
params := dto.MaterialFileQueryParams{
|
||||
params := query.MaterialFileQueryParams{
|
||||
SubjectID: subjectID,
|
||||
FileType: fileType,
|
||||
Status: status,
|
||||
|
||||
@@ -87,14 +87,14 @@ func (h *MessageHandler) enrichConversations(ctx context.Context, convs []*model
|
||||
// MessageHandler 消息处理器
|
||||
type MessageHandler struct {
|
||||
chatService service.ChatService
|
||||
messageService *service.MessageService
|
||||
messageService service.MessageService
|
||||
userService service.UserService
|
||||
groupService service.GroupService
|
||||
wsPublisher ws.MessagePublisher
|
||||
}
|
||||
|
||||
// NewMessageHandler 创建消息处理器
|
||||
func NewMessageHandler(chatService service.ChatService, messageService *service.MessageService, userService service.UserService, groupService service.GroupService, wsPublisher ws.MessagePublisher) *MessageHandler {
|
||||
func NewMessageHandler(chatService service.ChatService, messageService service.MessageService, userService service.UserService, groupService service.GroupService, wsPublisher ws.MessagePublisher) *MessageHandler {
|
||||
return &MessageHandler{
|
||||
chatService: chatService,
|
||||
messageService: messageService,
|
||||
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
|
||||
// NotificationHandler 通知处理器
|
||||
type NotificationHandler struct {
|
||||
notificationService *service.NotificationService
|
||||
notificationService service.NotificationService
|
||||
}
|
||||
|
||||
// NewNotificationHandler 创建通知处理器
|
||||
func NewNotificationHandler(notificationService *service.NotificationService) *NotificationHandler {
|
||||
func NewNotificationHandler(notificationService service.NotificationService) *NotificationHandler {
|
||||
return &NotificationHandler{
|
||||
notificationService: notificationService,
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ import (
|
||||
|
||||
// QRCodeHandler 二维码登录处理器
|
||||
type QRCodeHandler struct {
|
||||
qrcodeService *service.QRCodeLoginService
|
||||
qrcodeService service.QRCodeLoginService
|
||||
}
|
||||
|
||||
// NewQRCodeHandler 创建二维码登录处理器
|
||||
func NewQRCodeHandler(qrcodeService *service.QRCodeLoginService) *QRCodeHandler {
|
||||
func NewQRCodeHandler(qrcodeService service.QRCodeLoginService) *QRCodeHandler {
|
||||
return &QRCodeHandler{
|
||||
qrcodeService: qrcodeService,
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@ import (
|
||||
|
||||
// UploadHandler 上传处理器
|
||||
type UploadHandler struct {
|
||||
uploadService *service.UploadService
|
||||
uploadService service.UploadService
|
||||
}
|
||||
|
||||
// NewUploadHandler 创建上传处理器
|
||||
func NewUploadHandler(uploadService *service.UploadService) *UploadHandler {
|
||||
func NewUploadHandler(uploadService service.UploadService) *UploadHandler {
|
||||
return &UploadHandler{
|
||||
uploadService: uploadService,
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ type UserHandler struct {
|
||||
userService service.UserService
|
||||
activityService service.UserActivityService
|
||||
profileAuditService service.UserProfileAuditService
|
||||
jwtService *service.JWTService
|
||||
jwtService service.JWTService
|
||||
logService *service.LogService
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func (h *UserHandler) SetProfileAuditService(profileAuditService service.UserPro
|
||||
}
|
||||
|
||||
// SetJWTService 设置JWT服务
|
||||
func (h *UserHandler) SetJWTService(jwtService *service.JWTService) {
|
||||
func (h *UserHandler) SetJWTService(jwtService service.JWTService) {
|
||||
h.jwtService = jwtService
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@ import (
|
||||
|
||||
// VoteHandler 投票处理器
|
||||
type VoteHandler struct {
|
||||
voteService *service.VoteService
|
||||
voteService service.VoteService
|
||||
postService service.PostService
|
||||
}
|
||||
|
||||
// NewVoteHandler 创建投票处理器
|
||||
func NewVoteHandler(voteService *service.VoteService, postService service.PostService) *VoteHandler {
|
||||
func NewVoteHandler(voteService service.VoteService, postService service.PostService) *VoteHandler {
|
||||
return &VoteHandler{
|
||||
voteService: voteService,
|
||||
postService: postService,
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"with_you/internal/model"
|
||||
"with_you/internal/pkg/response"
|
||||
"with_you/internal/pkg/ws"
|
||||
"with_you/internal/repository"
|
||||
"with_you/internal/service"
|
||||
)
|
||||
|
||||
@@ -69,9 +68,9 @@ type WSHandler struct {
|
||||
publisher ws.MessagePublisher
|
||||
chatService service.ChatService
|
||||
groupService service.GroupService
|
||||
jwtService *service.JWTService
|
||||
jwtService service.JWTService
|
||||
callService service.CallService
|
||||
userRepo repository.UserRepository
|
||||
userService service.UserService
|
||||
clientSeq uint64
|
||||
}
|
||||
|
||||
@@ -92,9 +91,9 @@ func NewWSHandler(
|
||||
publisher ws.MessagePublisher,
|
||||
chatService service.ChatService,
|
||||
groupService service.GroupService,
|
||||
jwtService *service.JWTService,
|
||||
jwtService service.JWTService,
|
||||
callService service.CallService,
|
||||
userRepo repository.UserRepository,
|
||||
userService service.UserService,
|
||||
) *WSHandler {
|
||||
return &WSHandler{
|
||||
publisher: publisher,
|
||||
@@ -102,7 +101,7 @@ func NewWSHandler(
|
||||
groupService: groupService,
|
||||
jwtService: jwtService,
|
||||
callService: callService,
|
||||
userRepo: userRepo,
|
||||
userService: userService,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,7 +577,7 @@ func (h *WSHandler) handleAck(client *ws.Client, payload json.RawMessage) {
|
||||
|
||||
// isVerified 检查用户是否已通过身份认证
|
||||
func (h *WSHandler) isVerified(ctx context.Context, client *ws.Client) bool {
|
||||
user, err := h.userRepo.GetByID(client.UserID)
|
||||
user, err := h.userService.GetUserByID(ctx, client.UserID)
|
||||
if err != nil {
|
||||
h.publisher.SendError(client, "internal_error", "获取用户信息失败")
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user