优化结构

This commit is contained in:
Yvan 2026-08-28 09:44:11 +08:00
parent 279692375b
commit e997d9718e
26 changed files with 106 additions and 129 deletions

View File

@ -388,12 +388,8 @@ func NewPaymentUsecase(repo PaymentRepo, orders PaymentOrderRepo, hooks PaymentH
} }
func NewConfiguredPaymentUsecase(repo PaymentRepo, orders PaymentOrderRepo, hooks PaymentHooks, sources *PaymentOrderSourceRegistry, fulfillments *PaymentFulfillmentRegistry, appLogger *slog.Logger) (*PaymentUsecase, error) { func NewConfiguredPaymentUsecase(repo PaymentRepo, orders PaymentOrderRepo, hooks PaymentHooks, sources *PaymentOrderSourceRegistry, fulfillments *PaymentFulfillmentRegistry, appLogger *slog.Logger) (*PaymentUsecase, error) {
if sources == nil || sources.Len() == 0 { // Business modules are optional in the template. Missing modules are
return nil, errors.New("支付业务订单来源未注册,无法启动支付服务") // reported when the corresponding payment operation is invoked.
}
if fulfillments == nil || fulfillments.Len() == 0 {
return nil, errors.New("支付发货 handler 未注册,无法启动支付服务")
}
return NewPaymentUsecase(repo, orders, hooks, sources, fulfillments, appLogger), nil return NewPaymentUsecase(repo, orders, hooks, sources, fulfillments, appLogger), nil
} }
@ -924,8 +920,6 @@ func (uc *PaymentUsecase) refundWithOrder(ctx context.Context, provider, tradeNo
message := "" message := ""
if providerErr != nil { if providerErr != nil {
message = providerErr.Error() message = providerErr.Error()
} else if !accepted {
message = "支付平台未接受退款请求"
} }
order, err = uc.orders.CompletePaymentRefundRequest(ctx, provider, tradeNo, token, accepted, message) order, err = uc.orders.CompletePaymentRefundRequest(ctx, provider, tradeNo, token, accepted, message)
if err != nil { if err != nil {

View File

@ -100,7 +100,6 @@ type ErrorRecord struct {
type AuditRecordRepo interface { type AuditRecordRepo interface {
RecordOperation(context.Context, *OperationRecord) error RecordOperation(context.Context, *OperationRecord) error
RecordLogin(context.Context, *LoginLog) error RecordLogin(context.Context, *LoginLog) error
RecordDataAccess(context.Context, *DataAccessLog) error
CreateError(context.Context, *ErrorRecord) error CreateError(context.Context, *ErrorRecord) error
} }

View File

@ -206,7 +206,10 @@ func (uc *MediaUsecase) CompleteUpload(ctx context.Context, userID, uploadID uin
return nil, value return nil, value
} }
chunks, err := uc.ListChunks(ctx, uploadID) chunks, err := uc.ListChunks(ctx, uploadID)
if err != nil || len(chunks) != session.ChunkTotal { if err != nil {
return fail(err)
}
if len(chunks) != session.ChunkTotal {
return fail(fmt.Errorf("分片不全: %d/%d", len(chunks), session.ChunkTotal)) return fail(fmt.Errorf("分片不全: %d/%d", len(chunks), session.ChunkTotal))
} }
sort.Slice(chunks, func(i, j int) bool { return chunks[i].Index < chunks[j].Index }) sort.Slice(chunks, func(i, j int) bool { return chunks[i].Index < chunks[j].Index })

View File

@ -31,6 +31,22 @@ func MergeRuntimeConfig(current, next *Config) *Config {
} }
if merged.Data == nil { if merged.Data == nil {
merged.Data = cloneData(current.Data) merged.Data = cloneData(current.Data)
} else if current.Data != nil {
if merged.Data.Database == nil {
merged.Data.Database = clonePtr(current.Data.Database)
}
if merged.Data.Redis == nil {
merged.Data.Redis = cloneRedis(current.Data.Redis)
}
if merged.Data.Mongo == nil {
merged.Data.Mongo = cloneMongo(current.Data.Mongo)
}
if merged.Data.DatabaseList == nil {
merged.Data.DatabaseList = cloneSlice(current.Data.DatabaseList, clonePtr)
}
if merged.Data.RedisList == nil {
merged.Data.RedisList = cloneSlice(current.Data.RedisList, cloneRedis)
}
} }
if merged.Admin == nil { if merged.Admin == nil {
merged.Admin = cloneAdmin(current.Admin) merged.Admin = cloneAdmin(current.Admin)

View File

@ -168,3 +168,12 @@ func TestMergeRuntimeConfigPreservesOmittedSections(t *testing.T) {
t.Fatal("MergeRuntimeConfig leaked mutable storage state into current config") t.Fatal("MergeRuntimeConfig leaked mutable storage state into current config")
} }
} }
func TestMergeRuntimeConfigPreservesOmittedNestedDataSections(t *testing.T) {
current := &Config{Data: &Data{Database: &Database{Source: "current-dsn"}}}
next := &Config{Data: &Data{}}
merged := MergeRuntimeConfig(current, next)
if merged.Data == nil || merged.Data.Database == nil || merged.Data.Database.Source != "current-dsn" {
t.Fatalf("nested database section was not preserved: %#v", merged.Data)
}
}

View File

@ -3,6 +3,8 @@ package integration
import ( import (
"gorm.io/gorm" "gorm.io/gorm"
"kra/internal/integration/runtimeconfig" "kra/internal/integration/runtimeconfig"
"github.com/google/wire"
) )
// Provider is the minimal database/runtime seam for integration configuration. // Provider is the minimal database/runtime seam for integration configuration.
@ -10,3 +12,5 @@ type Provider interface {
DB() *gorm.DB DB() *gorm.DB
IntegrationRuntime() *runtimeconfig.Store IntegrationRuntime() *runtimeconfig.Store
} }
var ProviderSet = wire.NewSet(NewIntegrationConfigRepo, NewPaymentConfigReader)

