feat: add IM admin management
This commit is contained in:
@@ -0,0 +1,315 @@
|
||||
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),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user