spark-server/internal/module/group/model/group.go
2026-09-23 17:11:56 +08:00

195 lines
5.4 KiB
Go
Raw 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 model
import (
"context"
"time"
"spark-server/internal/module/group/entity"
"spark-server/internal/pkg/errs"
)
// Group maps table t_groups.
type Group struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement;comment:群号,表内自增,对外群 ID"`
ConversationID int64 `gorm:"column:conversation_id;uniqueIndex;comment:对应 t_conversations.id(Snowflake),发消息与同步用"`
Name string `gorm:"column:name;comment:群名称"`
Avatar string `gorm:"column:avatar;comment:群头像对象存储 key,空表示未设置"`
Announcement string `gorm:"column:announcement;comment:群公告,仅群主/管理员可改"`
OwnerID int64 `gorm:"column:owner_id;comment:群主 user_id"`
MutedAll int `gorm:"column:muted_all;comment:0=未全员禁言 1=全员禁言(群主/管理员仍可发言)"`
MemberCount int `gorm:"column:member_count;comment:当前成员数,含群主"`
Status int `gorm:"column:status;comment:1=正常 2=已解散"`
CreatedAt time.Time `gorm:"column:created_at;comment:创建时间"`
UpdatedAt time.Time `gorm:"column:updated_at;comment:资料或成员变更时间"`
}
func (Group) TableName() string { return "t_groups" }
func (r *Group) entity() *entity.Group {
if r == nil {
return nil
}
g := &entity.Group{
ID: r.ID, ConversationID: r.ConversationID, Name: r.Name, Avatar: r.Avatar, Announcement: r.Announcement, OwnerID: r.OwnerID,
MemberCount: r.MemberCount, Status: entity.Status(r.Status),
CreatedAtMS: r.CreatedAt.UnixMilli(), UpdatedAtMS: r.UpdatedAt.UnixMilli(),
}
g.MutedAll = r.MutedAll != 0
return g
}
func groupRow(g *entity.Group) *Group {
now := msTime(g.CreatedAtMS)
updated := msTime(g.UpdatedAtMS)
if g.UpdatedAtMS <= 0 {
updated = now
}
row := &Group{
ID: g.ID, ConversationID: g.ConversationID, Name: g.Name, Avatar: g.Avatar, Announcement: g.Announcement, OwnerID: g.OwnerID,
MemberCount: g.MemberCount, Status: int(g.Status),
CreatedAt: now, UpdatedAt: updated,
}
if g.MutedAll {
row.MutedAll = 1
}
if row.Status == 0 {
row.Status = int(entity.StatusActive)
}
return row
}
func (m *Repo) Get(ctx context.Context, id int64) (*entity.Group, error) {
if id <= 0 {
return nil, errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return nil, err
}
var row Group
if err := db.Where("id = ?", id).Take(&row).Error; err != nil {
return nil, mapDBErr(err)
}
return row.entity(), nil
}
func (m *Repo) GetByConversation(ctx context.Context, conversationID int64) (*entity.Group, error) {
if conversationID <= 0 {
return nil, errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return nil, err
}
var row Group
if err := db.Where("conversation_id = ?", conversationID).Take(&row).Error; err != nil {
return nil, mapDBErr(err)
}
return row.entity(), nil
}
func (m *Repo) ListByUser(ctx context.Context, userID int64, limit int) ([]*entity.Group, error) {
if userID <= 0 {
return nil, errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return nil, err
}
limit = entity.ClampLimit(limit)
var rows []Group
err = db.Table("`t_groups` AS g").Select("g.*").
Joins("INNER JOIN t_group_members m ON m.group_id = g.id").
Where("m.user_id = ? AND g.status = ?", userID, entity.StatusActive).
Order("g.updated_at DESC").Limit(limit).Find(&rows).Error
if err != nil {
return nil, mapDBErr(err)
}
out := make([]*entity.Group, 0, len(rows))
for i := range rows {
out = append(out, rows[i].entity())
}
return out, nil
}
const purgeListCap = 10000
func (m *Repo) ListAllActiveByUser(ctx context.Context, userID int64) ([]*entity.Group, error) {
if userID <= 0 {
return nil, errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return nil, err
}
var rows []Group
err = db.Table("`t_groups` AS g").Select("g.*").
Joins("INNER JOIN t_group_members m ON m.group_id = g.id").
Where("m.user_id = ? AND g.status = ?", userID, entity.StatusActive).
Order("g.updated_at DESC").Limit(purgeListCap).Find(&rows).Error
if err != nil {
return nil, mapDBErr(err)
}
out := make([]*entity.Group, 0, len(rows))
for i := range rows {
out = append(out, rows[i].entity())
}
return out, nil
}
func (m *Repo) UpdateProfile(ctx context.Context, g *entity.Group) error {
if g == nil || g.ID <= 0 {
return errs.ErrInvalidArgument
}
db, err := m.session(ctx)
if err != nil {
return err
}
res := db.Model(&Group{}).Where("id = ? AND status = ?", g.ID, entity.StatusActive).Updates(map[string]any{
"name": g.Name,
"avatar": g.Avatar,
"announcement": g.Announcement,
"muted_all": boolInt(g.MutedAll),
"updated_at": msTime(g.UpdatedAtMS),
})
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
return nil
}
func (m *Repo) UpdateLastMsg(ctx context.Context, conversationID, msgID, atMS int64) error {
db, err := m.session(ctx)
if err != nil {
return err
}
res := db.Table("t_conversations").Where("id = ?", conversationID).Updates(map[string]any{
"last_msg_id": msgID,
"last_msg_at": msTime(atMS),
})
if res.Error != nil {
return mapDBErr(res.Error)
}
if res.RowsAffected == 0 {
return errs.ErrNotFound
}
return nil
}
func msTime(ms int64) time.Time {
if ms <= 0 {
return time.Now()
}
return time.UnixMilli(ms)
}
func boolInt(v bool) int {
if v {
return 1
}
return 0
}