Files
im_manager/server/internal/logic/sys/im_invite.go
T

316 lines
9.9 KiB
Go

package sys
import (
"context"
"fmt"
"hotgo/internal/library/imadmin"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"io"
"strconv"
"time"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
)
type sSysImInvite struct{}
func NewSysImInvite() *sSysImInvite {
return &sSysImInvite{}
}
func init() {
service.RegisterSysImInvite(NewSysImInvite())
}
type imInviteListRequest struct {
Page int `json:"page,omitempty"`
PerPage int `json:"per_page,omitempty"`
InviteCode string `json:"invite_code,omitempty"`
Status string `json:"status,omitempty"`
BatchID int64 `json:"batch_id,omitempty"`
CreatedBy int64 `json:"created_by,omitempty"`
CreatedAtStart string `json:"created_at_start,omitempty"`
CreatedAtEnd string `json:"created_at_end,omitempty"`
ExpiresAtStart string `json:"expires_at_start,omitempty"`
ExpiresAtEnd string `json:"expires_at_end,omitempty"`
}
type imInviteCreateRequest struct {
ExpiresAt string `json:"expires_at"`
Remark string `json:"remark,omitempty"`
IdempotencyKey string `json:"idempotency_key,omitempty"`
}
type imInviteBatchCreateRequest struct {
Quantity int `json:"quantity"`
ExpiresAt string `json:"expires_at"`
Remark string `json:"remark,omitempty"`
IdempotencyKey string `json:"idempotency_key,omitempty"`
}
type imInviteCodeResponse struct {
ID int64 `json:"id"`
BatchID *int64 `json:"batch_id"`
Code string `json:"code"`
Status string `json:"status"`
ExpiresAt *time.Time `json:"expires_at"`
UsedBy *int64 `json:"used_by"`
UsedAt *time.Time `json:"used_at"`
RequestID string `json:"request_id"`
CreatedBy int64 `json:"created_by"`
Remark string `json:"remark"`
CreatedAt *time.Time `json:"created_at"`
}
type imInviteBatchResponse struct {
BatchID int64 `json:"batch_id"`
Quantity int `json:"quantity"`
ActiveCount int `json:"active_count"`
UsedCount int `json:"used_count"`
RevokedCount int `json:"revoked_count"`
ExpiredCount int `json:"expired_count"`
ExpiresAt *time.Time `json:"expires_at"`
CreatedAt *time.Time `json:"created_at"`
}
func (s *sSysImInvite) List(ctx context.Context, in *sysin.ImInviteListInp) (list []*sysin.ImInviteCodeModel, totalCount int, err error) {
if err = in.Filter(ctx); err != nil {
return
}
scope, err := resolveImAdminScope(ctx, in.TenantId)
if err != nil {
return
}
req, err := buildInviteListRequest(in)
if err != nil {
return
}
var page imadmin.Page[imInviteCodeResponse]
if err = imadmin.DefaultClient(ctx).ListCodes(ctx, scope, req, &page); err != nil {
_ = writeImAdminAudit(ctx, scope.TenantId, "invite_list", "invite_code", 0, "failed", g.Map{"hasInviteCode": in.InviteCode != ""})
return
}
_ = writeImAdminAudit(ctx, scope.TenantId, "invite_list", "invite_code", 0, "success", g.Map{"hasInviteCode": in.InviteCode != ""})
list = make([]*sysin.ImInviteCodeModel, 0, len(page.Items))
for i := range page.Items {
list = append(list, convertInviteCode(page.Items[i]))
}
totalCount = page.Total
return
}
func (s *sSysImInvite) Create(ctx context.Context, in *sysin.ImInviteCreateInp) (res *sysin.ImInviteCodeModel, err error) {
if err = in.Filter(ctx); err != nil {
return
}
scope, err := resolveImAdminScope(ctx, in.TenantId)
if err != nil {
return
}
req := imInviteCreateRequest{ExpiresAt: formatRFC3339(in.ExpiresAt), Remark: in.Remark, IdempotencyKey: in.IdempotencyKey}
var upstream imInviteCodeResponse
err = imadmin.DefaultClient(ctx).CreateCode(ctx, scope, req, &upstream)
res = convertInviteCode(upstream)
result := "success"
if err != nil {
result = "failed"
}
targetId, _ := strconv.ParseInt(res.Id, 10, 64)
_ = writeImAdminAudit(ctx, scope.TenantId, "invite_create", "invite_code", targetId, result, g.Map{"expiresAt": in.ExpiresAt, "remark": in.Remark})
return
}
func (s *sSysImInvite) BatchCreate(ctx context.Context, in *sysin.ImInviteBatchCreateInp) (res *sysin.ImInviteBatchModel, err error) {
if err = in.Filter(ctx); err != nil {
return
}
scope, err := resolveImAdminScope(ctx, in.TenantId)
if err != nil {
return
}
req := imInviteBatchCreateRequest{Quantity: in.Quantity, ExpiresAt: formatRFC3339(in.ExpiresAt), Remark: in.Remark, IdempotencyKey: in.IdempotencyKey}
var upstream imInviteBatchResponse
err = imadmin.DefaultClient(ctx).CreateBatch(ctx, scope, req, &upstream)
res = convertInviteBatch(upstream)
result := "success"
if err != nil {
result = "failed"
}
targetId, _ := strconv.ParseInt(res.BatchId, 10, 64)
_ = writeImAdminAudit(ctx, scope.TenantId, "invite_batch_create", "invite_batch", targetId, result, g.Map{"quantity": in.Quantity, "expiresAt": in.ExpiresAt, "remark": in.Remark})
return
}
func (s *sSysImInvite) BatchView(ctx context.Context, in *sysin.ImInviteBatchViewInp) (res *sysin.ImInviteBatchDetailModel, err error) {
scope, err := resolveImAdminScope(ctx, in.TenantId)
if err != nil {
return
}
batchId, err := sysin.ParseOptionalInt64(in.BatchId)
if err != nil {
return
}
var upstream imInviteBatchResponse
err = imadmin.DefaultClient(ctx).GetBatch(ctx, scope, batchId, &upstream)
res = &sysin.ImInviteBatchDetailModel{ImInviteBatchModel: *convertInviteBatch(upstream)}
return
}
func (s *sSysImInvite) Revoke(ctx context.Context, in *sysin.ImInviteRevokeInp) (err error) {
scope, err := resolveImAdminScope(ctx, in.TenantId)
if err != nil {
return
}
id, err := sysin.ParseOptionalInt64(in.Id)
if err != nil {
return
}
err = imadmin.DefaultClient(ctx).RevokeCode(ctx, scope, id)
result := "success"
if err != nil {
result = "failed"
}
_ = writeImAdminAudit(ctx, scope.TenantId, "invite_revoke", "invite_code", id, result, nil)
return
}
func (s *sSysImInvite) BatchRevoke(ctx context.Context, in *sysin.ImInviteBatchRevokeInp) (res *sysin.ImInviteBatchModel, err error) {
scope, err := resolveImAdminScope(ctx, in.TenantId)
if err != nil {
return
}
batchId, err := sysin.ParseOptionalInt64(in.BatchId)
if err != nil {
return
}
var upstream struct {
Batch *imInviteBatchResponse `json:"batch"`
RevokedCount int `json:"revoked_count"`
}
err = imadmin.DefaultClient(ctx).RevokeBatch(ctx, scope, batchId, &upstream)
if upstream.Batch != nil {
res = convertInviteBatch(*upstream.Batch)
} else {
res = &sysin.ImInviteBatchModel{BatchId: strconv.FormatInt(batchId, 10), RevokedCount: upstream.RevokedCount}
}
result := "success"
if err != nil {
result = "failed"
}
_ = writeImAdminAudit(ctx, scope.TenantId, "invite_batch_revoke", "invite_batch", batchId, result, nil)
return
}
func (s *sSysImInvite) Export(ctx context.Context, in *sysin.ImInviteListInp) (err error) {
if err = in.Filter(ctx); err != nil {
return
}
scope, err := resolveImAdminScope(ctx, in.TenantId)
if err != nil {
return
}
req, err := buildInviteListRequest(in)
if err != nil {
return
}
resp, err := imadmin.DefaultClient(ctx).ExportCodes(ctx, scope, req)
if err != nil {
_ = writeImAdminAudit(ctx, scope.TenantId, "invite_export", "invite_code", 0, "failed", g.Map{"hasInviteCode": in.InviteCode != ""})
return
}
defer resp.Body.Close()
request := ghttp.RequestFromCtx(ctx)
if request == nil {
return gerror.New("请求上下文不存在")
}
filename := resp.Header.Get("Content-Disposition")
if filename == "" {
filename = `attachment; filename="registration-invite-codes.csv"`
}
request.Response.Header().Set("Content-Type", resp.Header.Get("Content-Type"))
request.Response.Header().Set("Content-Disposition", filename)
if _, err = io.Copy(request.Response.Writer, resp.Body); err != nil {
return gerror.Wrap(err, "转发导出文件失败")
}
_ = writeImAdminAudit(ctx, scope.TenantId, "invite_export", "invite_code", 0, "success", g.Map{"hasInviteCode": in.InviteCode != ""})
fmt.Fprint(request.Response.Writer, "")
return
}
func buildInviteListRequest(in *sysin.ImInviteListInp) (imInviteListRequest, error) {
batchId, err := sysin.ParseOptionalInt64(in.BatchId)
if err != nil {
return imInviteListRequest{}, err
}
createdBy, err := sysin.ParseOptionalInt64(in.CreatedBy)
if err != nil {
return imInviteListRequest{}, err
}
return imInviteListRequest{
Page: in.Page,
PerPage: in.PerPage,
InviteCode: in.InviteCode,
Status: in.Status,
BatchID: batchId,
CreatedBy: createdBy,
CreatedAtStart: formatRFC3339(in.CreatedAtStart),
CreatedAtEnd: formatRFC3339(in.CreatedAtEnd),
ExpiresAtStart: formatRFC3339(in.ExpiresAtStart),
ExpiresAtEnd: formatRFC3339(in.ExpiresAtEnd),
}, nil
}
func formatRFC3339(t *gtime.Time) string {
if t == nil {
return ""
}
return t.Time.UTC().Format(time.RFC3339)
}
func convertTime(t *time.Time) *gtime.Time {
if t == nil {
return nil
}
return gtime.New(t)
}
func formatOptionalInt64(value *int64) string {
if value == nil || *value == 0 {
return ""
}
return strconv.FormatInt(*value, 10)
}
func convertInviteCode(item imInviteCodeResponse) *sysin.ImInviteCodeModel {
return &sysin.ImInviteCodeModel{
Id: strconv.FormatInt(item.ID, 10),
BatchId: formatOptionalInt64(item.BatchID),
Code: item.Code,
Status: item.Status,
ExpiresAt: convertTime(item.ExpiresAt),
UsedBy: formatOptionalInt64(item.UsedBy),
UsedAt: convertTime(item.UsedAt),
RequestId: item.RequestID,
CreatedBy: strconv.FormatInt(item.CreatedBy, 10),
Remark: item.Remark,
CreatedAt: convertTime(item.CreatedAt),
}
}
func convertInviteBatch(item imInviteBatchResponse) *sysin.ImInviteBatchModel {
return &sysin.ImInviteBatchModel{
BatchId: strconv.FormatInt(item.BatchID, 10),
Quantity: item.Quantity,
ActiveCount: item.ActiveCount,
UsedCount: item.UsedCount,
RevokedCount: item.RevokedCount,
ExpiredCount: item.ExpiredCount,
ExpiresAt: convertTime(item.ExpiresAt),
CreatedAt: convertTime(item.CreatedAt),
}
}