View File

@ -1,5 +0,0 @@
package integration
import "github.com/google/wire"
var ProviderSet = wire.NewSet(NewIntegrationConfigRepo, NewPaymentConfigReader)

View File

@ -424,15 +424,15 @@ func paymentCreateRequiresNotifyURL(provider string, extra, config map[string]an
normalized := strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(value))) normalized := strings.NewReplacer(".", "_", "-", "_", " ", "_").Replace(strings.ToLower(strings.TrimSpace(value)))
switch provider { switch provider {
case bizpayment.PaymentAlipay, bizpayment.PaymentAlipayV3: case bizpayment.PaymentAlipay, bizpayment.PaymentAlipayV3:
return !contains([]string{"pay", "trade_pay", "alipay_trade_pay", "barcode", "barcode_pay", "micropay", "face_to_face"}, normalized) return !paymentkit.ContainsFold([]string{"pay", "trade_pay", "alipay_trade_pay", "barcode", "barcode_pay", "micropay", "face_to_face"}, normalized)
case bizpayment.PaymentWechatV2: case bizpayment.PaymentWechatV2:
return !contains([]string{"micropay", "micro_pay", "barcode", "barcode_pay", "pay_code", "payment_code"}, normalized) return !paymentkit.ContainsFold([]string{"micropay", "micro_pay", "barcode", "barcode_pay", "pay_code", "payment_code"}, normalized)
case bizpayment.PaymentWechatV3: case bizpayment.PaymentWechatV3:
return !contains([]string{"micropay", "micro_pay", "codepay", "code_pay", "barcode", "barcode_pay", "facepay", "face_pay"}, normalized) return !paymentkit.ContainsFold([]string{"micropay", "micro_pay", "codepay", "code_pay", "barcode", "barcode_pay", "facepay", "face_pay"}, normalized)
case bizpayment.PaymentQQ: case bizpayment.PaymentQQ:
return !contains([]string{"micropay", "micro_pay", "barcode", "barcode_pay"}, normalized) return !paymentkit.ContainsFold([]string{"micropay", "micro_pay", "barcode", "barcode_pay"}, normalized)
case bizpayment.PaymentLakala: case bizpayment.PaymentLakala:
return !contains([]string{"retail", "retail_pay", "micropay", "barcode"}, normalized) return !paymentkit.ContainsFold([]string{"retail", "retail_pay", "micropay", "barcode"}, normalized)
default: default:
return true return true
} }
@ -516,12 +516,3 @@ func paymentCallbackAck(provider string, values map[string]any, success bool) bi
} }
return ack return ack
} }
func contains(values []string, value string) bool {
for _, item := range values {
if item == value {
return true
}
}
return false
}

View File

