Smail/server/services/list/list.go
Jinnrry e194d6ecfd
feature/v2.8.3 (#269)
1.优化垃圾邮件处理
2.升级所有依赖,go版本升级到1.24
2025-04-20 09:59:56 +08:00

257 lines
8.1 KiB
Go

package list
import (
"fmt"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"strings"
)
import . "xorm.io/builder"
func GetEmailList(ctx *context.Context, tagInfo dto.SearchTag, keyword string, pop3List bool, offset, limit int) (emailList []*response.EmailResponseData, total int64) {
return getList(ctx, tagInfo, keyword, pop3List, offset, limit)
}
func getList(ctx *context.Context, tagInfo dto.SearchTag, keyword string, pop3List bool, offset, limit int) (emailList []*response.EmailResponseData, total int64) {
querySQL, queryParams := genSQL(ctx, false, tagInfo, keyword, pop3List, offset, limit)
err := db.Instance.SQL(querySQL, queryParams...).Find(&emailList)
if err != nil {
log.WithContext(ctx).Errorf("SQL ERROR: %s ,Error:%s", querySQL, err)
}
totalSQL, totalParams := genSQL(ctx, true, tagInfo, keyword, pop3List, offset, limit)
_, err = db.Instance.SQL(totalSQL, totalParams...).Get(&total)
if err != nil {
log.WithContext(ctx).Errorf("SQL ERROR: %s ,Error:%s", querySQL, err)
}
return emailList, total
}
func genSQL(ctx *context.Context, count bool, tagInfo dto.SearchTag, keyword string, pop3List bool, offset, limit int) (string, []any) {
sqlParams := []any{ctx.UserID}
sql := "select "
if count {
sql += `count(1) from email e left join user_email ue on e.id=ue.email_id where ue.user_id = ? `
} else if pop3List {
sql += `e.id,e.size from email e left join user_email ue on e.id=ue.email_id where ue.user_id = ? `
} else {
sql += `e.*,ue.is_read from email e left join user_email ue on e.id=ue.email_id where ue.user_id = ? `
}
if tagInfo.Status != -1 {
sql += " and ue.status =? "
sqlParams = append(sqlParams, tagInfo.Status)
} else if tagInfo.Status == -1 {
sql += " and ue.status = 0"
}
if tagInfo.Type != -1 {
sql += " and type =? "
sqlParams = append(sqlParams, tagInfo.Type)
}
if tagInfo.GroupId != -1 {
sql += " and ue.group_id=? "
sqlParams = append(sqlParams, tagInfo.GroupId)
} else {
sql += " and ue.group_id=0 "
}
if keyword != "" {
sql += " and (subject like ? or text like ? )"
sqlParams = append(sqlParams, "%"+keyword+"%", "%"+keyword+"%")
}
if limit == 0 {
limit = 10
}
sql += " order by e.id desc"
if limit < 10000 {
sql += fmt.Sprintf(" LIMIT %d OFFSET %d ", limit, offset)
}
return sql, sqlParams
}
type statRes struct {
Total int64
Size int64
}
// Stat 查询邮件总数和大小
func Stat(ctx *context.Context) (int64, int64) {
sql := `select count(1) as total,sum(size) as size from email e left join user_email ue on e.id=ue.email_id where ue.user_id = ? and e.type = 0 and ue.status != 3`
var ret statRes
_, err := db.Instance.SQL(sql, ctx.UserID).Get(&ret)
if err != nil {
log.WithContext(ctx).Errorf("SQL ERROR: %s ,Error:%s", sql, err)
}
return ret.Total, ret.Size
}
type ImapListReq struct {
UidList []int
Star int
End int
}
func GetUEListByUID(ctx *context.Context, groupName string, star, end int, uidList []int) []*response.UserEmailUIDData {
var ue []*response.UserEmailUIDData
sql := "SELECT id,email_id, is_read, ROW_NUMBER() OVER (ORDER BY id) AS serial_number FROM `user_email` WHERE user_id = ? "
params := []any{ctx.UserID}
if len(uidList) > 0 {
sql += fmt.Sprintf(" and id in (%s)", array.Join(uidList, ","))
}
if star > 0 {
sql += " and id >=?"
params = append(params, star)
}
if end > 0 {
sql += " and id <=?"
params = append(params, end)
}
switch groupName {
case "INBOX":
sql += " and status =?"
params = append(params, 0)
case "Sent Messages":
sql += " and status =?"
params = append(params, 1)
case "Drafts":
sql += " and status =?"
params = append(params, 4)
case "Deleted Messages":
sql += " and status =?"
params = append(params, 3)
case "Junk":
sql += " and status =?"
params = append(params, 5)
default:
groupNames := strings.Split(groupName, "/")
groupName = groupNames[len(groupNames)-1]
var group models.Group
db.Instance.Table("group").Where("user_id=? and name=?", ctx.UserID, groupName).Get(&group)
if group.ID == 0 {
return nil
}
sql += " and group_id = ?"
params = append(params, group.ID)
}
db.Instance.SQL(sql, params...).Find(&ue)
return ue
}
func getEmailListByUidList(ctx *context.Context, groupName string, req ImapListReq, uid bool) []*response.EmailResponseData {
var ret []*response.EmailResponseData
var ue []*response.UserEmailUIDData
sql := fmt.Sprintf("SELECT id,email_id, is_read, ROW_NUMBER() OVER (ORDER BY id) AS serial_number FROM `user_email` WHERE (user_id = ? and id in (%s))", array.Join(req.UidList, ","))
if req.Star > 0 && req.End != 0 {
sql = fmt.Sprintf("SELECT id,email_id, is_read, ROW_NUMBER() OVER (ORDER BY id) AS serial_number FROM `user_email` WHERE (user_id = ? and id >=%d and id <= %d)", req.Star, req.End)
}
if req.Star > 0 && req.End == 0 {
sql = fmt.Sprintf("SELECT id,email_id, is_read, ROW_NUMBER() OVER (ORDER BY id) AS serial_number FROM `user_email` WHERE (user_id = ? and id >=%d )", req.Star)
}
err := db.Instance.SQL(sql, ctx.UserID).Find(&ue)
if err != nil {
log.WithContext(ctx).Errorf("SQL ERROR: %s ,Error:%s", sql, err)
}
ueMap := map[int]*response.UserEmailUIDData{}
var emailIds []int
for _, email := range ue {
ueMap[email.EmailID] = email
emailIds = append(emailIds, email.EmailID)
}
_ = db.Instance.Table("email").Select("*").Where(Eq{"id": emailIds}).Find(&ret)
for i, data := range ret {
ret[i].IsRead = ueMap[data.Id].IsRead
ret[i].SerialNumber = ueMap[data.Id].SerialNumber
ret[i].UeId = ueMap[data.Id].ID
}
return ret
}
func GetEmailListByGroup(ctx *context.Context, groupName string, req ImapListReq, uid bool) []*response.EmailResponseData {
if len(req.UidList) == 0 && req.Star == 0 && req.End == 0 {
return nil
}
if uid {
return getEmailListByUidList(ctx, groupName, req, uid)
}
var ret []*response.EmailResponseData
var ue []*response.UserEmailUIDData
sql := fmt.Sprintf("SELECT * from (SELECT id,email_id, is_read, ROW_NUMBER() OVER (ORDER BY id) AS serial_number FROM `user_email` WHERE (user_id = ? and status = ? and group_id=0 )) a WHERE serial_number in (%s)", array.Join(req.UidList, ","))
if req.Star > 0 && req.End == 0 {
sql = fmt.Sprintf("SELECT * from (SELECT id,email_id, is_read, ROW_NUMBER() OVER (ORDER BY id) AS serial_number FROM `user_email` WHERE (user_id = ? and status = ? and group_id=0 )) a WHERE serial_number >= %d", req.Star)
}
if req.Star > 0 && req.End > 0 {
sql = fmt.Sprintf("SELECT * from (SELECT id,email_id, is_read, ROW_NUMBER() OVER (ORDER BY id) AS serial_number FROM `user_email` WHERE (user_id = ? and status = ? and group_id=0 )) a WHERE serial_number >= %d and serial_number <=%d", req.Star, req.End)
}
switch groupName {
case "INBOX":
db.Instance.SQL(sql, ctx.UserID, 0).Find(&ue)
case "Sent Messages":
db.Instance.SQL(sql, ctx.UserID, 1).Find(&ue)
case "Drafts":
db.Instance.SQL(sql, ctx.UserID, 4).Find(&ue)
case "Deleted Messages":
db.Instance.SQL(sql, ctx.UserID, 3).Find(&ue)
case "Junk":
db.Instance.SQL(sql, ctx.UserID, 5).Find(&ue)
default:
groupNames := strings.Split(groupName, "/")
groupName = groupNames[len(groupNames)-1]
var group models.Group
db.Instance.Table("group").Where("user_id=? and name=?", ctx.UserID, groupName).Get(&group)
if group.ID == 0 {
return ret
}
db.Instance.
SQL(fmt.Sprintf(
"SELECT * from (SELECT id,email_id, is_read, ROW_NUMBER() OVER (ORDER BY id) AS serial_number FROM `user_email` WHERE (user_id = ? and group_id = ?)) a WHERE serial_number in (%s)",
array.Join(req.UidList, ","))).
Find(&ue, ctx.UserID, group.ID)
}
ueMap := map[int]*response.UserEmailUIDData{}
var emailIds []int
for _, email := range ue {
ueMap[email.EmailID] = email
emailIds = append(emailIds, email.EmailID)
}
_ = db.Instance.Table("email").Select("*").Where(Eq{"id": emailIds}).Find(&ret)
for i, data := range ret {
ret[i].IsRead = ueMap[data.Id].IsRead
ret[i].SerialNumber = ueMap[data.Id].SerialNumber
ret[i].UeId = ueMap[data.Id].ID
}
return ret
}