Files
backend/internal/repository/material_repo.go
lan d9aa4b46c3
All checks were successful
Build Backend / build (push) Successful in 4m55s
Build Backend / build-docker (push) Successful in 10m34s
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.
2026-06-15 03:41:59 +08:00

264 lines
7.7 KiB
Go
Raw Permalink 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 repository
import (
"with_you/internal/model"
"with_you/internal/pkg/utils"
"with_you/internal/query"
"gorm.io/gorm"
)
// MaterialSubjectRepository 学科分类仓储接口
type MaterialSubjectRepository interface {
ListActive() ([]*model.MaterialSubject, error)
ListAll() ([]*model.MaterialSubject, error)
GetByID(id string) (*model.MaterialSubject, error)
Create(subject *model.MaterialSubject) error
Update(subject *model.MaterialSubject) error
Delete(id string) error
CountMaterials(subjectID string) (int64, error)
}
// materialSubjectRepository 学科分类仓储实现
type materialSubjectRepository struct {
db *gorm.DB
}
func NewMaterialSubjectRepository(db *gorm.DB) MaterialSubjectRepository {
return &materialSubjectRepository{db: db}
}
// ListActive 获取所有启用的学科分类
func (r *materialSubjectRepository) ListActive() ([]*model.MaterialSubject, error) {
var subjects []*model.MaterialSubject
err := r.db.
Where("is_active = ?", true).
Order("sort_order ASC, created_at ASC").
Find(&subjects).Error
return subjects, err
}
// ListAll 获取所有学科分类(管理端用)
func (r *materialSubjectRepository) ListAll() ([]*model.MaterialSubject, error) {
var subjects []*model.MaterialSubject
err := r.db.
Order("sort_order ASC, created_at ASC").
Find(&subjects).Error
return subjects, err
}
// GetByID 根据ID获取学科分类
func (r *materialSubjectRepository) GetByID(id string) (*model.MaterialSubject, error) {
var subject model.MaterialSubject
if err := r.db.First(&subject, "id = ?", id).Error; err != nil {
return nil, err
}
return &subject, nil
}
// Create 创建学科分类
func (r *materialSubjectRepository) Create(subject *model.MaterialSubject) error {
return r.db.Create(subject).Error
}
// Update 更新学科分类
func (r *materialSubjectRepository) Update(subject *model.MaterialSubject) error {
return r.db.Save(subject).Error
}
// Delete 删除学科分类
func (r *materialSubjectRepository) Delete(id string) error {
return r.db.Delete(&model.MaterialSubject{}, "id = ?", id).Error
}
// CountMaterials 统计学科下的资料数量
func (r *materialSubjectRepository) CountMaterials(subjectID string) (int64, error) {
var count int64
err := r.db.Model(&model.MaterialFile{}).Where("subject_id = ?", subjectID).Count(&count).Error
return count, err
}
// MaterialFileRepository 文件资料仓储接口
type MaterialFileRepository interface {
List(params query.MaterialFileQueryParams) ([]*model.MaterialFile, int64, error)
GetByID(id string) (*model.MaterialFile, error)
GetByIDWithSubject(id string) (*model.MaterialFile, error)
Create(file *model.MaterialFile) error
Update(file *model.MaterialFile) error
Delete(id string) error
IncrementDownloadCount(id string) error
GetBySubjectID(subjectID string, page, pageSize int) ([]*model.MaterialFile, int64, error)
Search(keyword string, page, pageSize int) ([]*model.MaterialFile, int64, error)
GetHotMaterials(limit int) ([]*model.MaterialFile, error)
GetLatestMaterials(limit int) ([]*model.MaterialFile, error)
}
// materialFileRepository 文件资料仓储实现
type materialFileRepository struct {
db *gorm.DB
}
func NewMaterialFileRepository(db *gorm.DB) MaterialFileRepository {
return &materialFileRepository{db: db}
}
// List 获取资料列表(支持筛选和分页)
func (r *materialFileRepository) List(params query.MaterialFileQueryParams) ([]*model.MaterialFile, int64, error) {
var files []*model.MaterialFile
var total int64
query := r.db.Model(&model.MaterialFile{})
// 筛选条件
if params.SubjectID != "" {
query = query.Where("subject_id = ?", params.SubjectID)
}
if params.FileType != "" {
query = query.Where("file_type = ?", params.FileType)
}
if params.Status != "" {
query = query.Where("status = ?", params.Status)
}
if params.Keyword != "" {
keyword := "%" + utils.EscapeLikeWildcard(params.Keyword) + "%"
query = query.Where("title LIKE ? OR description LIKE ?", keyword, keyword)
}
// 统计总数
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
// 排序
sortBy := params.SortBy
if sortBy == "" {
sortBy = "created_at"
}
sortOrder := params.SortOrder
if sortOrder == "" {
sortOrder = "DESC"
}
orderClause := sortBy + " " + sortOrder
// 分页
page := params.Page
if page < 1 {
page = 1
}
pageSize := params.PageSize
if pageSize < 1 {
pageSize = 20
}
offset := (page - 1) * pageSize
// 查询
if err := query.Order(orderClause).Offset(offset).Limit(pageSize).Find(&files).Error; err != nil {
return nil, 0, err
}
return files, total, nil
}
// GetByID 根据ID获取资料详情
func (r *materialFileRepository) GetByID(id string) (*model.MaterialFile, error) {
var file model.MaterialFile
if err := r.db.First(&file, "id = ?", id).Error; err != nil {
return nil, err
}
return &file, nil
}
// GetByIDWithSubject 根据ID获取资料详情包含学科信息
func (r *materialFileRepository) GetByIDWithSubject(id string) (*model.MaterialFile, error) {
var file model.MaterialFile
if err := r.db.Preload("Subject").First(&file, "id = ?", id).Error; err != nil {
return nil, err
}
return &file, nil
}
// Create 创建资料
func (r *materialFileRepository) Create(file *model.MaterialFile) error {
return r.db.Create(file).Error
}
// Update 更新资料
func (r *materialFileRepository) Update(file *model.MaterialFile) error {
return r.db.Save(file).Error
}
// Delete 删除资料
func (r *materialFileRepository) Delete(id string) error {
return r.db.Delete(&model.MaterialFile{}, "id = ?", id).Error
}
// IncrementDownloadCount 增加下载次数
func (r *materialFileRepository) IncrementDownloadCount(id string) error {
return r.db.Model(&model.MaterialFile{}).Where("id = ?", id).
UpdateColumn("download_count", gorm.Expr("download_count + ?", 1)).Error
}
// GetBySubjectID 根据学科ID获取资料列表
func (r *materialFileRepository) GetBySubjectID(subjectID string, page, pageSize int) ([]*model.MaterialFile, int64, error) {
var files []*model.MaterialFile
var total int64
query := r.db.Model(&model.MaterialFile{}).Where("subject_id = ? AND status = ?", subjectID, model.MaterialStatusActive)
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
if err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&files).Error; err != nil {
return nil, 0, err
}
return files, total, nil
}
// Search 搜索资料
func (r *materialFileRepository) Search(keyword string, page, pageSize int) ([]*model.MaterialFile, int64, error) {
var files []*model.MaterialFile
var total int64
query := r.db.Model(&model.MaterialFile{}).Where("status = ?", model.MaterialStatusActive)
if keyword != "" {
kw := "%" + utils.EscapeLikeWildcard(keyword) + "%"
query = query.Where("title LIKE ? OR description LIKE ?", kw, kw)
}
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * pageSize
if err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&files).Error; err != nil {
return nil, 0, err
}
return files, total, nil
}
// GetHotMaterials 获取热门资料(按下载次数排序)
func (r *materialFileRepository) GetHotMaterials(limit int) ([]*model.MaterialFile, error) {
var files []*model.MaterialFile
err := r.db.
Where("status = ?", model.MaterialStatusActive).
Order("download_count DESC").
Limit(limit).
Find(&files).Error
return files, err
}
// GetLatestMaterials 获取最新资料
func (r *materialFileRepository) GetLatestMaterials(limit int) ([]*model.MaterialFile, error) {
var files []*model.MaterialFile
err := r.db.
Where("status = ?", model.MaterialStatusActive).
Order("created_at DESC").
Limit(limit).
Find(&files).Error
return files, err
}