@ -1,9 +1,16 @@
package payment package payment
import "gorm.io/gorm" import (
"gorm.io/gorm"
"github.com/google/wire"
)
// Provider is the narrow persistence seam required by payment repositories. // Provider is the narrow persistence seam required by payment repositories.
// Keeping it here lets payment remain an independent data module. // Keeping it here lets payment remain an independent data module.
type Provider interface { type Provider interface {
DB() *gorm.DB DB() *gorm.DB
} }
// ProviderSet wires payment persistence repositories.
var ProviderSet = wire.NewSet(NewPaymentRepo, NewPaymentOrderRepo)

View File

@ -1,6 +0,0 @@
package payment
import "github.com/google/wire"
// ProviderSet wires payment persistence repositories.
var ProviderSet = wire.NewSet(NewPaymentRepo, NewPaymentOrderRepo)

View File

@ -71,7 +71,7 @@ func (r *announcementRepo) List(ctx context.Context, filter system.AnnouncementF
if filter.StartCreatedAt != nil && filter.EndCreatedAt != nil { if filter.StartCreatedAt != nil && filter.EndCreatedAt != nil {
db = db.Where("created_at BETWEEN ? AND ?", filter.StartCreatedAt, filter.EndCreatedAt) db = db.Where("created_at BETWEEN ? AND ?", filter.StartCreatedAt, filter.EndCreatedAt)
} }
return listRows(db, filter.Page, filter.PageSize, filter.PageSize > 0, func(po announcementPO) *system.Announcement { return listRows(db.Order("id desc"), filter.Page, filter.PageSize, filter.PageSize > 0, func(po announcementPO) *system.Announcement {
return announcementToBiz(po) return announcementToBiz(po)
}) })
} }

View File

@ -21,12 +21,10 @@ type DataAccessLogPO struct {
func (DataAccessLogPO) TableName() string { return "sys_data_access_logs" } func (DataAccessLogPO) TableName() string { return "sys_data_access_logs" }
func (r *auditRecorderRepo) RecordDataAccess(ctx context.Context, v *system.DataAccessLog) error {
return r.data.DB().WithContext(ctx).Create(&DataAccessLogPO{EventType: v.EventType, TargetTable: v.TargetTable, Operation: v.Operation, UserID: v.UserID, AuthorityID: v.AuthorityID, Scope: v.Scope, RequestID: v.RequestID, Method: v.Method, Path: v.Path, Detail: v.Detail}).Error
}
func dataAccessFromPO(v DataAccessLogPO) *system.DataAccessLog { func dataAccessFromPO(v DataAccessLogPO) *system.DataAccessLog {
return &system.DataAccessLog{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, EventType: v.EventType, TargetTable: v.TargetTable, Operation: v.Operation, UserID: v.UserID, AuthorityID: v.AuthorityID, Scope: v.Scope, RequestID: v.RequestID, Method: v.Method, Path: v.Path, Detail: v.Detail} return &system.DataAccessLog{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, EventType: v.EventType, TargetTable: v.TargetTable, Operation: v.Operation, UserID: v.UserID, AuthorityID: v.AuthorityID, Scope: v.Scope, RequestID: v.RequestID, Method: v.Method, Path: v.Path, Detail: v.Detail}
} }
func (r *auditQueryRepo) ListDataAccess(ctx context.Context, page, size int, q *system.DataAccessLog) ([]*system.DataAccessLog, int64, error) { func (r *auditQueryRepo) ListDataAccess(ctx context.Context, page, size int, q *system.DataAccessLog) ([]*system.DataAccessLog, int64, error) {
db := r.data.DB().WithContext(ctx).Model(&DataAccessLogPO{}) db := r.data.DB().WithContext(ctx).Model(&DataAccessLogPO{})
if q != nil { if q != nil {
@ -47,6 +45,7 @@ func (r *auditQueryRepo) ListDataAccess(ctx context.Context, page, size int, q *
} }
return out, total, nil return out, total, nil
} }
func (r *auditQueryRepo) DeleteDataAccess(ctx context.Context, ids []uint) error { func (r *auditQueryRepo) DeleteDataAccess(ctx context.Context, ids []uint) error {
return r.data.DB().WithContext(ctx).Delete(&DataAccessLogPO{}, "id IN ?", ids).Error return r.data.DB().WithContext(ctx).Delete(&DataAccessLogPO{}, "id IN ?", ids).Error
} }

View File

@ -70,7 +70,7 @@ func (r *parameterRepo) ListParameters(ctx context.Context, page, size int, q *s
db = db.Where(clause.Like{Column: clause.Column{Name: "key"}, Value: "%" + q.Key + "%"}) db = db.Where(clause.Like{Column: clause.Column{Name: "key"}, Value: "%" + q.Key + "%"})
} }
} }
return listRows(db, page, size, true, func(po parameterPO) *system.SystemParameter { return listRows(db.Order("id desc"), page, size, true, func(po parameterPO) *system.SystemParameter {
return parameterFromPO(po) return parameterFromPO(po)
}) })
} }

