- 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.
175 lines
5.6 KiB
Go
175 lines
5.6 KiB
Go
package service
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"with_you/internal/model"
|
|
"with_you/internal/query"
|
|
"with_you/internal/repository"
|
|
)
|
|
|
|
// ErrSubjectHasMaterials 学科下存在资料,无法删除
|
|
var ErrSubjectHasMaterials = errors.New("学科下存在资料,无法删除")
|
|
|
|
// MaterialService 学习资料服务接口
|
|
type MaterialService interface {
|
|
// 学科相关
|
|
ListActiveSubjects() ([]*model.MaterialSubject, error)
|
|
ListAllSubjects() ([]*model.MaterialSubject, error)
|
|
GetSubjectByID(id string) (*model.MaterialSubject, error)
|
|
GetSubjectByIDWithMaterialCount(id string) (*model.MaterialSubject, int64, error)
|
|
CreateSubject(name, icon, color, description string, sortOrder int, isActive bool) (*model.MaterialSubject, error)
|
|
UpdateSubject(id, name, icon, color, description string, sortOrder int, isActive bool) (*model.MaterialSubject, error)
|
|
DeleteSubject(id string) error
|
|
|
|
// 资料相关
|
|
ListMaterials(params query.MaterialFileQueryParams) ([]*model.MaterialFile, int64, error)
|
|
GetMaterialByID(id string) (*model.MaterialFile, error)
|
|
GetMaterialByIDWithSubject(id string) (*model.MaterialFile, error)
|
|
GetMaterialsBySubject(subjectID string, page, pageSize int) ([]*model.MaterialFile, int64, error)
|
|
SearchMaterials(keyword string, page, pageSize int) ([]*model.MaterialFile, int64, error)
|
|
GetHotMaterials(limit int) ([]*model.MaterialFile, error)
|
|
GetLatestMaterials(limit int) ([]*model.MaterialFile, error)
|
|
CreateMaterial(file *model.MaterialFile) error
|
|
UpdateMaterial(file *model.MaterialFile) error
|
|
DeleteMaterial(id string) error
|
|
IncrementDownloadCount(id string) error
|
|
}
|
|
|
|
// materialServiceImpl 学习资料服务实现
|
|
type materialServiceImpl struct {
|
|
subjectRepo repository.MaterialSubjectRepository
|
|
fileRepo repository.MaterialFileRepository
|
|
}
|
|
|
|
// NewMaterialService 创建学习资料服务
|
|
func NewMaterialService(
|
|
subjectRepo repository.MaterialSubjectRepository,
|
|
fileRepo repository.MaterialFileRepository,
|
|
) MaterialService {
|
|
return &materialServiceImpl{
|
|
subjectRepo: subjectRepo,
|
|
fileRepo: fileRepo,
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// 学科相关方法
|
|
// =====================================================
|
|
|
|
func (s *materialServiceImpl) ListActiveSubjects() ([]*model.MaterialSubject, error) {
|
|
return s.subjectRepo.ListActive()
|
|
}
|
|
|
|
func (s *materialServiceImpl) ListAllSubjects() ([]*model.MaterialSubject, error) {
|
|
return s.subjectRepo.ListAll()
|
|
}
|
|
|
|
func (s *materialServiceImpl) GetSubjectByID(id string) (*model.MaterialSubject, error) {
|
|
return s.subjectRepo.GetByID(id)
|
|
}
|
|
|
|
func (s *materialServiceImpl) GetSubjectByIDWithMaterialCount(id string) (*model.MaterialSubject, int64, error) {
|
|
subject, err := s.subjectRepo.GetByID(id)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
count, err := s.subjectRepo.CountMaterials(id)
|
|
if err != nil {
|
|
return subject, 0, nil
|
|
}
|
|
return subject, count, nil
|
|
}
|
|
|
|
func (s *materialServiceImpl) CreateSubject(name, icon, color, description string, sortOrder int, isActive bool) (*model.MaterialSubject, error) {
|
|
subject := &model.MaterialSubject{
|
|
Name: name,
|
|
Icon: icon,
|
|
Color: color,
|
|
Description: description,
|
|
SortOrder: sortOrder,
|
|
IsActive: isActive,
|
|
}
|
|
if err := s.subjectRepo.Create(subject); err != nil {
|
|
return nil, err
|
|
}
|
|
return subject, nil
|
|
}
|
|
|
|
func (s *materialServiceImpl) UpdateSubject(id, name, icon, color, description string, sortOrder int, isActive bool) (*model.MaterialSubject, error) {
|
|
subject, err := s.subjectRepo.GetByID(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
subject.Name = name
|
|
subject.Icon = icon
|
|
subject.Color = color
|
|
subject.Description = description
|
|
subject.SortOrder = sortOrder
|
|
subject.IsActive = isActive
|
|
if err := s.subjectRepo.Update(subject); err != nil {
|
|
return nil, err
|
|
}
|
|
return subject, nil
|
|
}
|
|
|
|
func (s *materialServiceImpl) DeleteSubject(id string) error {
|
|
// 检查学科下是否有资料
|
|
count, err := s.subjectRepo.CountMaterials(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if count > 0 {
|
|
return ErrSubjectHasMaterials
|
|
}
|
|
return s.subjectRepo.Delete(id)
|
|
}
|
|
|
|
// =====================================================
|
|
// 资料相关方法
|
|
// =====================================================
|
|
|
|
func (s *materialServiceImpl) ListMaterials(params query.MaterialFileQueryParams) ([]*model.MaterialFile, int64, error) {
|
|
return s.fileRepo.List(params)
|
|
}
|
|
|
|
func (s *materialServiceImpl) GetMaterialByID(id string) (*model.MaterialFile, error) {
|
|
return s.fileRepo.GetByID(id)
|
|
}
|
|
|
|
func (s *materialServiceImpl) GetMaterialByIDWithSubject(id string) (*model.MaterialFile, error) {
|
|
return s.fileRepo.GetByIDWithSubject(id)
|
|
}
|
|
|
|
func (s *materialServiceImpl) GetMaterialsBySubject(subjectID string, page, pageSize int) ([]*model.MaterialFile, int64, error) {
|
|
return s.fileRepo.GetBySubjectID(subjectID, page, pageSize)
|
|
}
|
|
|
|
func (s *materialServiceImpl) SearchMaterials(keyword string, page, pageSize int) ([]*model.MaterialFile, int64, error) {
|
|
return s.fileRepo.Search(keyword, page, pageSize)
|
|
}
|
|
|
|
func (s *materialServiceImpl) GetHotMaterials(limit int) ([]*model.MaterialFile, error) {
|
|
return s.fileRepo.GetHotMaterials(limit)
|
|
}
|
|
|
|
func (s *materialServiceImpl) GetLatestMaterials(limit int) ([]*model.MaterialFile, error) {
|
|
return s.fileRepo.GetLatestMaterials(limit)
|
|
}
|
|
|
|
func (s *materialServiceImpl) CreateMaterial(file *model.MaterialFile) error {
|
|
return s.fileRepo.Create(file)
|
|
}
|
|
|
|
func (s *materialServiceImpl) UpdateMaterial(file *model.MaterialFile) error {
|
|
return s.fileRepo.Update(file)
|
|
}
|
|
|
|
func (s *materialServiceImpl) DeleteMaterial(id string) error {
|
|
return s.fileRepo.Delete(id)
|
|
}
|
|
|
|
func (s *materialServiceImpl) IncrementDownloadCount(id string) error {
|
|
return s.fileRepo.IncrementDownloadCount(id)
|
|
}
|