Files
mailgo/internal/store/mail_store.go
T
2026-06-01 19:46:51 +08:00

221 lines
7.0 KiB
Go

package store
import (
"errors"
"time"
"mail_go/internal/db"
"gorm.io/gorm"
)
// Common store errors
var (
ErrInvalidEmail = errors.New("无效的邮箱地址格式")
ErrInvalidCredentials = errors.New("用户名或密码错误")
ErrUserInactive = errors.New("用户已被禁用")
ErrRecordNotFound = errors.New("记录不存在")
)
// MailStore defines the interface for mail message operations.
type MailStore interface {
Create(msg *db.Message) error
GetByID(id uint) (*db.Message, error)
ListByUserAndFolder(userID uint, folder string, page, size int) ([]db.Message, int64, error)
ListAllByUserAndFolder(userID uint, folder string) ([]db.Message, error)
CountByUserAndFolder(userID uint, folder string) (int64, error)
MarkRead(id uint) error
MarkFlagged(id uint, flagged bool) error
MoveToFolder(id uint, folder string) error
Delete(id uint) error
CountUnread(userID uint, folder string) (int64, error)
CountByFolder(folder string) (int64, error)
CountAll() (int64, error)
TotalSizeByFolder(folder string) (int64, error)
TotalSize() (int64, error)
CountByFolderSince(folder string, since time.Time) (int64, error)
ListAll(page, size int) ([]db.Message, int64, error)
ListAllByFolder(folder string, page, size int) ([]db.Message, int64, error)
}
// mailStoreGorm implements MailStore using GORM.
type mailStoreGorm struct {
db *gorm.DB
}
// newMailStore creates a new GORM-backed MailStore.
func newMailStore(database *gorm.DB) MailStore {
return &mailStoreGorm{db: database}
}
// Create inserts a new message record.
func (s *mailStoreGorm) Create(msg *db.Message) error {
return s.db.Create(msg).Error
}
// GetByID retrieves a message by primary key.
func (s *mailStoreGorm) GetByID(id uint) (*db.Message, error) {
var msg db.Message
if err := s.db.First(&msg, id).Error; err != nil {
return nil, err
}
return &msg, nil
}
// ListByUserAndFolder retrieves a paginated list of messages for a user and folder.
func (s *mailStoreGorm) ListByUserAndFolder(userID uint, folder string, page, size int) ([]db.Message, int64, error) {
var messages []db.Message
var total int64
query := s.db.Where("user_id = ? AND folder = ?", userID, folder)
if err := query.Model(&db.Message{}).Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * size
if err := query.Order("date DESC").Offset(offset).Limit(size).Find(&messages).Error; err != nil {
return nil, 0, err
}
return messages, total, nil
}
// MarkRead sets the IsRead flag to true for a message.
func (s *mailStoreGorm) MarkRead(id uint) error {
return s.db.Model(&db.Message{}).Where("id = ?", id).Update("is_read", true).Error
}
// MarkFlagged sets the IsFlagged flag for a message.
func (s *mailStoreGorm) MarkFlagged(id uint, flagged bool) error {
return s.db.Model(&db.Message{}).Where("id = ?", id).Update("is_flagged", flagged).Error
}
// MoveToFolder changes the folder of a message.
func (s *mailStoreGorm) MoveToFolder(id uint, folder string) error {
return s.db.Model(&db.Message{}).Where("id = ?", id).Update("folder", folder).Error
}
// Delete removes a message by ID.
func (s *mailStoreGorm) Delete(id uint) error {
return s.db.Delete(&db.Message{}, id).Error
}
// CountUnread returns the count of unread messages for a user in a folder.
func (s *mailStoreGorm) CountUnread(userID uint, folder string) (int64, error) {
var count int64
if err := s.db.Model(&db.Message{}).
Where("user_id = ? AND folder = ? AND is_read = ?", userID, folder, false).
Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
// ListAllByUserAndFolder retrieves all messages for a user in a folder without pagination.
// Messages are ordered by ID ascending so that sequence numbers are stable.
func (s *mailStoreGorm) ListAllByUserAndFolder(userID uint, folder string) ([]db.Message, error) {
var messages []db.Message
if err := s.db.Where("user_id = ? AND folder = ?", userID, folder).
Order("id ASC").Find(&messages).Error; err != nil {
return nil, err
}
return messages, nil
}
// CountByUserAndFolder returns the total count of messages for a user in a folder.
func (s *mailStoreGorm) CountByUserAndFolder(userID uint, folder string) (int64, error) {
var count int64
if err := s.db.Model(&db.Message{}).
Where("user_id = ? AND folder = ?", userID, folder).
Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
// CountByFolder returns the total count of messages in a given folder.
func (s *mailStoreGorm) CountByFolder(folder string) (int64, error) {
var count int64
if err := s.db.Model(&db.Message{}).Where("folder = ?", folder).Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
// CountAll returns the total count of all messages.
func (s *mailStoreGorm) CountAll() (int64, error) {
var count int64
if err := s.db.Model(&db.Message{}).Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
// TotalSizeByFolder returns the total size (in bytes) of message bodies in a given folder.
func (s *mailStoreGorm) TotalSizeByFolder(folder string) (int64, error) {
var total int64
err := s.db.Model(&db.Message{}).
Where("folder = ?", folder).
Select("COALESCE(SUM(LENGTH(text_body) + LENGTH(html_body)), 0)").
Scan(&total).Error
if err != nil {
return 0, err
}
return total, nil
}
// TotalSize returns the total size (in bytes) of all message bodies.
func (s *mailStoreGorm) TotalSize() (int64, error) {
var total int64
err := s.db.Model(&db.Message{}).
Select("COALESCE(SUM(LENGTH(text_body) + LENGTH(html_body)), 0)").
Scan(&total).Error
if err != nil {
return 0, err
}
return total, nil
}
// CountByFolderSince returns the count of messages in a folder since a given time.
func (s *mailStoreGorm) CountByFolderSince(folder string, since time.Time) (int64, error) {
var count int64
if err := s.db.Model(&db.Message{}).
Where("folder = ? AND created_at >= ?", folder, since).
Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
// ListAll retrieves a paginated list of all messages across all users.
func (s *mailStoreGorm) ListAll(page, size int) ([]db.Message, int64, error) {
var messages []db.Message
var total int64
if err := s.db.Model(&db.Message{}).Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * size
if err := s.db.Preload("User").Order("date DESC").Offset(offset).Limit(size).Find(&messages).Error; err != nil {
return nil, 0, err
}
return messages, total, nil
}
// ListAllByFolder retrieves a paginated list of all messages in a given folder across all users.
func (s *mailStoreGorm) ListAllByFolder(folder string, page, size int) ([]db.Message, int64, error) {
var messages []db.Message
var total int64
query := s.db.Where("folder = ?", folder)
if err := query.Model(&db.Message{}).Count(&total).Error; err != nil {
return nil, 0, err
}
offset := (page - 1) * size
if err := s.db.Preload("User").Where("folder = ?", folder).Order("date DESC").Offset(offset).Limit(size).Find(&messages).Error; err != nil {
return nil, 0, err
}
return messages, total, nil
}