316 lines
9.9 KiB
Go
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),
|
|
}
|
|
}
|