package sys import ( "context" "hotgo/internal/consts" "hotgo/internal/dao" "hotgo/internal/library/contexts" "hotgo/internal/library/imtenant" "hotgo/internal/model/entity" "hotgo/internal/model/input/sysin" "hotgo/internal/service" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" ) type sSysImFilePolicy struct{} func NewSysImFilePolicy() *sSysImFilePolicy { return &sSysImFilePolicy{} } func init() { service.RegisterSysImFilePolicy(NewSysImFilePolicy()) } func (s *sSysImFilePolicy) List(ctx context.Context, in *sysin.ImFilePolicyListInp) (list []*sysin.ImFilePolicyListModel, totalCount int, err error) { if err = in.Filter(ctx); err != nil { return } tenant, err := s.resolveTenant(ctx, in.TenantId) if err != nil { return } if err = s.ensureRows(ctx, tenant.Id); err != nil { return } mod := s.model(ctx).Where("tenant_id", tenant.Id) if in.Purpose != "" { mod = mod.Where("purpose", in.Purpose) } if in.AutoCleanup != nil { mod = mod.Where("auto_cleanup", *in.AutoCleanup) } if in.ScanEnabled != nil { mod = mod.Where("scan_enabled", *in.ScanEnabled) } mod = mod.Page(in.Page, in.PerPage).OrderAsc("id") if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取IM文件策略失败,请稍后重试!") return } for _, item := range list { item.TenantName = tenant.Name } return } func (s *sSysImFilePolicy) Update(ctx context.Context, in *sysin.ImFilePolicyUpdateInp) (err error) { if err = in.Filter(ctx); err != nil { return } tenant, err := s.resolveTenant(ctx, in.TenantId) if err != nil { return err } if err = s.ensureRows(ctx, tenant.Id); err != nil { return err } allowedMimes := "[]" if in.AllowedMimes != nil && in.AllowedMimes.String() != "" && in.AllowedMimes.String() != "null" { allowedMimes = in.AllowedMimes.String() } if _, err = imtenant.RegistryDB().Model("im_file_policy").Safe().Ctx(ctx). Where("tenant_id", tenant.Id). Where("purpose", in.Purpose). Data(g.Map{ "max_size": in.MaxSize, "retention_days": in.RetentionDays, "allowed_mimes": allowedMimes, "auto_cleanup": in.AutoCleanup, "scan_enabled": in.ScanEnabled, "remark": in.Remark, "updated_at": gtime.Now(), "updated_by": contexts.GetUserId(ctx), }).Update(); err != nil { return gerror.Wrap(err, "更新IM文件策略失败,请稍后重试!") } _ = writeImAdminAudit(ctx, tenant.Id, "im_file_policy_update", "im_file_policy", 0, "success", g.Map{ "purpose": in.Purpose, "auto_cleanup": in.AutoCleanup, "scan_enabled": in.ScanEnabled, }) return nil } func (s *sSysImFilePolicy) model(ctx context.Context) *gdb.Model { return imtenant.RegistryDB().Model("im_file_policy").Safe().Ctx(ctx).Fields( "id", "tenant_id", "purpose", "max_size", "retention_days", "CAST(allowed_mimes AS CHAR) allowed_mimes", "auto_cleanup", "scan_enabled", "remark", "updated_at", ) } func (s *sSysImFilePolicy) resolveTenant(ctx context.Context, selectedTenantId int64) (tenant *entity.ImTenant, err error) { scope, err := resolveImAdminScope(ctx, selectedTenantId) if err != nil { return nil, err } if err = imtenant.RegistryDB().Model(dao.ImTenant.Table()).Safe().Ctx(ctx).WherePri(scope.TenantId).Scan(&tenant); err != nil { return nil, gerror.Wrap(err, "获取IM租户失败") } if tenant == nil { return nil, gerror.New("IM租户不存在") } return tenant, nil } func (s *sSysImFilePolicy) ensureRows(ctx context.Context, tenantId int64) error { for _, item := range defaultFilePolicies() { count, err := imtenant.RegistryDB().Model("im_file_policy").Safe().Ctx(ctx). Where("tenant_id", tenantId). Where("purpose", item.Purpose). Count() if err != nil { return gerror.Wrap(err, "检查IM文件策略失败") } if count > 0 { continue } _, err = imtenant.RegistryDB().Exec(ctx, `INSERT INTO im_file_policy (tenant_id,purpose,max_size,retention_days,allowed_mimes,auto_cleanup,scan_enabled,remark,created_by,updated_by) VALUES(?,?,?,?,CAST(? AS JSON),?,?,?,?,?)`, tenantId, item.Purpose, item.MaxSize, item.RetentionDays, item.AllowedMimes, item.AutoCleanup, item.ScanEnabled, item.Remark, contexts.GetUserId(ctx), contexts.GetUserId(ctx)) if err != nil { return gerror.Wrap(err, "初始化IM文件策略失败") } } return nil } type filePolicySeed struct { Purpose string MaxSize int64 RetentionDays int AllowedMimes string AutoCleanup int ScanEnabled int Remark string } func defaultFilePolicies() []*filePolicySeed { const mb = 1024 * 1024 return []*filePolicySeed{ {Purpose: consts.ImFilePurposeChat, MaxSize: 100 * mb, RetentionDays: 365, AllowedMimes: "[]", AutoCleanup: 0, ScanEnabled: 0, Remark: "聊天附件默认策略"}, {Purpose: consts.ImFilePurposeUserAvatar, MaxSize: 5 * mb, RetentionDays: 0, AllowedMimes: `["image/jpeg","image/png","image/webp"]`, AutoCleanup: 0, ScanEnabled: 0, Remark: "用户头像长期保留"}, {Purpose: consts.ImFilePurposeGroupAvatar, MaxSize: 5 * mb, RetentionDays: 0, AllowedMimes: `["image/jpeg","image/png","image/webp"]`, AutoCleanup: 0, ScanEnabled: 0, Remark: "群头像长期保留"}, {Purpose: consts.ImFilePurposeGroupFile, MaxSize: 200 * mb, RetentionDays: 365, AllowedMimes: "[]", AutoCleanup: 0, ScanEnabled: 0, Remark: "群文件默认策略"}, {Purpose: consts.ImFilePurposeAbuseEvidence, MaxSize: 50 * mb, RetentionDays: 730, AllowedMimes: "[]", AutoCleanup: 0, ScanEnabled: 0, Remark: "举报证据默认策略"}, {Purpose: consts.ImFilePurposeFeedback, MaxSize: 50 * mb, RetentionDays: 365, AllowedMimes: "[]", AutoCleanup: 0, ScanEnabled: 0, Remark: "反馈附件默认策略"}, } }