View File

@ -3,6 +3,7 @@ package system
import ( import (
"kra/internal/config" "kra/internal/config"
"github.com/google/wire"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -14,3 +15,28 @@ type Provider interface {
DatabaseReady() bool DatabaseReady() bool
Runtime() *config.Store Runtime() *config.Store
} }
// ProviderSet wires system repositories and their runtime-backed adapters.
var ProviderSet = wire.NewSet(
NewRuntimeSettings,
NewTokenIssuer,
NewUserRepo,
NewAuthorityAccessRepo,
NewAPIRepo,
NewPermissionRepo,
NewMenuRepo,
NewDepartmentRepo,
NewPositionRepo,
NewDictionaryRepo,
NewParameterRepo,
NewAPITokenRepo,
NewSecurityRepo,
NewVersionRepo,
NewExportRepo,
NewAuditRepo,
NewAuditRecorderRepo,
NewLogFileRepo,
NewMediaRepo,
NewAnnouncementRepo,
NewMaintenanceRepo,
)

View File

@ -1,28 +0,0 @@
package system
import "github.com/google/wire"
// ProviderSet wires system repositories and their runtime-backed adapters.
var ProviderSet = wire.NewSet(
NewRuntimeSettings,
NewTokenIssuer,
NewUserRepo,
NewAuthorityAccessRepo,
NewAPIRepo,
NewPermissionRepo,
NewMenuRepo,
NewDepartmentRepo,
NewPositionRepo,
NewDictionaryRepo,
NewParameterRepo,
NewAPITokenRepo,
NewSecurityRepo,
NewVersionRepo,
NewExportRepo,
NewAuditRepo,
NewAuditRecorderRepo,
NewLogFileRepo,
NewMediaRepo,
NewAnnouncementRepo,
NewMaintenanceRepo,
)

View File

@ -59,6 +59,7 @@ func (r *versionRepo) ListVersions(ctx context.Context, page, size int, name, co
if code != "" { if code != "" {
db = db.Where("version_code = ?", code) db = db.Where("version_code = ?", code)
} }
db = db.Order("id desc")
var total int64 var total int64
if err := db.Count(&total).Error; err != nil { if err := db.Count(&total).Error; err != nil {
return nil, 0, err return nil, 0, err

View File

@ -1,7 +1,13 @@
package task package task
import dataprovider "kra/internal/data/provider" import (
dataprovider "kra/internal/data/provider"
"github.com/google/wire"
)
// Provider is the minimal database seam required by the task tables. // Provider is the minimal database seam required by the task tables.
// Task persistence must not depend on the full data runtime or system repos. // Task persistence must not depend on the full data runtime or system repos.
type Provider = dataprovider.Database type Provider = dataprovider.Database
var ProviderSet = wire.NewSet(NewTaskRepo)

View File

@ -1,5 +0,0 @@
package task
import "github.com/google/wire"
var ProviderSet = wire.NewSet(NewTaskRepo)

View File

@ -70,7 +70,7 @@ func skipStackFile(filename string) bool {
"/go/pkg/mod/", "/go/pkg/mod/",
"/go.uber.org/", "/go.uber.org/",
"/gorm.io/", "/gorm.io/",
"/pkg/logging/", "/internal/logging/",
"/internal/transport/middleware/", "/internal/transport/middleware/",
"/internal/transport/router/", "/internal/transport/router/",
"/internal/server/handler/", "/internal/server/handler/",

View File

@ -26,7 +26,7 @@ type Options struct {
} }
// ErrorEntry is the storage-neutral representation of an Error-level log. // ErrorEntry is the storage-neutral representation of an Error-level log.
// Keeping it in pkg/logging lets the log core report failures without taking a // Keeping it in internal/logging lets the log core report failures without taking a
// dependency on the application service or persistence layers. // dependency on the application service or persistence layers.
type ErrorEntry struct { type ErrorEntry struct {
Form, Info, Level, RequestID, TraceID string Form, Info, Level, RequestID, TraceID string

View File

@ -13,7 +13,7 @@ func NormalizeStatus(value, fallback string) string {
return "success" return "success"
case "WAIT_BUYER_PAY", "USERPAYING", "NOTPAY", "PROCESSING", "PENDING", "CREATED", "CLIENT_PENDING", "ACCEPT", "ACCEPTED", "PAYING": case "WAIT_BUYER_PAY", "USERPAYING", "NOTPAY", "PROCESSING", "PENDING", "CREATED", "CLIENT_PENDING", "ACCEPT", "ACCEPTED", "PAYING":
return "pending" return "pending"
case "CLOSED", "TRADE_CLOSED", "CANCELLED", "CANCELED", "REVOKED", "REFUND", "FAILED", "FAIL", "REJECTED", "DENIED", "DECLINED", "ERROR", "PAYERROR": case "CLOSED", "TRADE_CLOSED", "CANCELLED", "CANCELED", "REVOKED", "FAILED", "FAIL", "REJECTED", "DENIED", "DECLINED", "ERROR", "PAYERROR":
return "failed" return "failed"
default: default:
return fallback return fallback
@ -22,7 +22,7 @@ func NormalizeStatus(value, fallback string) string {
func NormalizeRefundStatus(value, fallback string) string { func NormalizeRefundStatus(value, fallback string) string {
switch strings.ToUpper(strings.TrimSpace(value)) { switch strings.ToUpper(strings.TrimSpace(value)) {
case "SUCCESS", "OK", "PAID", "REFUND_SUCCESS", "REFUNDED", "COMPLETED", "FINISHED": case "SUCCESS", "OK", "PAID", "REFUND_SUCCESS", "REFUNDED", "COMPLETED", "FINISHED", "TRADE_SUCCESS":
return "success" return "success"
case "WAIT_BUYER_PAY", "USERPAYING", "NOTPAY", "PROCESSING", "PENDING", "CREATED", "ACCEPT", "ACCEPTED", "PAYING": case "WAIT_BUYER_PAY", "USERPAYING", "NOTPAY", "PROCESSING", "PENDING", "CREATED", "ACCEPT", "ACCEPTED", "PAYING":
return "pending" return "pending"

View File

@ -24,3 +24,15 @@ func TestNormalizeStatusSeparatesRefundStates(t *testing.T) {
t.Fatalf("refund status = %q, want success", got) t.Fatalf("refund status = %q, want success", got)
} }
} }
func TestNormalizeStatusDoesNotTreatRefundAsPaymentFailure(t *testing.T) {
if got := NormalizeStatus("REFUND", "unknown"); got != "unknown" {
t.Fatalf("NormalizeStatus(REFUND) = %q, want fallback", got)
}
}
func TestNormalizeRefundStatusAcceptsTradeSuccess(t *testing.T) {
if got := NormalizeRefundStatus("TRADE_SUCCESS", "unknown"); got != "success" {
t.Fatalf("NormalizeRefundStatus(TRADE_SUCCESS) = %q, want success", got)
}
}

View File

@ -55,8 +55,7 @@ func requestUsesHTTPS(request *http.Request) bool {
return strings.EqualFold(strings.TrimSpace(forwarded), "https") return strings.EqualFold(strings.TrimSpace(forwarded), "https")
} }
// SetTokenCookie is the shared transport-level cookie policy. It has no KRA // SetTokenCookie is the shared transport-level cookie policy for the admin API.
// business dependency, so handlers and middleware can use pkg/httpx directly.
func SetTokenCookie(c *gin.Context, value string, maxAge int) { func SetTokenCookie(c *gin.Context, value string, maxAge int) {
if c == nil { if c == nil {
return return

View File

@ -1,9 +1,8 @@
package dto package dto
type GetAuthorityButtonsRequest struct { type GetAuthorityButtonsRequest struct {
MenuID uint `json:"menuID"` MenuID uint `json:"menuID"`
AuthorityID uint `json:"authorityId"` AuthorityID uint `json:"authorityId"`
Selected []uint `json:"selected"`
} }
type SetAuthorityButtonsRequest struct { type SetAuthorityButtonsRequest struct {

View File

@ -16,21 +16,7 @@ func (s *PaymentService) Order(ctx context.Context, provider, tradeNo string) (*
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &dto.PaymentOrderResponse{ return paymentOrderResponse(order)
ID: order.ID,
Provider: order.Provider, TradeNo: order.TradeNo, ProviderTradeNo: order.ProviderTradeNo,
BusinessType: order.BusinessType, BusinessID: order.BusinessID, Subject: order.Subject,
PaymentMode: order.PaymentMode, OriginalAmount: order.OriginalAmount,
Amount: order.Amount, PaidAmount: order.PaidAmount, PayerPaidAmount: order.PayerPaidAmount,
CashPaidAmount: order.CashPaidAmount, PointPaidAmount: order.PointPaidAmount,
DiscountAmount: order.DiscountAmount, ProviderDiscountAmount: order.ProviderDiscountAmount,
MerchantDiscountAmount: order.MerchantDiscountAmount, SettlementAmount: order.SettlementAmount,
Currency: order.Currency, PayerCurrency: order.PayerCurrency, AmountBreakdownKnown: order.AmountBreakdownKnown,
PaymentStatus: order.PaymentStatus, ProviderStatus: order.ProviderStatus, FulfillmentStatus: order.FulfillmentStatus,
RefundStatus: order.RefundStatus, RefundedAmount: order.RefundedAmount, RefundRequestedAmount: order.RefundRequestedAmount, RefundNo: order.RefundNo, LastError: order.LastError,
CreatedAt: order.CreatedAt, UpdatedAt: order.UpdatedAt, PaidAt: order.PaidAt,
FulfilledAt: order.FulfilledAt, RefundedAt: order.RefundedAt,
}, nil
} }
func (s *PaymentService) Orders(ctx context.Context, req *dto.PaymentOrderListRequest) ([]*dto.PaymentOrderResponse, int64, int, int, error) { func (s *PaymentService) Orders(ctx context.Context, req *dto.PaymentOrderListRequest) ([]*dto.PaymentOrderResponse, int64, int, int, error) {

View File

@ -14,34 +14,10 @@ func NewSecurityService(uc *system.SecurityUsecase) *SecurityService {
return &SecurityService{uc: uc} return &SecurityService{uc: uc}
} }
func (s *SecurityService) ActiveToken(ctx context.Context, username string) (string, error) {
return s.uc.ActiveToken(ctx, username)
}
func (s *SecurityService) LoginLocked(ctx context.Context, username string) (bool, error) {
return s.uc.LoginLocked(ctx, username)
}
func (s *SecurityService) IncrementLoginFailure(ctx context.Context, username string, expiration time.Duration) (int64, error) {
return s.uc.IncrementLoginFailure(ctx, username, expiration)
}
func (s *SecurityService) LockLogin(ctx context.Context, username string, expiration time.Duration) error {
return s.uc.LockLogin(ctx, username, expiration)
}
func (s *SecurityService) ClearLoginState(ctx context.Context, username string) {
s.uc.ClearLoginState(ctx, username)
}
func (s *SecurityService) EnsureLoginIPCounter(ctx context.Context, ip string, expiration time.Duration) (int, error) { func (s *SecurityService) EnsureLoginIPCounter(ctx context.Context, ip string, expiration time.Duration) (int, error) {
return s.uc.EnsureLoginIPCounter(ctx, ip, expiration) return s.uc.EnsureLoginIPCounter(ctx, ip, expiration)
} }
func (s *SecurityService) IncrementLoginIP(ctx context.Context, ip string, expiration time.Duration) (int64, error) {
return s.uc.IncrementLoginIP(ctx, ip, expiration)
}
func (s *SecurityService) IncrementRateLimit(ctx context.Context, key string, expiration time.Duration) (int64, error) { func (s *SecurityService) IncrementRateLimit(ctx context.Context, key string, expiration time.Duration) (int64, error) {
return s.uc.IncrementRateLimit(ctx, key, expiration) return s.uc.IncrementRateLimit(ctx, key, expiration)
} }
@ -58,12 +34,6 @@ func (s *SecurityService) DeleteCaptcha(ctx context.Context, id string) error {
return s.uc.DeleteCaptcha(ctx, id) return s.uc.DeleteCaptcha(ctx, id)
} }
func (s *SecurityService) UseMultipoint() bool { return s.uc.UseMultipoint() }
func (s *SecurityService) CaptchaSettings() system.CaptchaSettings { func (s *SecurityService) CaptchaSettings() system.CaptchaSettings {
return s.uc.CaptchaRuntimeSettings() return s.uc.CaptchaRuntimeSettings()
} }
func (s *SecurityService) RotateActiveToken(ctx context.Context, username, oldToken, newToken string, expiration time.Duration) error {
return s.uc.RotateActiveToken(ctx, username, oldToken, newToken, expiration)
}