chore: 并入 iotlcm-app 历史到 app/(原提交 f40bda9)
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
package allocatedispatch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/consts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/batchmetadata"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/rabbitmq"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity"
|
||||
)
|
||||
|
||||
type message struct {
|
||||
BatchNo string `json:"batchNo"`
|
||||
BatchType int `json:"batchType"`
|
||||
}
|
||||
|
||||
func Start(ctx context.Context) context.CancelFunc {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
if !g.Cfg().MustGet(ctx, "workerBatchAsync.enabled", false).Bool() || !g.Cfg().MustGet(ctx, "workerBatchAsync.allocateRecovery.enabled", true).Bool() {
|
||||
return cancel
|
||||
}
|
||||
interval := g.Cfg().MustGet(ctx, "workerBatchAsync.allocateRecovery.intervalSeconds", 60).Int()
|
||||
if interval < 30 {
|
||||
interval = 30
|
||||
}
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Duration(interval) * time.Second)
|
||||
defer ticker.Stop()
|
||||
var cursor int64
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
next, err := recoverPage(ctx, cursor, publish)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "划拨任务补投失败: %+v", err)
|
||||
} else {
|
||||
cursor = next
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return cancel
|
||||
}
|
||||
|
||||
func due(batch *entity.BatchMain, now time.Time, processingDelay time.Duration) bool {
|
||||
if batch == nil || batch.BatchType != consts.BatchTypeAllocate || batch.SourceChannel != batchmetadata.MiniProgram {
|
||||
return false
|
||||
}
|
||||
delay := time.Minute
|
||||
switch batch.BatchAsyncStatus {
|
||||
case consts.BatchAsyncStatusPending:
|
||||
case consts.BatchAsyncStatusProcessing:
|
||||
delay = processingDelay
|
||||
default:
|
||||
return false
|
||||
}
|
||||
timestamp := batch.UpdatedAt
|
||||
if batch.BatchAsyncStatus == consts.BatchAsyncStatusProcessing && batch.StartTime != nil && !batch.StartTime.IsZero() {
|
||||
timestamp = batch.StartTime
|
||||
}
|
||||
if timestamp == nil || timestamp.IsZero() {
|
||||
timestamp = batch.CreatedAt
|
||||
}
|
||||
if timestamp == nil || timestamp.IsZero() {
|
||||
return false
|
||||
}
|
||||
return !timestamp.Time.Add(delay).After(now)
|
||||
}
|
||||
|
||||
func recoverPage(ctx context.Context, cursor int64, send func(context.Context, string, string) error) (int64, error) {
|
||||
if ctx.Err() != nil {
|
||||
return cursor, ctx.Err()
|
||||
}
|
||||
columns := dao.BatchMain.Columns()
|
||||
var parents []*entity.BatchMain
|
||||
err := dao.BatchMain.Ctx(ctx).Where(columns.Id+" > ?", cursor).
|
||||
Where(columns.BatchType, consts.BatchTypeAllocate).Where(columns.SourceChannel, batchmetadata.MiniProgram).
|
||||
Where("COALESCE(source_batch_no, '') = ''").
|
||||
WhereIn(columns.BatchAsyncStatus, []int{consts.BatchAsyncStatusPending, consts.BatchAsyncStatusProcessing}).
|
||||
OrderAsc(columns.Id).Limit(50).Scan(&parents)
|
||||
if err != nil {
|
||||
return cursor, err
|
||||
}
|
||||
if len(parents) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
minutes := g.Cfg().MustGet(ctx, "workerBatchAsync.allocateRecovery.processingRetryMinutes", 30).Int()
|
||||
if minutes < 30 {
|
||||
minutes = 30
|
||||
}
|
||||
delay := time.Duration(minutes) * time.Minute
|
||||
queue := strings.TrimSpace(g.Cfg().MustGet(ctx, "workerBatchAsync.queueName", "iotlcm.batch.execute").String())
|
||||
if queue == "" {
|
||||
queue = "iotlcm.batch.execute"
|
||||
}
|
||||
for _, parent := range parents {
|
||||
if ctx.Err() != nil {
|
||||
return cursor, ctx.Err()
|
||||
}
|
||||
cursor = parent.Id
|
||||
if parent.BatchInfo == nil || parent.BatchInfo.Get("jobRole").String() != "allocate_parent" || !due(parent, time.Now(), delay) {
|
||||
continue
|
||||
}
|
||||
var children []*entity.BatchMain
|
||||
err = dao.BatchMain.Ctx(ctx).Where(columns.SourceBatchNo, parent.BatchNo).
|
||||
Where(columns.BatchType, consts.BatchTypeAllocate).Where(columns.TenantId, parent.TenantId).
|
||||
Where(columns.CreatedBy, parent.CreatedBy).Where(columns.SourceChannel, batchmetadata.MiniProgram).Scan(&children)
|
||||
if err != nil {
|
||||
return cursor, err
|
||||
}
|
||||
for _, child := range children {
|
||||
if child.BatchInfo == nil || child.BatchInfo.Get("jobRole").String() != "allocate_chunk" || !due(child, time.Now(), delay) {
|
||||
continue
|
||||
}
|
||||
if err := send(ctx, queue, child.BatchNo); err != nil {
|
||||
g.Log().Errorf(ctx, "划拨子任务补投失败 batchNo:%s err:%+v", child.BatchNo, err)
|
||||
}
|
||||
}
|
||||
if err := send(ctx, queue, parent.BatchNo); err != nil {
|
||||
g.Log().Errorf(ctx, "划拨父任务补投失败 batchNo:%s err:%+v", parent.BatchNo, err)
|
||||
}
|
||||
}
|
||||
if len(parents) < 50 {
|
||||
return 0, nil
|
||||
}
|
||||
return cursor, nil
|
||||
}
|
||||
|
||||
func publish(ctx context.Context, queue, batchNo string) error {
|
||||
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
err := rabbitmq.Publish(ctx, queue, message{BatchNo: batchNo, BatchType: consts.BatchTypeAllocate})
|
||||
if err == nil {
|
||||
g.Log().Infof(ctx, "划拨持久任务补投 batchNo:%s time:%s", batchNo, gtime.Now())
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package allocatedispatch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"testing"
|
||||
"time"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity"
|
||||
)
|
||||
|
||||
func TestDue(t *testing.T) {
|
||||
now := time.Now()
|
||||
for _, test := range []struct {
|
||||
status int
|
||||
age time.Duration
|
||||
due bool
|
||||
}{{1, 59 * time.Second, false}, {1, 2 * time.Minute, true}, {2, 29 * time.Minute, false}, {2, 31 * time.Minute, true}, {3, time.Hour, false}, {4, time.Hour, false}, {5, time.Hour, false}} {
|
||||
batch := &entity.BatchMain{BatchType: 3, SourceChannel: "mini_program", BatchAsyncStatus: test.status, UpdatedAt: gtime.New(now.Add(-test.age))}
|
||||
if due(batch, now, 30*time.Minute) != test.due {
|
||||
t.Fatal(test)
|
||||
}
|
||||
}
|
||||
if due(&entity.BatchMain{BatchType: 3, SourceChannel: "console", BatchAsyncStatus: 1, UpdatedAt: gtime.New(now.Add(-time.Hour))}, now, 30*time.Minute) {
|
||||
t.Fatal("foreign channel replayed")
|
||||
}
|
||||
if due(&entity.BatchMain{BatchType: 3, SourceChannel: "mini_program", BatchAsyncStatus: 1}, now, 30*time.Minute) {
|
||||
t.Fatal("missing time replayed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecoveryPersistsFailureAndIsolatesParents(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
if err := gdb.SetConfig(gdb.Config{"default": gdb.ConfigGroup{{Type: "sqlite", Link: "sqlite::@file(:memory:)", MaxOpenConnCount: 1}}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = g.DB().Close(ctx) })
|
||||
for _, sql := range []string{
|
||||
`CREATE TABLE batch_main (id INTEGER PRIMARY KEY,batch_no TEXT,batch_type INTEGER,source_batch_no TEXT,source_channel TEXT,batch_async_status INTEGER,tenant_id TEXT,created_by INTEGER,batch_info TEXT,created_at TEXT,updated_at TEXT,start_time TEXT)`,
|
||||
`INSERT INTO batch_main VALUES (1,'PARENT',3,'','mini_program',1,'A',7,'{"jobRole":"allocate_parent"}','2020-01-01','2020-01-01',NULL), (2,'CHILD',3,'PARENT','mini_program',1,'A',7,'{"jobRole":"allocate_chunk"}','2020-01-01','2020-01-01',NULL), (3,'FOREIGN',3,'PARENT','mini_program',1,'B',7,'{"jobRole":"allocate_chunk"}','2020-01-01','2020-01-01',NULL), (4,'DONE',3,'','mini_program',3,'A',7,'{"jobRole":"allocate_parent"}','2020-01-01','2020-01-01',NULL), (5,'OTHER',101,'','mini_program',1,'A',7,'{}','2020-01-01','2020-01-01',NULL), (6,'CONSOLE',3,'','console',1,'A',7,'{"jobRole":"allocate_parent"}','2020-01-01','2020-01-01',NULL)`,
|
||||
} {
|
||||
if _, err := g.DB().Exec(ctx, sql); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, fail := range []bool{true, false} {
|
||||
var calls []string
|
||||
cursor, err := recoverPage(ctx, 0, func(ctx context.Context, queue, batchNo string) error {
|
||||
calls = append(calls, batchNo)
|
||||
if queue != "iotlcm.batch.execute" {
|
||||
t.Fatal(queue)
|
||||
}
|
||||
if fail {
|
||||
return errors.New("queue offline")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil || cursor != 0 || len(calls) != 2 || calls[0] != "CHILD" || calls[1] != "PARENT" {
|
||||
t.Fatal(calls, cursor, err)
|
||||
}
|
||||
}
|
||||
if _, err := g.DB().Exec(ctx, `UPDATE batch_main SET batch_async_status=3 WHERE batch_no='PARENT'`); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err := recoverPage(ctx, 0, func(context.Context, string, string) error { t.Fatal("terminal parent replayed"); return nil })
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cancelled, cancel := context.WithCancel(ctx)
|
||||
cancel()
|
||||
if _, err := recoverPage(cancelled, 0, func(context.Context, string, string) error { t.Fatal("cancelled replay"); return nil }); err == nil {
|
||||
t.Fatal("cancel ignored")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity"
|
||||
)
|
||||
|
||||
type (
|
||||
IAppAuth interface {
|
||||
Captcha(ctx context.Context) (captchaID string, captchaImage string, err error)
|
||||
SideCaptcha(ctx context.Context) (res *model.AppSideCaptchaModel, err error)
|
||||
CheckSideCaptcha(ctx context.Context, param *model.AppCheckSideCaptchaParam) (err error)
|
||||
SendSms(ctx context.Context, param *model.AppSendSmsParam) (res *model.AppSendSmsModel, err error)
|
||||
PhoneRegister(ctx context.Context, param *model.AppPhoneRegisterParam) (res *model.AppAuthTokenModel, err error)
|
||||
PhoneLogin(ctx context.Context, param *model.AppPhoneLoginParam) (res *model.AppAuthTokenModel, err error)
|
||||
PhoneSmsLogin(ctx context.Context, param *model.AppPhoneSmsLoginParam) (res *model.AppAuthTokenModel, err error)
|
||||
WechatLogin(ctx context.Context, param *model.AppWechatLoginParam) (res *model.AppWechatLoginModel, err error)
|
||||
WechatBindPhone(ctx context.Context, param *model.AppWechatBindPhoneParam) (res *model.AppWechatBindPhoneModel, err error)
|
||||
BindWechatOpenIdByLoginCode(ctx context.Context, user *entity.SysUser, wxCode string) error
|
||||
ForgotPassword(ctx context.Context, param *model.AppForgotPasswordParam) (err error)
|
||||
}
|
||||
IAppCard interface {
|
||||
// BalanceRechargeSubmit 创建余额充值待支付订单,并返回前端可使用的支付信息。
|
||||
// 余额入账和余额流水只在支付回调或模拟支付确认成功后写入。
|
||||
BalanceRechargeSubmit(ctx context.Context, param *model.AppBalanceRechargeSubmitParam) (res *model.AppBalanceRechargeSubmitModel, err error)
|
||||
BalanceRechargeMockPay(ctx context.Context, param *model.AppBalanceRechargeMockPayParam) (*model.AppBalanceRechargeStatusModel, error)
|
||||
BalanceRechargeStatus(ctx context.Context, param *model.AppBalanceRechargeStatusParam) (*model.AppBalanceRechargeStatusModel, error)
|
||||
BalanceRechargeRefund(ctx context.Context, param *model.AppBalanceRechargeRefundParam) (*model.AppOrderModel, error)
|
||||
// AllocateTargets 查询当前企业用户可划拨的目标客户。
|
||||
AllocateTargets(ctx context.Context, param *model.AppCardAllocateTargetListParam) (items []*model.AppCardAllocateTargetModel, total int, err error)
|
||||
// AllocateBatchPrepare 校验待划拨卡片,并写入划拨预处理批次。
|
||||
AllocateBatchPrepare(ctx context.Context, param *model.AppCardAllocateBatchPrepareParam) (res *model.AppCardAllocateBatchModel, err error)
|
||||
// AllocateBatchSubmit 确认划拨预处理批次,并更新卡片归属;划拨后原企业的可见和办理权限仍保留。
|
||||
AllocateBatchSubmit(ctx context.Context, param *model.AppCardAllocateBatchSubmitParam) (res *model.AppCardAllocateBatchModel, err error)
|
||||
Bind(ctx context.Context, param *model.AppCardBindParam) (res *model.AppCardModel, err error)
|
||||
// ChangePrepare 校验企业用户套餐变更条件,并写入预处理批次。
|
||||
ChangePrepare(ctx context.Context, param *model.AppCardChangePrepareParam) (res *model.AppCardChangePrepareModel, err error)
|
||||
// ChangeSubmit 确认套餐变更预处理批次,并在同一事务内完成余额扣款和本地套餐变更。
|
||||
ChangeSubmit(ctx context.Context, param *model.AppCardChangeSubmitParam) (res *model.AppCardChangeSubmitModel, err error)
|
||||
// 查询当前登录用户可见的套餐订购记录。
|
||||
PackageList(ctx context.Context, param *model.AppPackageListParam) (items []*model.AppPackageModel, total int, err error)
|
||||
// 查询卡片当前套餐详情。
|
||||
// 核心规则是“卡主表 current_package_code -> 套餐表 package_code”,订购记录只做详情兜底,
|
||||
// 避免卡主表与订购表不同步时前端报“套餐信息不存在”。
|
||||
PublicPackageDetail(ctx context.Context, param *model.AppPackagePublicDetailParam) (res *model.AppPackageModel, err error)
|
||||
// 处理首页免登录公共查卡,只返回卡基础信息,不开放绑卡、重启等业务能力。
|
||||
PublicQuery(ctx context.Context, param *model.AppCardQueryParam) (res *model.AppCardModel, err error)
|
||||
// 查询当前登录用户可见卡片。终端用户走 t_sim_terminal 关联表,
|
||||
// 企业用户沿用管理平台数据权限查询持卡列表。
|
||||
List(ctx context.Context, param *model.AppCardListParam) (items []*model.AppCardModel, total int, err error)
|
||||
// 登录后先查用户可见卡;查不到时回退公共查卡,保证登录后仍能查看公共卡详情。
|
||||
Detail(ctx context.Context, param *model.AppCardDetailParam) (res *model.AppCardModel, err error)
|
||||
// RenewPrepare 根据当前套餐 renewable_duration_config 生成可续费年限档位,
|
||||
// 再按当前用户身份解析套餐单年价,返回每个档位的续费总价。
|
||||
RenewPrepare(ctx context.Context, param *model.AppCardRenewPrepareParam) (res *model.AppCardRenewPrepareModel, err error)
|
||||
// RenewSubmit 使用账户余额支付,并把单卡续费也写入正式续费批次。
|
||||
RenewSubmit(ctx context.Context, param *model.AppCardRenewSubmitParam) (res *model.AppCardRenewSubmitModel, err error)
|
||||
// 批量续费约束做预校验:
|
||||
// 同一批次必须同当前套餐、同客户归属、同定价,才能生成统一续费档位。
|
||||
RenewBatchPrepare(ctx context.Context, param *model.AppCardRenewBatchPrepareParam) (res *model.AppCardRenewPrepareModel, err error)
|
||||
// RenewBatchSubmit 确认续费预处理批次,并在同一事务内完成余额扣款和批量续费落库。
|
||||
// 批量续费必须先走预处理校验,避免卡片、套餐或价格在提交时发生变化。
|
||||
RenewBatchSubmit(ctx context.Context, param *model.AppCardRenewBatchSubmitParam) (res *model.AppCardRenewSubmitModel, err error)
|
||||
// Restart 兼容原重启接口。启用 worker 后停机、复机和重启都投递批次异步执行。
|
||||
Restart(ctx context.Context, param *model.AppCardRestartParam) (res *model.AppCardRestartModel, err error)
|
||||
Stop(ctx context.Context, param *model.AppCardRestartParam) (res *model.AppCardLifecycleModel, err error)
|
||||
Start(ctx context.Context, param *model.AppCardRestartParam) (res *model.AppCardLifecycleModel, err error)
|
||||
// LifecycleBatchSubmit 提交卡片停机、复机和重启批次。
|
||||
// 终端用户仅允许重启;停机和复机仍然只开放给企业用户。
|
||||
LifecycleBatchSubmit(ctx context.Context, param *model.AppCardLifecycleParam) (res *model.AppCardLifecycleModel, err error)
|
||||
LifecycleBatchStatus(ctx context.Context, param *model.AppCardLifecycleStatusParam) (res *model.AppCardLifecycleModel, err error)
|
||||
BalanceRechargeWechatNotify(ctx context.Context) error
|
||||
BalanceRechargeWechatRefundNotify(ctx context.Context) error
|
||||
RecognizeCard(ctx context.Context) (res *model.AppCardRecognitionModel, err error)
|
||||
}
|
||||
IAppUser interface {
|
||||
WarningPreference(ctx context.Context) (*model.AppWarningPreferenceModel, error)
|
||||
SaveWarningPreference(ctx context.Context, param *model.AppWarningPreferenceParam) (*model.AppWarningPreferenceModel, error)
|
||||
UnbindWechat(ctx context.Context) (*model.AppWechatBindModel, error)
|
||||
CustomerList(ctx context.Context, param *model.AppCustomerListParam) (items []*model.AppCustomerModel, total int, summary *model.AppCustomerSummary, err error)
|
||||
CustomerDetail(ctx context.Context, param *model.AppCustomerDetailParam) (*model.AppCustomerDetailModel, error)
|
||||
Info(ctx context.Context) (res *model.AppUserInfoModel, err error)
|
||||
UpdateInfo(ctx context.Context, param *model.AppUpdateUserInfoParam) (res *model.AppUserInfoModel, err error)
|
||||
BindWechat(ctx context.Context, param *model.AppWechatBindParam) (res *model.AppWechatBindModel, err error)
|
||||
}
|
||||
IAppMessage interface {
|
||||
List(ctx context.Context, param *model.AppMessageListParam) (items []*model.AppMessageModel, total int, err error)
|
||||
Detail(ctx context.Context, param *model.AppMessageDetailParam) (*model.AppMessageModel, error)
|
||||
Read(ctx context.Context, param *model.AppMessageReadParam) error
|
||||
}
|
||||
IAppOrder interface {
|
||||
List(ctx context.Context, param *model.AppOrderListParam) (items []*model.AppOrderModel, total int, err error)
|
||||
Detail(ctx context.Context, param *model.AppOrderDetailParam) (*model.AppOrderModel, error)
|
||||
}
|
||||
IAppWarning interface {
|
||||
ConfigList(ctx context.Context, param *model.AppWarningConfigListParam) (res *model.AppWarningConfigListModel, err error)
|
||||
ConfigMeta(ctx context.Context) (res *model.AppWarningConfigMetaModel, err error)
|
||||
ConfigSave(ctx context.Context, param *model.AppWarningConfigSaveParam) (res *model.AppWarningConfigSaveModel, err error)
|
||||
ConfigBatchSave(ctx context.Context, param *model.AppWarningConfigBatchSaveParam) (res *model.AppWarningConfigBatchSaveModel, err error)
|
||||
ConfigNotify(ctx context.Context, param *model.AppWarningConfigNotifyParam) (res *model.AppWarningConfigNotifyModel, err error)
|
||||
ConfigBatchNotify(ctx context.Context, param *model.AppWarningConfigBatchNotifyParam) (res *model.AppWarningConfigBatchNotifyModel, err error)
|
||||
}
|
||||
IAppWorkOrder interface {
|
||||
Action(ctx context.Context, param *model.AppWorkOrderActionParam) error
|
||||
Upload(ctx context.Context) (output *model.SysOssUploadModel, err error)
|
||||
List(ctx context.Context, param *model.AppWorkOrderListParam) (items []*model.AppWorkOrderModel, total int, err error)
|
||||
Detail(ctx context.Context, param *model.AppWorkOrderDetailParam) (res *model.AppWorkOrderModel, err error)
|
||||
Create(ctx context.Context, param *model.AppWorkOrderCreateParam) (res *model.AppWorkOrderModel, err error)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localAppAuth IAppAuth
|
||||
localAppCard IAppCard
|
||||
localAppUser IAppUser
|
||||
localAppMessage IAppMessage
|
||||
localAppOrder IAppOrder
|
||||
localAppWarning IAppWarning
|
||||
localAppWorkOrder IAppWorkOrder
|
||||
)
|
||||
|
||||
func AppAuth() IAppAuth {
|
||||
if localAppAuth == nil {
|
||||
panic("implement not found for interface IAppAuth, forgot register?")
|
||||
}
|
||||
return localAppAuth
|
||||
}
|
||||
|
||||
func RegisterAppAuth(i IAppAuth) {
|
||||
localAppAuth = i
|
||||
}
|
||||
|
||||
func AppCard() IAppCard {
|
||||
if localAppCard == nil {
|
||||
panic("implement not found for interface IAppCard, forgot register?")
|
||||
}
|
||||
return localAppCard
|
||||
}
|
||||
|
||||
func RegisterAppCard(i IAppCard) {
|
||||
localAppCard = i
|
||||
}
|
||||
|
||||
func AppUser() IAppUser {
|
||||
if localAppUser == nil {
|
||||
panic("implement not found for interface IAppUser, forgot register?")
|
||||
}
|
||||
return localAppUser
|
||||
}
|
||||
|
||||
func RegisterAppUser(i IAppUser) {
|
||||
localAppUser = i
|
||||
}
|
||||
|
||||
func AppMessage() IAppMessage {
|
||||
if localAppMessage == nil {
|
||||
panic("implement not found for interface IAppMessage, forgot register?")
|
||||
}
|
||||
return localAppMessage
|
||||
}
|
||||
|
||||
func RegisterAppMessage(i IAppMessage) {
|
||||
localAppMessage = i
|
||||
}
|
||||
|
||||
func AppOrder() IAppOrder {
|
||||
if localAppOrder == nil {
|
||||
panic("implement not found for interface IAppOrder, forgot register?")
|
||||
}
|
||||
return localAppOrder
|
||||
}
|
||||
|
||||
func RegisterAppOrder(i IAppOrder) {
|
||||
localAppOrder = i
|
||||
}
|
||||
|
||||
func AppWarning() IAppWarning {
|
||||
if localAppWarning == nil {
|
||||
panic("implement not found for interface IAppWarning, forgot register?")
|
||||
}
|
||||
return localAppWarning
|
||||
}
|
||||
|
||||
func RegisterAppWarning(i IAppWarning) {
|
||||
localAppWarning = i
|
||||
}
|
||||
|
||||
func AppWorkOrder() IAppWorkOrder {
|
||||
if localAppWorkOrder == nil {
|
||||
panic("implement not found for interface IAppWorkOrder, forgot register?")
|
||||
}
|
||||
return localAppWorkOrder
|
||||
}
|
||||
|
||||
func RegisterAppWorkOrder(i IAppWorkOrder) {
|
||||
localAppWorkOrder = i
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
)
|
||||
|
||||
type IAppDiagnosis interface {
|
||||
Info(ctx context.Context, param *model.AppDiagnosisInfoParam) (res *model.AppDiagnosisInfoModel, err error)
|
||||
Flow(ctx context.Context, param *model.AppDiagnosisFlowParam) (res *model.AppDiagnosisFlowModel, err error)
|
||||
OpenInfo(ctx context.Context, param *model.AppOpenDiagnosisInfoParam) (res *model.AppDiagnosisInfoModel, err error)
|
||||
OpenFlow(ctx context.Context, param *model.AppOpenDiagnosisFlowParam) (res *model.AppDiagnosisFlowModel, err error)
|
||||
}
|
||||
|
||||
var localAppDiagnosis IAppDiagnosis
|
||||
|
||||
func AppDiagnosis() IAppDiagnosis {
|
||||
if localAppDiagnosis == nil {
|
||||
panic("implement not found for interface IAppDiagnosis, forgot register?")
|
||||
}
|
||||
return localAppDiagnosis
|
||||
}
|
||||
|
||||
func RegisterAppDiagnosis(i IAppDiagnosis) {
|
||||
localAppDiagnosis = i
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
package executionlog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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/util/gconv"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/consts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/allocationunits"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/batchmetadata"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/xgorm/handler"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
)
|
||||
|
||||
// 办理结果只允许发起人查看;通用批次日志沿用控制台的数据范围。
|
||||
type ownerOnlyKey struct{}
|
||||
|
||||
func scope(ctx context.Context) (*gdb.Model, error) {
|
||||
if contexts.GetUserId(ctx) <= 0 || strings.TrimSpace(contexts.GetTenantId(ctx)) == "" {
|
||||
return nil, gerror.New("请先登录")
|
||||
}
|
||||
return scopedModel(ctx, dao.BatchMain.Ctx(ctx))
|
||||
}
|
||||
|
||||
func scopedModel(ctx context.Context, mod *gdb.Model) (*gdb.Model, error) {
|
||||
user, tenant := contexts.GetUserId(ctx), strings.TrimSpace(contexts.GetTenantId(ctx))
|
||||
if user <= 0 || tenant == "" {
|
||||
return nil, gerror.New("请先登录")
|
||||
}
|
||||
mod = mod.Where("tenant_id", tenant)
|
||||
if ownerOnly, _ := ctx.Value(ownerOnlyKey{}).(bool); ownerOnly {
|
||||
return mod.Where("created_by", user), nil
|
||||
}
|
||||
if contexts.IsSuperAdmin(ctx) {
|
||||
return mod, nil
|
||||
}
|
||||
// 菜单范围由认证中间件读取当前数据库后写入,优先于登录时的角色快照。
|
||||
roleId := gconv.Int64(contexts.GetDataValue(ctx, "currentRoleId"))
|
||||
dataScope := gconv.String(contexts.GetDataValue(ctx, "currentRoleDataScope"))
|
||||
if roleId > 0 && dataScope != "" && len(contexts.GetRoles(ctx)) == 0 {
|
||||
identity := *contexts.GetUser(ctx)
|
||||
identity.Roles = []model.Role{{RoleId: roleId, DataScope: dataScope}}
|
||||
copied := *contexts.Get(ctx)
|
||||
copied.User = &identity
|
||||
ctx = contexts.Set(ctx, &copied)
|
||||
mod = mod.Ctx(ctx)
|
||||
}
|
||||
if len(contexts.GetRoles(ctx)) == 0 {
|
||||
return mod.Where("1 = 0"), nil
|
||||
}
|
||||
validScopes := []string{
|
||||
consts.SysRoleDataScopeAll, consts.SysRoleDataScopeCustom,
|
||||
consts.SysRoleDataScopeDept, consts.SysRoleDataScopeDeptAndBelow,
|
||||
consts.SysRoleDataScopePersonal, consts.SysRoleDataScopeDeptAndBelowOrPersonal,
|
||||
consts.SysRoleDataScopeOrgAndNextLevel, consts.SysRoleDataScopeOrgNextLevel,
|
||||
}
|
||||
if roleId > 0 && dataScope != "" {
|
||||
if !slices.Contains(validScopes, dataScope) {
|
||||
return mod.Where("1 = 0"), nil
|
||||
}
|
||||
} else {
|
||||
for _, role := range contexts.GetRoles(ctx) {
|
||||
if !slices.Contains(validScopes, role.DataScope) {
|
||||
return mod.Where("1 = 0"), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
// 先生成创建部门/创建人的过滤条件,再选择返回字段,避免 DTO 缺少权限字段导致漏过滤。
|
||||
return handler.FilterAuth(mod.Fields("created_dept", "created_by")), nil
|
||||
}
|
||||
|
||||
func dbError(ctx context.Context, err error) error {
|
||||
g.Log().Error(ctx, "execution log query failed", err)
|
||||
return gerror.New("执行日志查询失败,请稍后重试")
|
||||
}
|
||||
|
||||
func paging(page, size int) (int, int) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if size < 1 {
|
||||
size = 20
|
||||
}
|
||||
if size > 100 {
|
||||
size = 100
|
||||
}
|
||||
return page, size
|
||||
}
|
||||
|
||||
func normalize(item *model.AppExecutionLogItem) {
|
||||
item.SourceChannel = batchmetadata.Channel(item.SourceChannel)
|
||||
if !batchmetadata.ValidMode(item.ExecutionMode) {
|
||||
item.ExecutionMode = batchmetadata.Unknown
|
||||
}
|
||||
item.FailReason = safeReason(item.FailReason)
|
||||
}
|
||||
|
||||
// Do not expose internal network addresses, credentials or stack traces to mobile clients.
|
||||
var publicErrorCode = regexp.MustCompile("^[A-Za-z0-9_.-]{1,64}$")
|
||||
|
||||
func safeReason(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return ""
|
||||
}
|
||||
lower := strings.ToLower(value)
|
||||
for _, marker := range []string{"token", "secret", "password", "authorization", "api_key", "apikey", "http:", "https:", "rpc", "sql", "tcp", "panic", "goroutine", "stack", "/src/", "/app/", "dial ", "127.0.", "192." + "168.", "10.", "172.", "sk-", "mysql", "redis"} {
|
||||
if strings.Contains(lower, marker) {
|
||||
return "执行失败,请凭批次号联系客服核查"
|
||||
}
|
||||
}
|
||||
if strings.ContainsAny(value, "\r\n") || utf8.RuneCountInString(value) > 180 {
|
||||
return "执行失败,请凭批次号联系客服核查"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func List(ctx context.Context, in *model.AppExecutionLogListParam) ([]*model.AppExecutionLogItem, int, error) {
|
||||
mod, err := scope(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if in == nil {
|
||||
in = &model.AppExecutionLogListParam{}
|
||||
}
|
||||
c := dao.BatchMain.Columns()
|
||||
mod = mod.Fields(model.AppExecutionLogItem{})
|
||||
if n := strings.TrimSpace(in.BatchNo); n != "" {
|
||||
mod = mod.Where(c.BatchNo, n)
|
||||
}
|
||||
if in.SourceChannel != "" {
|
||||
mod = mod.Where(c.SourceChannel, in.SourceChannel)
|
||||
}
|
||||
if in.ExecutionMode != nil {
|
||||
mod = mod.Where(c.ExecutionMode, *in.ExecutionMode)
|
||||
}
|
||||
if in.SourceType != nil {
|
||||
mod = mod.Where(c.SourceType, *in.SourceType)
|
||||
}
|
||||
if in.BatchAsyncStatus != nil {
|
||||
mod = mod.Where(c.BatchAsyncStatus, *in.BatchAsyncStatus)
|
||||
}
|
||||
// Split allocation children are execution details, not a second user submission.
|
||||
// Allocation children are execution details of the parent submission. The
|
||||
// source_batch_no relation is authoritative; batch_info is only descriptive.
|
||||
mod = mod.Where("NOT (batch_type = ? AND COALESCE(source_batch_no, '') <> '' AND source_batch_no <> batch_no)", consts.BatchTypeAllocate)
|
||||
page, size := paging(in.Page, in.PageSize)
|
||||
items := make([]*model.AppExecutionLogItem, 0)
|
||||
total := 0
|
||||
if err = mod.Page(page, size).OrderDesc(c.Id).ScanAndCount(&items, &total, false); err != nil {
|
||||
return nil, 0, dbError(ctx, err)
|
||||
}
|
||||
unitFields := []*allocationunits.Fields{}
|
||||
for _, item := range items {
|
||||
normalize(item)
|
||||
if item.BatchType == consts.BatchTypeAllocate {
|
||||
item.Fields = allocationunits.Resolve(item.UnitInfo, item.StoredSourceDeptId, item.StoredTargetDeptId)
|
||||
unitFields = append(unitFields, &item.Fields)
|
||||
}
|
||||
}
|
||||
if err := allocationunits.Fill(ctx, contexts.GetTenantId(ctx), unitFields); err != nil {
|
||||
return nil, 0, dbError(ctx, err)
|
||||
}
|
||||
return items, total, nil
|
||||
}
|
||||
|
||||
func ensureAllocateParent(ctx context.Context, batchNo string) error {
|
||||
mod, err := scope(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
columns := dao.BatchMain.Columns()
|
||||
count, err := mod.Where(columns.BatchNo, strings.TrimSpace(batchNo)).Where("(batch_type = ? OR (batch_type = ? AND JSON_EXTRACT(batch_info, '$.targetBatchType') = ?))", consts.BatchTypeAllocate, consts.BatchTypePrepare, consts.BatchTypeAllocate).Where("COALESCE(source_batch_no, '') = ''").Count()
|
||||
if err != nil {
|
||||
return dbError(ctx, err)
|
||||
}
|
||||
if count != 1 {
|
||||
return gerror.New("划拨批次不存在或无权查看")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func AllocateSummary(ctx context.Context, batchNo string) (*model.AppExecutionLogItem, error) {
|
||||
ctx = context.WithValue(ctx, ownerOnlyKey{}, true)
|
||||
if err := ensureAllocateParent(ctx, batchNo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Summary(ctx, batchNo)
|
||||
}
|
||||
func AllocateDetails(ctx context.Context, in *model.AppExecutionLogDetailParam) ([]*model.AppExecutionLogDetail, int, error) {
|
||||
ctx = context.WithValue(ctx, ownerOnlyKey{}, true)
|
||||
if in == nil {
|
||||
return nil, 0, gerror.New("批次号不能为空")
|
||||
}
|
||||
if err := ensureAllocateParent(ctx, in.BatchNo); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return Details(ctx, in)
|
||||
}
|
||||
|
||||
func Summary(ctx context.Context, batchNo string) (*model.AppExecutionLogItem, error) {
|
||||
mod, err := scope(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if strings.TrimSpace(batchNo) == "" {
|
||||
return nil, gerror.New("批次号不能为空")
|
||||
}
|
||||
var item *model.AppExecutionLogItem
|
||||
if err = mod.Fields(model.AppExecutionLogItem{}).
|
||||
Where(dao.BatchMain.Columns().BatchNo, batchNo).
|
||||
Where("NOT (batch_type = ? AND COALESCE(source_batch_no, '') <> '' AND source_batch_no <> batch_no)", consts.BatchTypeAllocate).
|
||||
Scan(&item); err != nil {
|
||||
return nil, dbError(ctx, err)
|
||||
}
|
||||
if item == nil {
|
||||
return nil, gerror.New("执行日志不存在或无权查看")
|
||||
}
|
||||
normalize(item)
|
||||
if item.BatchType == consts.BatchTypeAllocate {
|
||||
item.Fields = allocationunits.Resolve(item.UnitInfo, item.StoredSourceDeptId, item.StoredTargetDeptId)
|
||||
if err := allocationunits.Fill(ctx, contexts.GetTenantId(ctx), []*allocationunits.Fields{&item.Fields}); err != nil {
|
||||
return nil, dbError(ctx, err)
|
||||
}
|
||||
}
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func Details(ctx context.Context, in *model.AppExecutionLogDetailParam) ([]*model.AppExecutionLogDetail, int, error) {
|
||||
if in == nil {
|
||||
return nil, 0, gerror.New("批次号不能为空")
|
||||
}
|
||||
parent, err := Summary(ctx, in.BatchNo)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
c := dao.BatchDetail.Columns()
|
||||
mod, err := scopedModel(ctx, dao.BatchDetail.Ctx(ctx))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
mod = mod.Fields(model.AppExecutionLogDetail{})
|
||||
if parent.BatchType == consts.BatchTypeAllocate {
|
||||
// 先按当前菜单的数据范围解析子批次,再用批次号索引查询明细。
|
||||
var children []struct {
|
||||
BatchNo string `orm:"batch_no"`
|
||||
}
|
||||
mainColumns := dao.BatchMain.Columns()
|
||||
childrenMod, err := scope(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if err := childrenMod.Fields(mainColumns.BatchNo).
|
||||
Where(mainColumns.SourceBatchNo, in.BatchNo).Where(mainColumns.BatchType, parent.BatchType).
|
||||
Where(mainColumns.BatchNo+" <> ?", in.BatchNo).Scan(&children); err != nil {
|
||||
return nil, 0, dbError(ctx, err)
|
||||
}
|
||||
batchNos := []string{in.BatchNo}
|
||||
for _, child := range children {
|
||||
batchNos = append(batchNos, child.BatchNo)
|
||||
}
|
||||
mod = mod.WhereIn(c.BatchNo, batchNos)
|
||||
} else {
|
||||
mod = mod.Where(c.BatchNo, in.BatchNo)
|
||||
}
|
||||
if in.DetailStatus != nil {
|
||||
mod = mod.Where(c.DetailStatus, *in.DetailStatus)
|
||||
}
|
||||
page, size := paging(in.Page, in.PageSize)
|
||||
items := make([]*model.AppExecutionLogDetail, 0)
|
||||
total := 0
|
||||
if err = mod.OrderAsc(c.Id).Page(page, size).ScanAndCount(&items, &total, false); err != nil {
|
||||
return nil, 0, dbError(ctx, err)
|
||||
}
|
||||
unitFields := []*allocationunits.Fields{}
|
||||
for index, item := range items {
|
||||
if parent.BatchType == consts.BatchTypeAllocate {
|
||||
item.Fields = allocationunits.Resolve(item.UnitInfo, parent.SourceDeptId, parent.TargetDeptId)
|
||||
if item.SourceDeptName == "" && item.SourceDeptId == parent.SourceDeptId {
|
||||
item.SourceDeptName = parent.SourceDeptName
|
||||
}
|
||||
if item.TargetDeptName == "" && item.TargetDeptId == parent.TargetDeptId {
|
||||
item.TargetDeptName = parent.TargetDeptName
|
||||
}
|
||||
unitFields = append(unitFields, &item.Fields)
|
||||
}
|
||||
item.RowNo = (page-1)*size + index + 1
|
||||
item.ErrorReason = safeReason(item.ErrorReason)
|
||||
if item.ErrorCode != "" && !publicErrorCode.MatchString(item.ErrorCode) {
|
||||
item.ErrorCode = "EXECUTION_FAILED"
|
||||
}
|
||||
}
|
||||
if err := allocationunits.Fill(ctx, contexts.GetTenantId(ctx), unitFields); err != nil {
|
||||
return nil, 0, dbError(ctx, err)
|
||||
}
|
||||
return items, total, nil
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
package executionlog
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"testing"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/consts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
)
|
||||
|
||||
func TestPrincipalIsolation(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
if _, _, err := List(ctx, nil); err == nil {
|
||||
t.Fatal("guest allowed")
|
||||
}
|
||||
if _, err := Summary(ctx, "mine"); err == nil {
|
||||
t.Fatal("guest summary allowed")
|
||||
}
|
||||
if _, _, err := Details(ctx, &model.AppExecutionLogDetailParam{BatchNo: "mine"}); err == nil {
|
||||
t.Fatal("guest details allowed")
|
||||
}
|
||||
if err := gdb.SetConfig(gdb.Config{"default": gdb.ConfigGroup{{Type: "sqlite", Link: "sqlite::@file(:memory:)", MaxOpenConnCount: 1}}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = g.DB().Close(ctx) })
|
||||
for _, sql := range []string{
|
||||
"CREATE TABLE batch_main (id INTEGER PRIMARY KEY, batch_no TEXT, batch_type INTEGER, source_batch_no TEXT, source_channel TEXT, execution_mode INTEGER, source_type INTEGER, batch_async_status INTEGER, total_count INTEGER, run_result INTEGER, fail_reason TEXT, created_at TEXT, start_time TEXT, end_time TEXT, tenant_id TEXT, created_by INTEGER, created_dept INTEGER DEFAULT 10, target_dept_id INTEGER DEFAULT 0, batch_info TEXT)",
|
||||
"CREATE TABLE batch_detail (id INTEGER PRIMARY KEY, batch_no TEXT, row_no INTEGER, item_id TEXT, detail_status INTEGER, error_code TEXT, error_reason TEXT, tenant_id TEXT, created_by INTEGER, created_dept INTEGER DEFAULT 10, snapshot TEXT)",
|
||||
"INSERT INTO batch_main(id,batch_no,batch_type,tenant_id,created_by,source_channel,execution_mode,source_type) VALUES (1,'mine',101,'A',7,'mini_program',1,0),(2,'other-user',101,'A',8,'console',2,3),(3,'other-tenant',101,'B',7,'console',2,3)",
|
||||
"INSERT INTO batch_detail(id,batch_no,row_no,item_id,detail_status,error_code,error_reason,tenant_id,created_by) VALUES(1,'mine',1,'card1',3,'ERR','套餐已过期','A',7),(2,'mine',2,'hidden',3,'ERR','hidden','B',7)",
|
||||
} {
|
||||
if _, err := g.DB().Exec(ctx, sql); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
ctx = contexts.Set(ctx, &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 7, DeptId: 10, TenantId: "A", Roles: []model.Role{{RoleId: 82, DataScope: consts.SysRoleDataScopePersonal}}}}})
|
||||
list, total, err := List(ctx, nil)
|
||||
if err != nil || total != 1 || len(list) != 1 || list[0].BatchNo != "mine" {
|
||||
t.Fatalf("list=%+v total=%d err=%v", list, total, err)
|
||||
}
|
||||
for _, no := range []string{"other-user", "other-tenant", "missing"} {
|
||||
if _, err := Summary(ctx, no); err == nil {
|
||||
t.Fatalf("summary exposed %s", no)
|
||||
}
|
||||
if _, _, err := Details(ctx, &model.AppExecutionLogDetailParam{BatchNo: no}); err == nil {
|
||||
t.Fatalf("details exposed %s", no)
|
||||
}
|
||||
}
|
||||
details, total, err := Details(ctx, &model.AppExecutionLogDetailParam{BatchNo: "mine"})
|
||||
if err != nil || total != 1 || len(details) != 1 || details[0].ItemId != "card1" {
|
||||
t.Fatalf("details=%+v total=%d err=%v", details, total, err)
|
||||
}
|
||||
source := 0
|
||||
list, total, err = List(ctx, &model.AppExecutionLogListParam{SourceType: &source, SourceChannel: "mini_program"})
|
||||
if err != nil || total != 1 || len(list) != 1 {
|
||||
t.Fatal("zero filter failed", err, total)
|
||||
}
|
||||
source = 3
|
||||
_, total, err = List(ctx, &model.AppExecutionLogListParam{SourceType: &source})
|
||||
if err != nil || total != 0 {
|
||||
t.Fatal("foreign records leaked through filter", err, total)
|
||||
}
|
||||
|
||||
t.Run("控制台数据范围", func(t *testing.T) {
|
||||
for _, sql := range []string{
|
||||
"CREATE TABLE sys_dept (dept_id INTEGER PRIMARY KEY, parent_id INTEGER, dept_type INTEGER, ancestors TEXT,tenant_id TEXT,dept_key TEXT,dept_name TEXT,deleted_at TEXT)",
|
||||
"CREATE TABLE sys_role_dept (tenant_id TEXT, role_id INTEGER, dept_id INTEGER)",
|
||||
"INSERT INTO sys_dept(dept_id,parent_id,dept_type,ancestors) VALUES(10,0,1,',0,'),(20,10,1,',0,10,'),(30,20,1,',0,10,20,'),(40,0,1,',0,')",
|
||||
"UPDATE sys_dept SET tenant_id='A',dept_name='部门',dept_key='key'",
|
||||
"INSERT INTO sys_role_dept VALUES('A',82,20),('B',82,40)",
|
||||
"UPDATE batch_main SET created_dept=20 WHERE batch_no='other-user'",
|
||||
"INSERT INTO batch_main(id,batch_no,batch_type,tenant_id,created_by,created_dept) VALUES(20,'grandchild',101,'A',9,30),(21,'outside',101,'A',10,40)",
|
||||
"INSERT INTO batch_detail(id,batch_no,row_no,item_id,detail_status,tenant_id,created_by,created_dept) VALUES(50,'other-user',1,'other-card',2,'A',8,20)",
|
||||
} {
|
||||
if _, err := g.DB().Exec(ctx, sql); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_, _ = g.DB().Exec(ctx, "DELETE FROM batch_main WHERE id IN (20,21)")
|
||||
_, _ = g.DB().Exec(ctx, "DELETE FROM batch_detail WHERE id=50")
|
||||
})
|
||||
cases := []struct {
|
||||
name, roleScope, menuScope string
|
||||
dept, role int64
|
||||
count int
|
||||
super bool
|
||||
}{
|
||||
{name: "仅本人", roleScope: "5", dept: 10, role: 82, count: 1},
|
||||
{name: "本部门", roleScope: "3", dept: 10, role: 82, count: 1},
|
||||
{name: "本部门及下级", roleScope: "4", dept: 10, role: 82, count: 3},
|
||||
{name: "自定义部门", roleScope: "2", dept: 10, role: 82, count: 1},
|
||||
{name: "全部仍隔离租户", roleScope: "1", dept: 10, role: 82, count: 4},
|
||||
{name: "部门及下级或本人", roleScope: "6", dept: 40, role: 82, count: 2},
|
||||
{name: "本组织及下一级", roleScope: "7", dept: 10, role: 82, count: 2},
|
||||
{name: "本组织下一级", roleScope: "8", dept: 10, role: 82, count: 1},
|
||||
{name: "无下一级", roleScope: "8", dept: 40, role: 82, count: 0},
|
||||
{name: "自定义空集合", roleScope: "2", dept: 10, role: 99, count: 0},
|
||||
{name: "菜单收窄角色", roleScope: "1", menuScope: "5", dept: 10, role: 82, count: 1},
|
||||
{name: "菜单放宽角色", roleScope: "5", menuScope: "1", dept: 10, role: 82, count: 4},
|
||||
{name: "无角色", dept: 10, count: 0},
|
||||
{name: "未知范围", roleScope: "unknown", dept: 10, role: 82, count: 0},
|
||||
{name: "超管仍隔离租户", dept: 10, role: consts.SuperAdminRoleId, count: 4, super: true},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
roles := []model.Role{}
|
||||
if tc.role > 0 {
|
||||
roles = append(roles, model.Role{RoleId: tc.role, DataScope: tc.roleScope})
|
||||
}
|
||||
testCtx := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 7, DeptId: tc.dept, TenantId: "A", Roles: roles}}})
|
||||
if tc.menuScope != "" {
|
||||
contexts.SetDataValue(testCtx, "currentRoleId", "82")
|
||||
contexts.SetDataValue(testCtx, "currentRoleDataScope", tc.menuScope)
|
||||
}
|
||||
list, total, err := List(testCtx, nil)
|
||||
if err != nil || total != tc.count {
|
||||
t.Fatalf("total=%d want=%d err=%v", total, tc.count, err)
|
||||
}
|
||||
for _, item := range list {
|
||||
if _, err := Summary(testCtx, item.BatchNo); err != nil {
|
||||
t.Fatal("列表与概览范围不一致", err)
|
||||
}
|
||||
}
|
||||
if _, err := Summary(testCtx, "other-tenant"); err == nil {
|
||||
t.Fatal("泄露其他租户")
|
||||
}
|
||||
if _, _, err := Details(testCtx, &model.AppExecutionLogDetailParam{BatchNo: "other-tenant"}); err == nil {
|
||||
t.Fatal("泄露其他租户明细")
|
||||
}
|
||||
visibleOther := false
|
||||
for _, item := range list {
|
||||
if item.BatchNo == "other-user" {
|
||||
visibleOther = true
|
||||
}
|
||||
}
|
||||
rows, total, err := Details(testCtx, &model.AppExecutionLogDetailParam{BatchNo: "other-user"})
|
||||
if visibleOther {
|
||||
if err != nil || total != 1 || rows[0].ItemId != "other-card" {
|
||||
t.Fatalf("可见部门明细缺失: %v %d %v", rows, total, err)
|
||||
}
|
||||
} else if err == nil {
|
||||
t.Fatal("不可见批次明细被放行")
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
for _, sql := range []string{
|
||||
`INSERT INTO batch_main(id,batch_no,batch_type,source_batch_no,batch_info,tenant_id,created_by) VALUES (4,'PARENT',3,'','{"jobRole":"allocate_parent"}','A',7),(5,'CHILD',3,'PARENT','{"jobRole":"allocate_chunk"}','A',7),(6,'FOREIGN-CHILD',3,'PARENT','{"jobRole":"allocate_chunk"}','A',8),(7,'RELATED',3,'PARENT','{}','A',7)`,
|
||||
"INSERT INTO batch_detail(id,batch_no,row_no,item_id,detail_status,error_code,error_reason,tenant_id,created_by) VALUES(3,'PARENT',1,'parent-card',2,'','','A',7),(4,'CHILD',1,'mine-child',2,'','','A',7),(5,'FOREIGN-CHILD',1,'foreign-child',2,'','','A',8),(6,'RELATED',1,'related-child',2,'','','A',7)",
|
||||
} {
|
||||
if _, err := g.DB().Exec(ctx, sql); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, sql := range []string{
|
||||
`UPDATE batch_main SET target_dept_id=20,batch_info='{"jobRole":"allocate_parent","sourceDeptName":"提交时划拨单位","targetDeptName":"提交时接收单位"}' WHERE batch_no='PARENT'`,
|
||||
`UPDATE batch_detail SET snapshot='{"sourceDeptId":10,"targetDeptId":20,"sourceDeptName":"明细划拨单位","targetDeptName":"明细接收单位"}' WHERE id=4`,
|
||||
} {
|
||||
if _, err := g.DB().Exec(ctx, sql); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
summary, err := Summary(ctx, "PARENT")
|
||||
if err != nil || summary.SourceDeptName != "提交时划拨单位" || summary.TargetDeptName != "提交时接收单位" {
|
||||
t.Fatal("概览未优先使用历史名称", summary, err)
|
||||
}
|
||||
details, total, err = Details(ctx, &model.AppExecutionLogDetailParam{BatchNo: "PARENT"})
|
||||
if err != nil || total != 3 || len(details) != 3 {
|
||||
t.Fatalf("child isolation: %+v %d %v", details, total, err)
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
for _, detail := range details {
|
||||
if detail.ItemId == "mine-child" && (detail.SourceDeptName != "明细划拨单位" || detail.TargetDeptName != "明细接收单位") {
|
||||
t.Fatal("明细快照名称被覆盖", detail)
|
||||
}
|
||||
if detail.ItemId != "mine-child" && detail.TargetDeptName != "提交时接收单位" {
|
||||
t.Fatal("明细未继承批次历史接收单位", detail)
|
||||
}
|
||||
seen[detail.ItemId] = true
|
||||
}
|
||||
for _, itemID := range []string{"parent-card", "mine-child", "related-child"} {
|
||||
if !seen[itemID] {
|
||||
t.Fatalf("parent details missing %s: %+v", itemID, details)
|
||||
}
|
||||
}
|
||||
list, total, err = List(ctx, nil)
|
||||
if err != nil || total != 2 {
|
||||
t.Fatalf("children appeared as submissions: %+v %d %v", list, total, err)
|
||||
}
|
||||
if _, err := AllocateSummary(ctx, "PARENT"); err != nil {
|
||||
t.Fatal("allocate result rejected", err)
|
||||
}
|
||||
if _, total, err := AllocateDetails(ctx, &model.AppExecutionLogDetailParam{BatchNo: "PARENT"}); err != nil || total != 3 {
|
||||
t.Fatal("allocate details rejected", total, err)
|
||||
}
|
||||
allCtx := contexts.Set(context.Background(), &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{ID: 8, DeptId: 20, TenantId: "A", Roles: []model.Role{{RoleId: 82, DataScope: consts.SysRoleDataScopeAll}}}}})
|
||||
if _, err := Summary(allCtx, "PARENT"); err != nil {
|
||||
t.Fatal("全部范围不能查看他人批次", err)
|
||||
}
|
||||
if _, err := AllocateSummary(allCtx, "PARENT"); err == nil {
|
||||
t.Fatal("办理恢复接口泄露他人任务")
|
||||
}
|
||||
if _, _, err := AllocateDetails(allCtx, &model.AppExecutionLogDetailParam{BatchNo: "PARENT"}); err == nil {
|
||||
t.Fatal("办理明细接口泄露他人任务")
|
||||
}
|
||||
for _, no := range []string{"mine", "CHILD", "RELATED", "other-user", "other-tenant", "missing"} {
|
||||
if _, err := AllocateSummary(ctx, no); err == nil {
|
||||
t.Fatalf("allocate summary exposed %s", no)
|
||||
}
|
||||
if _, _, err := AllocateDetails(ctx, &model.AppExecutionLogDetailParam{BatchNo: no}); err == nil {
|
||||
t.Fatalf("allocate details exposed %s", no)
|
||||
}
|
||||
}
|
||||
for _, no := range []string{"CHILD", "RELATED"} {
|
||||
if _, err := Summary(ctx, no); err == nil {
|
||||
t.Fatalf("child exposed as a standalone submission: %s", no)
|
||||
}
|
||||
}
|
||||
if _, err := g.DB().Exec(ctx, "INSERT INTO batch_main(id,batch_no,batch_type,source_batch_no,tenant_id,created_by) VALUES (8,'SELF',3,'SELF','A',7)"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := g.DB().Exec(ctx, "INSERT INTO batch_detail(id,batch_no,row_no,item_id,detail_status,error_code,error_reason,tenant_id,created_by) VALUES(7,'SELF',1,'self-card',2,'','','A',7)"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := Summary(ctx, "SELF"); err != nil {
|
||||
t.Fatal("self-referencing allocation hidden", err)
|
||||
}
|
||||
details, total, err = Details(ctx, &model.AppExecutionLogDetailParam{BatchNo: "SELF"})
|
||||
if err != nil || total != 1 || len(details) != 1 || details[0].ItemId != "self-card" {
|
||||
t.Fatalf("self allocation details lost: %+v %d %v", details, total, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeReason(t *testing.T) {
|
||||
for _, s := range []string{"token=abc", "dial tcp 192.0.2.10", "secret=abc", "panic\nstack", "https://internal"} {
|
||||
if safeReason(s) == s {
|
||||
t.Fatalf("sensitive reason exposed: %s", s)
|
||||
}
|
||||
}
|
||||
if safeReason("套餐已过期") != "套餐已过期" {
|
||||
t.Fatal("business explanation lost")
|
||||
}
|
||||
p, n := paging(0, 5000)
|
||||
if p != 1 || n != 100 {
|
||||
t.Fatal(p, n)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/xgorm/handler"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/genin"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/utility/tree"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type (
|
||||
IGenTestDemo interface {
|
||||
// Model 测试单表ORM模型
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
// List 获取测试单表列表
|
||||
List(ctx context.Context, in *genin.TestDemoListParam) (list []*genin.TestDemoListModel, totalCount int, err error)
|
||||
// Export 导出测试单表
|
||||
Export(ctx context.Context, in *genin.TestDemoListParam) (err error)
|
||||
// Edit 修改/新增测试单表
|
||||
Edit(ctx context.Context, in *genin.TestDemoEditParam) (err error)
|
||||
// Delete 删除测试单表
|
||||
Delete(ctx context.Context, in *genin.TestDemoDeleteParam) (err error)
|
||||
// View 获取测试单表指定信息
|
||||
View(ctx context.Context, in *genin.TestDemoViewParam) (res *genin.TestDemoViewModel, err error)
|
||||
}
|
||||
IGenTestTree interface {
|
||||
// Model 测试树表ORM模型
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
// List 获取测试树表列表
|
||||
List(ctx context.Context, in *genin.TestTreeListParam) (list []*genin.TestTreeListModel, totalCount int, err error)
|
||||
// Export 导出测试树表
|
||||
Export(ctx context.Context, in *genin.TestTreeListParam) (err error)
|
||||
// Edit 修改/新增测试树表
|
||||
Edit(ctx context.Context, in *genin.TestTreeEditParam) (err error)
|
||||
// Delete 删除测试树表
|
||||
Delete(ctx context.Context, in *genin.TestTreeDeleteParam) (err error)
|
||||
// View 获取测试树表指定信息
|
||||
View(ctx context.Context, in *genin.TestTreeViewParam) (res *genin.TestTreeViewModel, err error)
|
||||
// TreeOption 获取测试树表关系树选项
|
||||
TreeOption(ctx context.Context) (nodes []tree.Node, err error)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localGenTestDemo IGenTestDemo
|
||||
localGenTestTree IGenTestTree
|
||||
)
|
||||
|
||||
func GenTestDemo() IGenTestDemo {
|
||||
if localGenTestDemo == nil {
|
||||
panic("implement not found for interface IGenTestDemo, forgot register?")
|
||||
}
|
||||
return localGenTestDemo
|
||||
}
|
||||
|
||||
func RegisterGenTestDemo(i IGenTestDemo) {
|
||||
localGenTestDemo = i
|
||||
}
|
||||
|
||||
func GenTestTree() IGenTestTree {
|
||||
if localGenTestTree == nil {
|
||||
panic("implement not found for interface IGenTestTree, forgot register?")
|
||||
}
|
||||
return localGenTestTree
|
||||
}
|
||||
|
||||
func RegisterGenTestTree(i IGenTestTree) {
|
||||
localGenTestTree = i
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/xgorm/handler"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type (
|
||||
ISysGenTable interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
// 列表
|
||||
List(ctx context.Context, param *model.SysGenTableListParam) (output []*model.SysGenTableListModel, total int, err error)
|
||||
// 详情
|
||||
View(ctx context.Context, param *model.SysGenTableViewParam) (output *model.SysGenTableViewModel, err error)
|
||||
// 新增
|
||||
Add(ctx context.Context, param *model.SysGenTableAddParam) (output *model.SysGenTableAddModel, err error)
|
||||
// 修改
|
||||
Edit(ctx context.Context, param *model.SysGenTableEditParam) (output *model.SysGenTableEditModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysGenTableDeleteParam) (output *model.SysGenTableDeleteModel, err error)
|
||||
// 获取选择项
|
||||
Selects(ctx context.Context) (output *model.SelectsModel, err error)
|
||||
// 获取表选择项
|
||||
TableSelect(ctx context.Context, param *model.GenCodesTableSelectParam) (output []*model.GenCodesTableSelectModel, err error)
|
||||
// 获取字段选择项
|
||||
ColumnSelect(ctx context.Context, param *model.GenCodesColumnSelectParam) (output []*model.GenCodesColumnSelectModel, err error)
|
||||
// 获取字段列表
|
||||
ColumnList(ctx context.Context, param *model.GenCodesColumnListParam) (output []*model.GenCodesColumnListModel, err error)
|
||||
// 预览
|
||||
Preview(ctx context.Context, param *model.GenCodesPreviewParam) (output *model.GenCodesPreviewModel, err error)
|
||||
// 构建
|
||||
Build(ctx context.Context, param *model.GenCodesBuildParam) (output *model.GenCodesBuildModel, err error)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localSysGenTable ISysGenTable
|
||||
)
|
||||
|
||||
func SysGenTable() ISysGenTable {
|
||||
if localSysGenTable == nil {
|
||||
panic("implement not found for interface ISysGenTable, forgot register?")
|
||||
}
|
||||
return localSysGenTable
|
||||
}
|
||||
|
||||
func RegisterSysGenTable(i ISysGenTable) {
|
||||
localSysGenTable = i
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
)
|
||||
|
||||
type (
|
||||
IInfo interface {
|
||||
GetInfo() *model.InfoModel
|
||||
SetInfoName(Type string, Name string, Title string, Description string)
|
||||
SetInfoBuild(buildVersion string, buildTime string, commitID string)
|
||||
SetInfoData(data map[string]interface{})
|
||||
GetInfoData() map[string]interface{}
|
||||
AddInfoData(key string, value interface{})
|
||||
DelInfoData(key string)
|
||||
GetInfoDataByKey(key string) interface{}
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localInfo IInfo
|
||||
)
|
||||
|
||||
func Info() IInfo {
|
||||
if localInfo == nil {
|
||||
panic("implement not found for interface IInfo, forgot register?")
|
||||
}
|
||||
return localInfo
|
||||
}
|
||||
|
||||
func RegisterInfo(i IInfo) {
|
||||
localInfo = i
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
)
|
||||
|
||||
type (
|
||||
IMemoryDB interface {
|
||||
Init(ctx context.Context) error
|
||||
EventHandler(ctx context.Context, chg *model.BroadcastDbChgCache) error
|
||||
DB(ctx context.Context) gdb.DB
|
||||
Ctx(ctx context.Context) gdb.DB
|
||||
}
|
||||
IMemDBSysConfig interface {
|
||||
Init(ctx context.Context) error
|
||||
EventHandler(ctx context.Context) error
|
||||
TableName(ctx context.Context) string
|
||||
CreateTable(ctx context.Context) error
|
||||
LoadData(ctx context.Context, pk int64) error
|
||||
DeleteData(ctx context.Context, ids []int64) error
|
||||
}
|
||||
IMemDBSysDept interface {
|
||||
Init(ctx context.Context) error
|
||||
EventHandler(ctx context.Context) error
|
||||
TableName(ctx context.Context) string
|
||||
CreateTable(ctx context.Context) error
|
||||
LoadData(ctx context.Context, pk int64) error
|
||||
DeleteData(ctx context.Context, ids []int64) error
|
||||
}
|
||||
IMemDBSysDictData interface {
|
||||
Init(ctx context.Context) error
|
||||
EventHandler(ctx context.Context) error
|
||||
TableName(ctx context.Context) string
|
||||
CreateTable(ctx context.Context) error
|
||||
LoadData(ctx context.Context, pk int64) error
|
||||
DeleteData(ctx context.Context, ids []int64) error
|
||||
}
|
||||
IMemDBSysDictType interface {
|
||||
Init(ctx context.Context) error
|
||||
EventHandler(ctx context.Context) error
|
||||
TableName(ctx context.Context) string
|
||||
CreateTable(ctx context.Context) error
|
||||
LoadData(ctx context.Context, pk int64) error
|
||||
DeleteData(ctx context.Context, ids []int64) error
|
||||
}
|
||||
IMemDBSysMenu interface {
|
||||
Init(ctx context.Context) error
|
||||
EventHandler(ctx context.Context) error
|
||||
TableName(ctx context.Context) string
|
||||
CreateTable(ctx context.Context) error
|
||||
LoadData(ctx context.Context, pk int64) error
|
||||
DeleteData(ctx context.Context, ids []int64) error
|
||||
}
|
||||
IMemDBSysPost interface {
|
||||
Init(ctx context.Context) error
|
||||
EventHandler(ctx context.Context) error
|
||||
TableName(ctx context.Context) string
|
||||
CreateTable(ctx context.Context) error
|
||||
LoadData(ctx context.Context, pk int64) error
|
||||
DeleteData(ctx context.Context, ids []int64) error
|
||||
}
|
||||
IMemDBSysRole interface {
|
||||
Init(ctx context.Context) error
|
||||
EventHandler(ctx context.Context) error
|
||||
TableName(ctx context.Context) string
|
||||
CreateTable(ctx context.Context) error
|
||||
LoadData(ctx context.Context, pk int64) error
|
||||
DeleteData(ctx context.Context, ids []int64) error
|
||||
}
|
||||
IMemDBSysTenant interface {
|
||||
Init(ctx context.Context) error
|
||||
EventHandler(ctx context.Context) error
|
||||
DB(ctx context.Context) gdb.DB
|
||||
TableName(ctx context.Context) string
|
||||
CreateTable(ctx context.Context) error
|
||||
LoadData(ctx context.Context, pk int64) error
|
||||
DeleteData(ctx context.Context, ids []int64) error
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localMemoryDB IMemoryDB
|
||||
localMemDBSysConfig IMemDBSysConfig
|
||||
localMemDBSysDept IMemDBSysDept
|
||||
localMemDBSysDictData IMemDBSysDictData
|
||||
localMemDBSysDictType IMemDBSysDictType
|
||||
localMemDBSysMenu IMemDBSysMenu
|
||||
localMemDBSysPost IMemDBSysPost
|
||||
localMemDBSysRole IMemDBSysRole
|
||||
localMemDBSysTenant IMemDBSysTenant
|
||||
)
|
||||
|
||||
func MemoryDB() IMemoryDB {
|
||||
if localMemoryDB == nil {
|
||||
panic("implement not found for interface IMemoryDB, forgot register?")
|
||||
}
|
||||
return localMemoryDB
|
||||
}
|
||||
|
||||
func RegisterMemoryDB(i IMemoryDB) {
|
||||
localMemoryDB = i
|
||||
}
|
||||
|
||||
func MemDBSysConfig() IMemDBSysConfig {
|
||||
if localMemDBSysConfig == nil {
|
||||
panic("implement not found for interface IMemDBSysConfig, forgot register?")
|
||||
}
|
||||
return localMemDBSysConfig
|
||||
}
|
||||
|
||||
func RegisterMemDBSysConfig(i IMemDBSysConfig) {
|
||||
localMemDBSysConfig = i
|
||||
}
|
||||
|
||||
func MemDBSysDept() IMemDBSysDept {
|
||||
if localMemDBSysDept == nil {
|
||||
panic("implement not found for interface IMemDBSysDept, forgot register?")
|
||||
}
|
||||
return localMemDBSysDept
|
||||
}
|
||||
|
||||
func RegisterMemDBSysDept(i IMemDBSysDept) {
|
||||
localMemDBSysDept = i
|
||||
}
|
||||
|
||||
func MemDBSysDictData() IMemDBSysDictData {
|
||||
if localMemDBSysDictData == nil {
|
||||
panic("implement not found for interface IMemDBSysDictData, forgot register?")
|
||||
}
|
||||
return localMemDBSysDictData
|
||||
}
|
||||
|
||||
func RegisterMemDBSysDictData(i IMemDBSysDictData) {
|
||||
localMemDBSysDictData = i
|
||||
}
|
||||
|
||||
func MemDBSysDictType() IMemDBSysDictType {
|
||||
if localMemDBSysDictType == nil {
|
||||
panic("implement not found for interface IMemDBSysDictType, forgot register?")
|
||||
}
|
||||
return localMemDBSysDictType
|
||||
}
|
||||
|
||||
func RegisterMemDBSysDictType(i IMemDBSysDictType) {
|
||||
localMemDBSysDictType = i
|
||||
}
|
||||
|
||||
func MemDBSysMenu() IMemDBSysMenu {
|
||||
if localMemDBSysMenu == nil {
|
||||
panic("implement not found for interface IMemDBSysMenu, forgot register?")
|
||||
}
|
||||
return localMemDBSysMenu
|
||||
}
|
||||
|
||||
func RegisterMemDBSysMenu(i IMemDBSysMenu) {
|
||||
localMemDBSysMenu = i
|
||||
}
|
||||
|
||||
func MemDBSysPost() IMemDBSysPost {
|
||||
if localMemDBSysPost == nil {
|
||||
panic("implement not found for interface IMemDBSysPost, forgot register?")
|
||||
}
|
||||
return localMemDBSysPost
|
||||
}
|
||||
|
||||
func RegisterMemDBSysPost(i IMemDBSysPost) {
|
||||
localMemDBSysPost = i
|
||||
}
|
||||
|
||||
func MemDBSysRole() IMemDBSysRole {
|
||||
if localMemDBSysRole == nil {
|
||||
panic("implement not found for interface IMemDBSysRole, forgot register?")
|
||||
}
|
||||
return localMemDBSysRole
|
||||
}
|
||||
|
||||
func RegisterMemDBSysRole(i IMemDBSysRole) {
|
||||
localMemDBSysRole = i
|
||||
}
|
||||
|
||||
func MemDBSysTenant() IMemDBSysTenant {
|
||||
if localMemDBSysTenant == nil {
|
||||
panic("implement not found for interface IMemDBSysTenant, forgot register?")
|
||||
}
|
||||
return localMemDBSysTenant
|
||||
}
|
||||
|
||||
func RegisterMemDBSysTenant(i IMemDBSysTenant) {
|
||||
localMemDBSysTenant = i
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
type (
|
||||
IMiddleware interface {
|
||||
// 响应处理中间件
|
||||
ResponseHandler(r *ghttp.Request)
|
||||
// Ctx 自定义上下文对象
|
||||
Ctx(r *ghttp.Request)
|
||||
// CORS 跨域处理
|
||||
CORS(r *ghttp.Request)
|
||||
// Auth 认证处理
|
||||
Auth(r *ghttp.Request)
|
||||
// IsExceptLogin 判断是否需要验证登录
|
||||
IsExceptLogin(ctx context.Context, path string) bool
|
||||
// OperationLog 操作日志
|
||||
OperationLog(r *ghttp.Request)
|
||||
// ResponseHandlerRaw 返回处理中间件
|
||||
ResponseHandlerRaw(r *ghttp.Request)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localMiddleware IMiddleware
|
||||
)
|
||||
|
||||
func Middleware() IMiddleware {
|
||||
if localMiddleware == nil {
|
||||
panic("implement not found for interface IMiddleware, forgot register?")
|
||||
}
|
||||
return localMiddleware
|
||||
}
|
||||
|
||||
func RegisterMiddleware(i IMiddleware) {
|
||||
localMiddleware = i
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
)
|
||||
|
||||
type (
|
||||
IMonitorServer interface {
|
||||
GetGoInfo(ctx context.Context) (res *model.GoRunInfo)
|
||||
// GetHostInfo 获取主机信息
|
||||
GetHostInfo(ctx context.Context) (data []byte)
|
||||
// GetSysLoad 获取系统负载信息
|
||||
GetSysLoad(ctx context.Context) (data []byte)
|
||||
// GetCpuInfo 获取CPU信息
|
||||
GetCpuInfo(ctx context.Context) (data []byte)
|
||||
// GetMemInfo 获取内存信息
|
||||
GetMemInfo(ctx context.Context) (data []byte)
|
||||
// GetDiskInfo 获取磁盘信息
|
||||
GetDiskInfo(ctx context.Context) (data []byte)
|
||||
// GetNetStatusInfo 获取网络信息
|
||||
GetNetStatusInfo(ctx context.Context) (data []byte)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localMonitorServer IMonitorServer
|
||||
)
|
||||
|
||||
func MonitorServer() IMonitorServer {
|
||||
if localMonitorServer == nil {
|
||||
panic("implement not found for interface IMonitorServer, forgot register?")
|
||||
}
|
||||
return localMonitorServer
|
||||
}
|
||||
|
||||
func RegisterMonitorServer(i IMonitorServer) {
|
||||
localMonitorServer = i
|
||||
}
|
||||
@@ -0,0 +1,612 @@
|
||||
// ================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// You can delete these comments if you wish manually maintain this interface file.
|
||||
// ================================================================================
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "git.5iot.com/iotlcm-public/iotlcm-app/api/system/v1"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/xgorm/handler"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/request"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
type (
|
||||
ISysAuth interface {
|
||||
Login(ctx context.Context, param *model.LoginParams) (res *model.LoginUserOut, token string, err error)
|
||||
// 生成Token
|
||||
GenerateToken(ctx context.Context, user *model.LoginUserOut) (claims *model.CustomClaims, token string, err error)
|
||||
// 解析Token
|
||||
ParseToken(ctx context.Context, token string) (claims *model.CustomClaims, err error)
|
||||
// 删除Token
|
||||
DeleteToken(ctx context.Context, token string) (err error)
|
||||
// 获取token
|
||||
GetAccessToken(ctx context.Context) (token string, err error)
|
||||
// 根据Token获取当前登录用户信息
|
||||
GetCurrentUser(ctx context.Context) (claims *model.CustomClaims, err error)
|
||||
// 获取用户权限码
|
||||
GetUserAccessCodeList(ctx context.Context, userId int64) (accessCodeList []string, menuRoleAccessCodeList []string, err error)
|
||||
// 根据openId登录
|
||||
LoginByOpenId(ctx context.Context, social *model.SysSocialListModel) (res *model.LoginUserOut, token string, err error)
|
||||
}
|
||||
ISysCaptcha interface {
|
||||
// 生成验证码
|
||||
GenerateCaptcha(ctx context.Context) (key string, image string, err error)
|
||||
// 验证验证码
|
||||
VerifyCaptcha(ctx context.Context, key string, value string) (err error)
|
||||
}
|
||||
ISysClient interface {
|
||||
List(ctx context.Context, query *model.SysClientListParam) (items []*model.SysClientListModel, total int, err error)
|
||||
View(ctx context.Context, param *model.SysClientViewParam) (item *model.SysClientViewModel, err error)
|
||||
Add(ctx context.Context, param *model.SysClientAddParam) (output *model.SysClientAddModel, err error)
|
||||
Edit(ctx context.Context, param *model.SysClientEditParam) (output *model.SysClientEditModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysClientDeleteParam) (output *model.SysClientDeleteModel, err error)
|
||||
Status(ctx context.Context, param *model.SysClientStatusParam) (output *model.SysClientStatusModel, err error)
|
||||
}
|
||||
ISysConfig interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
ModelQuery(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, param *model.SysConfigListParam) (items []*model.SysConfigListModel, total int, err error)
|
||||
Add(ctx context.Context, param *model.SysConfigAddParam) (output *model.SysConfigAddModel, err error)
|
||||
Edit(ctx context.Context, param *model.SysConfigEditParam) (output *model.SysConfigEditModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysConfigDeleteParam) (output *model.SysConfigDeleteModel, err error)
|
||||
View(ctx context.Context, param *model.SysConfigViewParam) (output *model.SysConfigViewModel, err error)
|
||||
GetConfigByKey(ctx context.Context, configKey string) (config *entity.SysConfig, err error)
|
||||
}
|
||||
ISysDept interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
ModelQuery(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
GetDeptList(ctx context.Context, query model.SysDeptListParam) (items []*model.SysDeptListModel, total int, err error)
|
||||
GetDeptById(ctx context.Context, id int64) (dept *model.SysDeptViewModel, err error)
|
||||
// 构建树结构
|
||||
DeptTree(ctx context.Context, parentDept *model.SysDeptTreeModel, deptList []*model.SysDeptListModel, ancestors string) (data []*model.SysDeptTreeModel, err error)
|
||||
GetDeptTree(ctx context.Context, query model.SysDeptTreeParam) (items []*model.SysDeptTreeModel, err error)
|
||||
// 递归构建结构
|
||||
RecursionDeptIds(ctx context.Context, parentId int64, deptList []*model.SysDeptListModel, data *[]int64) (err error)
|
||||
// 根据父部门id获取部门列表
|
||||
GetDeptIdsByParentId(ctx context.Context, parentId int64) (ids []int64, err error)
|
||||
AddDept(ctx context.Context, dept *model.SysDeptAddModel) (deptId int64, err error)
|
||||
EditDept(ctx context.Context, dept *model.SysDeptEditModel) (deptId int64, err error)
|
||||
DeleteDept(ctx context.Context, dept *model.SysDeptDeleteModel) (deptId int64, err error)
|
||||
// 刷新部门 ancestors
|
||||
RefreshDeptAncestors(ctx context.Context) (err error)
|
||||
GetParentIDAncestors(ctx context.Context, depts []*model.SysDeptViewModel, printId int64, ancestors *string) (err error)
|
||||
GetDeptListByIds(ctx context.Context, ids []int64) (depts []*model.SysDeptListModel, err error)
|
||||
// 验证上级是否是公司
|
||||
ValidateParentIsCompany(ctx context.Context, parentId int64) (isCompany bool, err error)
|
||||
// 获取组织公司Map
|
||||
GetDeptCompanyMap(ctx context.Context) (map[int64]string, error)
|
||||
// 获取上级公司组织信息
|
||||
GetParentCompanyInfo(ctx context.Context, deptId int64) *model.SysDeptListModel
|
||||
}
|
||||
ISysDictData interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
ModelQuery(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, param *model.SysDictDataListParam) (items []model.SysDictDataListModel, total int, err error)
|
||||
View(ctx context.Context, param *model.SysDictDataViewParam) (data *model.SysDictDataViewModel, err error)
|
||||
Add(ctx context.Context, param *model.SysDictDataAddParam) (output *model.SysDictDataAddModel, err error)
|
||||
Edit(ctx context.Context, param *model.SysDictDataEditParam) (output *model.SysDictDataEditModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysDictDataDeleteParam) (output *model.SysDictDataDeleteModel, err error)
|
||||
GetDictLabel(ctx context.Context, dictType string, dictCode string) string
|
||||
GetDictListByTypes(ctx context.Context, dictTypes []string) (dictDataList []model.SysDictDataListModel, err error)
|
||||
}
|
||||
ISysDictType interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
ModelQuery(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, param *model.SysDictTypeListParam) (items []model.SysDictTypeListModel, total int, err error)
|
||||
View(ctx context.Context, param *model.SysDictTypeViewParam) (data *model.SysDictTypeViewModel, err error)
|
||||
Add(ctx context.Context, param *model.SysDictTypeAddParam) (output *model.SysDictTypeAddModel, err error)
|
||||
Edit(ctx context.Context, param *model.SysDictTypeEditParam) (output *model.SysDictTypeEditModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysDictTypeDeleteParam) (output *model.SysDictTypeDeleteModel, err error)
|
||||
}
|
||||
ISysJob interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, query *model.SysJobListParam, pageInfo *request.PageInfo) (Data []*model.SysJobListModel, total int, err error)
|
||||
View(ctx context.Context, jobId int64) (Data *model.SysJobViewModel, err error)
|
||||
Add(ctx context.Context, jobAdd *model.SysJobAddModel) (LastInsertId int64, err error)
|
||||
Update(ctx context.Context, jobUpdate *model.SysJobUpdateModel) (RowsAffected int64, err error)
|
||||
UpdateStatus(ctx context.Context, jobUpdate *model.SysJobUpdateStatusModel) (RowsAffected int64, err error)
|
||||
Delete(ctx context.Context, jobDelete *model.SysJobDeleteModel) (RowsAffected int64, err error)
|
||||
Exec(ctx context.Context, jobId int64) error
|
||||
// 查询所有的状态正常的任务列表,并进行初始注册
|
||||
InitRegister() error
|
||||
}
|
||||
ISysLogininfor interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, param *model.SysLogininforListParam) (items []*model.SysLogininforListModel, total int, err error)
|
||||
AddLogininfor(ctx context.Context, logininfor *model.SysLogininforAddModel) (id int64, err error)
|
||||
Delete(ctx context.Context, param *model.SysLogininforDeleteParam) (output *model.SysLogininforDeleteModel, err error)
|
||||
}
|
||||
ISysMenu interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
ModelQuery(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, param *model.SysMenuListParam) (data []*model.SysMenuListModel, total int, err error)
|
||||
// 获取租户菜单列表, 系统租户返回所有菜单,其他租户返回当前租户菜单
|
||||
GetTenantMenu(ctx context.Context, query *model.SysMenuListParam) (data []*model.SysMenuListModel, total int, err error)
|
||||
// 构建树结构
|
||||
MenuTree(ctx context.Context, parentMenu *model.SysMenuTree, menuList []*entity.SysMenu) (data []*model.SysMenuTree, err error)
|
||||
// 获取用户动态路由列表
|
||||
GetUserMenu(ctx context.Context) (data []*entity.SysMenu, err error)
|
||||
// 构建用户动态路由树
|
||||
BuildUserMenuTree(ctx context.Context, parentMenu *v1.RouteMenu, menuList []*entity.SysMenu, allPath string) (data v1.MenuAllRes, err error)
|
||||
// 获取用户动态路由树
|
||||
GetUserMenuTree(ctx context.Context) (data v1.MenuAllRes, err error)
|
||||
GetSysMenuView(ctx context.Context, menuId int64) (data *model.SysMenuViewModel, err error)
|
||||
UpdateSysMenu(ctx context.Context, menu *model.SysMenuUpdateModel) (data *model.SysMenuViewModel, err error)
|
||||
AddSysMenu(ctx context.Context, menu *model.SysMenuAddModel) (data *model.SysMenuViewModel, err error)
|
||||
DeleteSysMenu(ctx context.Context, menuId int64) (err error)
|
||||
GetFastList(ctx context.Context) (res map[int64]*entity.SysMenu, err error)
|
||||
}
|
||||
ISysNotice interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, param *model.SysNoticeListParam) (items []*model.SysNoticeListModel, total int, err error)
|
||||
Add(ctx context.Context, param *model.SysNoticeAddParam) (err error)
|
||||
Edit(ctx context.Context, param *model.SysNoticeEditParam) (err error)
|
||||
Delete(ctx context.Context, param *model.SysNoticeDeleteParam) (err error)
|
||||
View(ctx context.Context, param *model.SysNoticeViewParam) (data *model.SysNoticeViewModel, err error)
|
||||
}
|
||||
ISysNoticeUser interface {
|
||||
// Model 用户通知公告表ORM模型
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
// List 获取用户通知公告表列表
|
||||
List(ctx context.Context, in *model.SysNoticeUserListParam) (list []*model.SysNoticeUserListModel, totalCount int, err error)
|
||||
// Export 导出用户通知公告表
|
||||
Export(ctx context.Context, in *model.SysNoticeUserListParam) (err error)
|
||||
// Edit 修改/新增用户通知公告表
|
||||
Edit(ctx context.Context, in *model.SysNoticeUserEditParam) (err error)
|
||||
// Delete 删除用户通知公告表
|
||||
Delete(ctx context.Context, in *model.SysNoticeUserDeleteParam) (err error)
|
||||
// View 获取用户通知公告表指定信息
|
||||
View(ctx context.Context, in *model.SysNoticeUserViewParam) (res *model.SysNoticeUserViewModel, err error)
|
||||
// Status 更新用户通知公告表状态
|
||||
Status(ctx context.Context, in *model.SysNoticeUserStatusParam) (err error)
|
||||
// Read 已读
|
||||
Read(ctx context.Context, in *model.SysNoticeUserReadParam) (err error)
|
||||
}
|
||||
ISysOperLog interface {
|
||||
GetOperLogList(ctx context.Context, query *model.SysOperLogListParam, page *request.PageInfo) (items []*model.SysOperLogListModel, total int, err error)
|
||||
AnalysisLog(ctx context.Context) (data *model.SysOperLogAddParam, err error)
|
||||
ClearOperationLogByDays(ctx context.Context, days int) error
|
||||
RealWrite(ctx context.Context, data model.SysOperLogAddParam) (err error)
|
||||
}
|
||||
ISysOss interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, param *model.SysOssListParam, pageInfo *request.PageInfo) (items []*model.SysOssListModel, total int, err error)
|
||||
View(ctx context.Context, param *model.SysOssViewParam) (output *model.SysOssViewModel, err error)
|
||||
Download(ctx context.Context, param *model.SysOssDownloadParam) (output *model.SysOssDownloadModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysOssDeleteParam) (output *model.SysOssDeleteModel, err error)
|
||||
Upload(ctx context.Context, param *model.SysOssUploadParam) (output *model.SysOssUploadModel, err error)
|
||||
MoveFile(ctx context.Context, param *model.SysOssMoveFileParam) (output *model.SysOssMoveFileModel, err error)
|
||||
SaveContent(ctx context.Context, param *model.SysOssSaveContentParam) (output *model.SysOssSaveContentModel, err error)
|
||||
GetSaveFilePathConfig(ctx context.Context, newFileType int, notAddDate int) (string, error)
|
||||
MoveFileLocal(ctx context.Context, filePath string, newFileType int, useOriginalName int, subDirName string, isAddDate int) (result model.UploadResponse, err error)
|
||||
// 保存内容
|
||||
SaveContentLocal(ctx context.Context, content []byte, newFileType int, fileName string, subDirName string, isAddDate int) (result model.UploadResponse, err error)
|
||||
UploadLocal(ctx context.Context, file *ghttp.UploadFile, newFileType int, useOriginalName int, subDirName string, notAddDate int) (result model.UploadResponse, err error)
|
||||
DownloadLocal(ctx context.Context, file *entity.SysOss) (err error)
|
||||
DeleteLocal(ctx context.Context, file *entity.SysOss) (err error)
|
||||
CheckType(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error)
|
||||
CheckSize(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error)
|
||||
GetAllUrl(ctx context.Context, url string) (allUrl string, ossId int64, fileSize int64, OriginalName string, md5 string, hmac string, err error)
|
||||
}
|
||||
ISysOssConfig interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, param *model.SysOssConfigListParam) (items []*model.SysOssConfigListModel, total int, err error)
|
||||
View(ctx context.Context, param *model.SysOssConfigViewParam) (item *model.SysOssConfigViewModel, err error)
|
||||
Add(ctx context.Context, param *model.SysOssConfigAddParam) (item *model.SysOssConfigAddModel, err error)
|
||||
Edit(ctx context.Context, param *model.SysOssConfigEditParam) (item *model.SysOssConfigEditModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysOssConfigDeleteParam) (item *model.SysOssConfigDeleteModel, err error)
|
||||
GetAllUrlByService(ctx context.Context, path string, tenantId string, ossService string) (allUrl string, err error)
|
||||
}
|
||||
ISysPost interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
ModelQuery(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
List(ctx context.Context, query *model.SysPostListParam) (items []*model.SysPostListModel, total int, err error)
|
||||
View(ctx context.Context, param *model.SysPostViewParam) (post *model.SysPostViewModel, err error)
|
||||
Add(ctx context.Context, param *model.SysPostAddParam) (post *model.SysPostAddModel, err error)
|
||||
Edit(ctx context.Context, param *model.SysPostEditParam) (post *model.SysPostEditModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysPostDeleteParam) (post *model.SysPostDeleteModel, err error)
|
||||
Export(ctx context.Context, param *model.SysPostExportParam) (post *model.SysPostExportModel, err error)
|
||||
}
|
||||
ISysQrcode interface {
|
||||
// 获取登录二维码
|
||||
GetQrcodeLogin(ctx context.Context) (res *model.QrcodeLoginModel, err error)
|
||||
// 获取登录二维码扫码结果
|
||||
GetQrcodeLoginStatus(ctx context.Context, tempUserId string) (res *model.QrcodeLoginModel, err error)
|
||||
// 获取绑定二维码
|
||||
GetQrcodeBind(ctx context.Context) (res *model.QrcodeCacheModel, err error)
|
||||
// 获取绑定二维码扫码结果
|
||||
GetQrcodeBindStatus(ctx context.Context) (res *model.QrcodeBindStatusModel, err error)
|
||||
// 扫码回调
|
||||
QrcodeScanCallback(ctx context.Context, param *model.QrcodeScanCallbackParam) (err error)
|
||||
// 扫码后选择用户登录
|
||||
QrcodeLoginSelectUserId(ctx context.Context, param *model.QrcodeLoginSelectUserIdParam) (res *model.QrcodeLoginAndBindOpenIdModel, err error)
|
||||
// 登录并绑定
|
||||
QrcodeLoginAndBindOpenId(ctx context.Context, param *model.QrcodeLoginAndBindOpenIdParam) (res *model.QrcodeLoginAndBindOpenIdModel, err error)
|
||||
// 注册并绑定
|
||||
QrcodeRegisterAndBindOpenId(ctx context.Context, param *model.QrcodeRegisterAndBindOpenIdParam) (res *model.QrcodeLoginAndBindOpenIdModel, err error)
|
||||
}
|
||||
ISysRole interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
ModelQuery(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
// 获取租户下角色列表
|
||||
List(ctx context.Context, param *model.SysRoleListParam) (res []*model.SysRoleListModel, total int, err error)
|
||||
// 获取角色详情
|
||||
View(ctx context.Context, param *model.SysRoleViewParam) (res *model.SysRoleViewModel, err error)
|
||||
// 获取角色菜单
|
||||
GetRoleMenu(ctx context.Context, id int64) (res []*entity.SysMenu, err error)
|
||||
// 获取角色部门
|
||||
GetRoleDept(ctx context.Context, id int64) (res []*entity.SysDept, err error)
|
||||
// 获取角色列表对应菜单
|
||||
GetRoleListMenu(ctx context.Context, ids []int64) (res []*entity.SysRoleMenu, err error)
|
||||
// 新增角色
|
||||
Add(ctx context.Context, param *model.SysRoleAddParam) (role *model.SysRoleAddModel, err error)
|
||||
// 编辑角色
|
||||
Edit(ctx context.Context, param *model.SysRoleEditParam) (role *model.SysRoleEditModel, err error)
|
||||
// 删除角色
|
||||
Delete(ctx context.Context, param *model.SysRoleDeleteParam) (role *model.SysRoleDeleteModel, err error)
|
||||
RoleMenu(ctx context.Context, roleId int64, menuIds []int64) (err error)
|
||||
// 自定义角色部门数据权限
|
||||
RoleDept(ctx context.Context, roleId int64, deptIds []int64) (err error)
|
||||
// 编辑角色数据权限
|
||||
EditRoleDataScope(ctx context.Context, model *model.SysRoleDataScopeEditParam) (err error)
|
||||
}
|
||||
ISysSocial interface {
|
||||
// 查询社会化关系表
|
||||
List(ctx context.Context, query *model.SysSocialListParam, page *request.PageInfo) (items []*model.SysSocialListModel, total int, err error)
|
||||
// 删除社会化关系表
|
||||
Delete(ctx context.Context, id int64) (err error)
|
||||
Create(ctx context.Context, social *model.SysSocialSaveParam) (err error)
|
||||
}
|
||||
ISysTenant interface {
|
||||
ModelQuery(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
// 获取租户信息
|
||||
View(ctx context.Context, param *model.SysTenantViewParam) (data *model.SysTenantViewModel, err error)
|
||||
// 获取租户列表
|
||||
List(ctx context.Context, param *model.SysTenantListParam) (data []*model.SysTenantListModel, total int, err error)
|
||||
Add(ctx context.Context, param *model.SysTenantAddParam) (output *model.SysTenantAddModel, err error)
|
||||
Edit(ctx context.Context, param *model.SysTenantEditParam) (output *model.SysTenantEditModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysTenantDeleteParam) (output *model.SysTenantDeleteModel, err error)
|
||||
Status(ctx context.Context, param *model.SysTenantStatusParam) (output *model.SysTenantStatusModel, err error)
|
||||
// 新建租户插入系统参数表数据
|
||||
BatchInsertSysParam(ctx context.Context, tx gdb.TX, tenantId string, createdBy int64, createdDept int64) (ids []int64, err error)
|
||||
// 同步租户菜单
|
||||
SyncTenantMenu(ctx context.Context, tenantId string) (err error)
|
||||
// 查询用户ID是否是租户管理员
|
||||
IsTenantAdmin(ctx context.Context, userIds []int64) (isAdminUserIds []int64, err error)
|
||||
}
|
||||
ISysTenantPackage interface {
|
||||
// 获取租户套餐
|
||||
View(ctx context.Context, param *model.SysTenantPackageViewParam) (data *model.SysTenantPackageViewModel, err error)
|
||||
List(ctx context.Context, param *model.SysTenantPackageListParam) (data []*model.SysTenantPackageListModel, total int, err error)
|
||||
Add(ctx context.Context, param *model.SysTenantPackageAddParam) (output *model.SysTenantPackageAddModel, err error)
|
||||
Edit(ctx context.Context, param *model.SysTenantPackageEditParam) (output *model.SysTenantPackageEditModel, err error)
|
||||
Delete(ctx context.Context, param *model.SysTenantPackageDeleteParam) (output *model.SysTenantPackageDeleteModel, err error)
|
||||
Status(ctx context.Context, param *model.SysTenantPackageStatusParam) (output *model.SysTenantPackageStatusModel, err error)
|
||||
}
|
||||
ISysUser interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
// 根据用户名获取用户信息,不验证当前租户
|
||||
GetUserByUsername(ctx context.Context, username string, tenantId string) (user *entity.SysUser, err error)
|
||||
// 根据邮箱获取用户信息,不验证当前租户
|
||||
GetUserByEmail(ctx context.Context, email string, tenantId string) (user *entity.SysUser, err error)
|
||||
// 根据手机号获取用户信息,不验证当前租户
|
||||
GetUserByPhone(ctx context.Context, phone string, tenantId string) (user *entity.SysUser, err error)
|
||||
// 根据用户名和密码获取用户信息
|
||||
GetUserByUsernameAndPassword(ctx context.Context, tenantId string, username string, password string) (user *entity.SysUser, err error)
|
||||
// 根据用户ID获取用户信息
|
||||
GetUserById(ctx context.Context, id int64) (user *model.SysUserViewModel, err error)
|
||||
// 获取用户列表
|
||||
List(ctx context.Context, page *request.PageInfo, query *model.UserListParam) (items []*model.SysUserListModel, total int, err error)
|
||||
// 新增用户
|
||||
AddUser(ctx context.Context, req *model.SysUserAddModel) (data *model.SysUserViewModel, err error)
|
||||
Profile(ctx context.Context) (user *model.UserProfileModel, err error)
|
||||
UpdateCurrentUser(ctx context.Context, req *model.UpdateCurrentUserModel) (user *model.SysUserViewModel, err error)
|
||||
UpdateCurrentUserPassword(ctx context.Context, req *model.UpdateCurrentUserPasswordModel) (err error)
|
||||
UpdateUser(ctx context.Context, req *model.SysUserUpdateModel) (err error)
|
||||
DeleteUser(ctx context.Context, userIds []int64) (err error)
|
||||
ResetPassword(ctx context.Context, userId int64, password string) (err error)
|
||||
UpdateLoginInfo(ctx context.Context, userId int64, loginIp string) (err error)
|
||||
// 获取用户角色ID列表
|
||||
GetUserRoleIds(ctx context.Context, userId int64) (roleIds []int64, err error)
|
||||
// 获取用户岗位ID列表
|
||||
GetUserPostIds(ctx context.Context, userId int64) (postIds []int64, err error)
|
||||
Register(ctx context.Context, param *model.SysUserRegisterModel) (err error)
|
||||
// Status 更新用户状态
|
||||
Status(ctx context.Context, param *model.SysUserStatusParam) (err error)
|
||||
// 批量查询用户迷你信息
|
||||
BatchGetUserMiniInfo(ctx context.Context, userIds []int64) (users []*model.SysUserMiniModel, err error)
|
||||
}
|
||||
ISysUserOnline interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
Add(ctx context.Context, userOnline *model.SysUserOnlineAddModel) (err error)
|
||||
List(ctx context.Context, query *model.SysUserOnlineListParam, page *request.PageInfo) (items []*model.SysUserOnlineListModel, total int, err error)
|
||||
Delete(ctx context.Context, ids []int64) (err error)
|
||||
DeleteByToken(ctx context.Context, token string) (err error)
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
localSysAuth ISysAuth
|
||||
localSysCaptcha ISysCaptcha
|
||||
localSysClient ISysClient
|
||||
localSysConfig ISysConfig
|
||||
localSysDept ISysDept
|
||||
localSysDictData ISysDictData
|
||||
localSysDictType ISysDictType
|
||||
localSysJob ISysJob
|
||||
localSysLogininfor ISysLogininfor
|
||||
localSysMenu ISysMenu
|
||||
localSysNotice ISysNotice
|
||||
localSysNoticeUser ISysNoticeUser
|
||||
localSysOperLog ISysOperLog
|
||||
localSysOss ISysOss
|
||||
localSysOssConfig ISysOssConfig
|
||||
localSysPost ISysPost
|
||||
localSysQrcode ISysQrcode
|
||||
localSysRole ISysRole
|
||||
localSysSocial ISysSocial
|
||||
localSysTenant ISysTenant
|
||||
localSysTenantPackage ISysTenantPackage
|
||||
localSysUser ISysUser
|
||||
localSysUserOnline ISysUserOnline
|
||||
)
|
||||
|
||||
func SysAuth() ISysAuth {
|
||||
if localSysAuth == nil {
|
||||
panic("implement not found for interface ISysAuth, forgot register?")
|
||||
}
|
||||
return localSysAuth
|
||||
}
|
||||
|
||||
func RegisterSysAuth(i ISysAuth) {
|
||||
localSysAuth = i
|
||||
}
|
||||
|
||||
func SysCaptcha() ISysCaptcha {
|
||||
if localSysCaptcha == nil {
|
||||
panic("implement not found for interface ISysCaptcha, forgot register?")
|
||||
}
|
||||
return localSysCaptcha
|
||||
}
|
||||
|
||||
func RegisterSysCaptcha(i ISysCaptcha) {
|
||||
localSysCaptcha = i
|
||||
}
|
||||
|
||||
func SysClient() ISysClient {
|
||||
if localSysClient == nil {
|
||||
panic("implement not found for interface ISysClient, forgot register?")
|
||||
}
|
||||
return localSysClient
|
||||
}
|
||||
|
||||
func RegisterSysClient(i ISysClient) {
|
||||
localSysClient = i
|
||||
}
|
||||
|
||||
func SysConfig() ISysConfig {
|
||||
if localSysConfig == nil {
|
||||
panic("implement not found for interface ISysConfig, forgot register?")
|
||||
}
|
||||
return localSysConfig
|
||||
}
|
||||
|
||||
func RegisterSysConfig(i ISysConfig) {
|
||||
localSysConfig = i
|
||||
}
|
||||
|
||||
func SysDept() ISysDept {
|
||||
if localSysDept == nil {
|
||||
panic("implement not found for interface ISysDept, forgot register?")
|
||||
}
|
||||
return localSysDept
|
||||
}
|
||||
|
||||
func RegisterSysDept(i ISysDept) {
|
||||
localSysDept = i
|
||||
}
|
||||
|
||||
func SysDictData() ISysDictData {
|
||||
if localSysDictData == nil {
|
||||
panic("implement not found for interface ISysDictData, forgot register?")
|
||||
}
|
||||
return localSysDictData
|
||||
}
|
||||
|
||||
func RegisterSysDictData(i ISysDictData) {
|
||||
localSysDictData = i
|
||||
}
|
||||
|
||||
func SysDictType() ISysDictType {
|
||||
if localSysDictType == nil {
|
||||
panic("implement not found for interface ISysDictType, forgot register?")
|
||||
}
|
||||
return localSysDictType
|
||||
}
|
||||
|
||||
func RegisterSysDictType(i ISysDictType) {
|
||||
localSysDictType = i
|
||||
}
|
||||
|
||||
func SysJob() ISysJob {
|
||||
if localSysJob == nil {
|
||||
panic("implement not found for interface ISysJob, forgot register?")
|
||||
}
|
||||
return localSysJob
|
||||
}
|
||||
|
||||
func RegisterSysJob(i ISysJob) {
|
||||
localSysJob = i
|
||||
}
|
||||
|
||||
func SysLogininfor() ISysLogininfor {
|
||||
if localSysLogininfor == nil {
|
||||
panic("implement not found for interface ISysLogininfor, forgot register?")
|
||||
}
|
||||
return localSysLogininfor
|
||||
}
|
||||
|
||||
func RegisterSysLogininfor(i ISysLogininfor) {
|
||||
localSysLogininfor = i
|
||||
}
|
||||
|
||||
func SysMenu() ISysMenu {
|
||||
if localSysMenu == nil {
|
||||
panic("implement not found for interface ISysMenu, forgot register?")
|
||||
}
|
||||
return localSysMenu
|
||||
}
|
||||
|
||||
func RegisterSysMenu(i ISysMenu) {
|
||||
localSysMenu = i
|
||||
}
|
||||
|
||||
func SysNotice() ISysNotice {
|
||||
if localSysNotice == nil {
|
||||
panic("implement not found for interface ISysNotice, forgot register?")
|
||||
}
|
||||
return localSysNotice
|
||||
}
|
||||
|
||||
func RegisterSysNotice(i ISysNotice) {
|
||||
localSysNotice = i
|
||||
}
|
||||
|
||||
func SysNoticeUser() ISysNoticeUser {
|
||||
if localSysNoticeUser == nil {
|
||||
panic("implement not found for interface ISysNoticeUser, forgot register?")
|
||||
}
|
||||
return localSysNoticeUser
|
||||
}
|
||||
|
||||
func RegisterSysNoticeUser(i ISysNoticeUser) {
|
||||
localSysNoticeUser = i
|
||||
}
|
||||
|
||||
func SysOperLog() ISysOperLog {
|
||||
if localSysOperLog == nil {
|
||||
panic("implement not found for interface ISysOperLog, forgot register?")
|
||||
}
|
||||
return localSysOperLog
|
||||
}
|
||||
|
||||
func RegisterSysOperLog(i ISysOperLog) {
|
||||
localSysOperLog = i
|
||||
}
|
||||
|
||||
func SysOss() ISysOss {
|
||||
if localSysOss == nil {
|
||||
panic("implement not found for interface ISysOss, forgot register?")
|
||||
}
|
||||
return localSysOss
|
||||
}
|
||||
|
||||
func RegisterSysOss(i ISysOss) {
|
||||
localSysOss = i
|
||||
}
|
||||
|
||||
func SysOssConfig() ISysOssConfig {
|
||||
if localSysOssConfig == nil {
|
||||
panic("implement not found for interface ISysOssConfig, forgot register?")
|
||||
}
|
||||
return localSysOssConfig
|
||||
}
|
||||
|
||||
func RegisterSysOssConfig(i ISysOssConfig) {
|
||||
localSysOssConfig = i
|
||||
}
|
||||
|
||||
func SysPost() ISysPost {
|
||||
if localSysPost == nil {
|
||||
panic("implement not found for interface ISysPost, forgot register?")
|
||||
}
|
||||
return localSysPost
|
||||
}
|
||||
|
||||
func RegisterSysPost(i ISysPost) {
|
||||
localSysPost = i
|
||||
}
|
||||
|
||||
func SysQrcode() ISysQrcode {
|
||||
if localSysQrcode == nil {
|
||||
panic("implement not found for interface ISysQrcode, forgot register?")
|
||||
}
|
||||
return localSysQrcode
|
||||
}
|
||||
|
||||
func RegisterSysQrcode(i ISysQrcode) {
|
||||
localSysQrcode = i
|
||||
}
|
||||
|
||||
func SysRole() ISysRole {
|
||||
if localSysRole == nil {
|
||||
panic("implement not found for interface ISysRole, forgot register?")
|
||||
}
|
||||
return localSysRole
|
||||
}
|
||||
|
||||
func RegisterSysRole(i ISysRole) {
|
||||
localSysRole = i
|
||||
}
|
||||
|
||||
func SysSocial() ISysSocial {
|
||||
if localSysSocial == nil {
|
||||
panic("implement not found for interface ISysSocial, forgot register?")
|
||||
}
|
||||
return localSysSocial
|
||||
}
|
||||
|
||||
func RegisterSysSocial(i ISysSocial) {
|
||||
localSysSocial = i
|
||||
}
|
||||
|
||||
func SysTenant() ISysTenant {
|
||||
if localSysTenant == nil {
|
||||
panic("implement not found for interface ISysTenant, forgot register?")
|
||||
}
|
||||
return localSysTenant
|
||||
}
|
||||
|
||||
func RegisterSysTenant(i ISysTenant) {
|
||||
localSysTenant = i
|
||||
}
|
||||
|
||||
func SysTenantPackage() ISysTenantPackage {
|
||||
if localSysTenantPackage == nil {
|
||||
panic("implement not found for interface ISysTenantPackage, forgot register?")
|
||||
}
|
||||
return localSysTenantPackage
|
||||
}
|
||||
|
||||
func RegisterSysTenantPackage(i ISysTenantPackage) {
|
||||
localSysTenantPackage = i
|
||||
}
|
||||
|
||||
func SysUser() ISysUser {
|
||||
if localSysUser == nil {
|
||||
panic("implement not found for interface ISysUser, forgot register?")
|
||||
}
|
||||
return localSysUser
|
||||
}
|
||||
|
||||
func RegisterSysUser(i ISysUser) {
|
||||
localSysUser = i
|
||||
}
|
||||
|
||||
func SysUserOnline() ISysUserOnline {
|
||||
if localSysUserOnline == nil {
|
||||
panic("implement not found for interface ISysUserOnline, forgot register?")
|
||||
}
|
||||
return localSysUserOnline
|
||||
}
|
||||
|
||||
func RegisterSysUserOnline(i ISysUserOnline) {
|
||||
localSysUserOnline = i
|
||||
}
|
||||
Reference in New Issue
Block a user