优化结构
This commit is contained in:
parent
969afee284
commit
ee179d6b34
|
|
@ -158,14 +158,6 @@ func (uc *SecurityUsecase) ValidatePassword(value *SecurityConfig, password stri
|
|||
return nil
|
||||
}
|
||||
|
||||
func (uc *SecurityUsecase) ValidateCurrentPassword(ctx context.Context, password string) error {
|
||||
config, err := uc.Current(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return uc.ValidatePassword(config, password)
|
||||
}
|
||||
|
||||
func (uc *SecurityUsecase) LoginLocked(ctx context.Context, username string) (bool, error) {
|
||||
_, locked, err := uc.cache.Get(ctx, loginLockKey(username))
|
||||
return locked, err
|
||||
|
|
|
|||
|
|
@ -69,16 +69,6 @@ func (uc *UserUsecase) Login(ctx context.Context, username, password string) (*U
|
|||
return u, nil
|
||||
}
|
||||
|
||||
func (uc *UserUsecase) User(ctx context.Context, id uint) (*User, error) {
|
||||
user, err := uc.repo.FindUserByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = uc.repo.FillDepartmentNamePaths(ctx, user)
|
||||
uc.fallbackDefaultRouter(ctx, user)
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// UserByUUID resolves the identity from the UUID embedded in the JWT rather
|
||||
// than from the mutable numeric ID used by administrative records.
|
||||
func (uc *UserUsecase) UserByUUID(ctx context.Context, uuid string) (*User, error) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package config
|
||||
|
||||
// MaskedSecret is the placeholder written in place of a stored secret whenever a
|
||||
// configuration payload leaves the process. Every layer that masks or preserves
|
||||
// configuration secrets shares this sentinel so a masked read round-trips into a
|
||||
// write without silently overwriting the stored value.
|
||||
const MaskedSecret = "******"
|
||||
|
||||
// IsMaskedSecret reports whether an inbound value carries no new secret, either
|
||||
// because it was omitted or because it is the mask handed out on read.
|
||||
func IsMaskedSecret(value string) bool { return value == "" || value == MaskedSecret }
|
||||
|
||||
// ObjectStores lists every object-store block of a storage configuration so
|
||||
// callers iterate the providers instead of repeating the list.
|
||||
func ObjectStores(value *Storage) []*ObjectStore {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
return []*ObjectStore{value.AliyunOSS, value.HuaweiOBS, value.TencentCOS, value.AWSS3, value.CloudflareR2, value.Minio}
|
||||
}
|
||||
|
||||
// MaskStorageSecrets replaces every populated storage secret with MaskedSecret.
|
||||
func MaskStorageSecrets(value *Storage) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
if value.Qiniu != nil && value.Qiniu.SecretKey != "" {
|
||||
value.Qiniu.SecretKey = MaskedSecret
|
||||
}
|
||||
for _, item := range ObjectStores(value) {
|
||||
if item != nil && item.SecretKey != "" {
|
||||
item.SecretKey = MaskedSecret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,24 +10,3 @@ func cloneAdminConfig(value *config.Admin) *config.Admin {
|
|||
}
|
||||
return config.CloneAdmin(value)
|
||||
}
|
||||
|
||||
func maskStorageSecrets(storage *config.Storage) {
|
||||
if storage == nil {
|
||||
return
|
||||
}
|
||||
if storage.Qiniu != nil && storage.Qiniu.SecretKey != "" {
|
||||
storage.Qiniu.SecretKey = "******"
|
||||
}
|
||||
for _, item := range []*config.ObjectStore{
|
||||
storage.AliyunOSS,
|
||||
storage.HuaweiOBS,
|
||||
storage.TencentCOS,
|
||||
storage.AWSS3,
|
||||
storage.CloudflareR2,
|
||||
storage.Minio,
|
||||
} {
|
||||
if item != nil && item.SecretKey != "" {
|
||||
item.SecretKey = "******"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"kra/internal/config"
|
||||
"kra/internal/integration/runtimeconfig"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
|
@ -158,7 +159,7 @@ func maskIntegrationSecrets(kind, provider string, values map[string]any) {
|
|||
for key, value := range values {
|
||||
if secretFields[key] || likelyIntegrationSecret(key) {
|
||||
if text, ok := value.(string); ok && text != "" {
|
||||
values[key] = "******"
|
||||
values[key] = config.MaskedSecret
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
|
@ -172,7 +173,7 @@ func mergeIntegrationSecrets(kind, provider string, values, old map[string]any)
|
|||
secretFields := integrationSecretFields(kind, provider)
|
||||
for key, value := range values {
|
||||
if secretFields[key] || likelyIntegrationSecret(key) {
|
||||
if text, ok := value.(string); ok && text == "******" {
|
||||
if text, ok := value.(string); ok && text == config.MaskedSecret {
|
||||
if prior, exists := old[key]; exists {
|
||||
values[key] = prior
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,11 +157,11 @@ func TestMaskStorageSecretsLeavesUnconfiguredProvidersEmpty(t *testing.T) {
|
|||
AliyunOSS: &config.ObjectStore{SecretKey: "configured-secret"},
|
||||
Minio: &config.ObjectStore{},
|
||||
}
|
||||
maskStorageSecrets(storage)
|
||||
config.MaskStorageSecrets(storage)
|
||||
if storage.Qiniu.SecretKey != "" || storage.Minio.SecretKey != "" {
|
||||
t.Fatalf("empty provider secrets were masked: %#v", storage)
|
||||
}
|
||||
if storage.AliyunOSS.SecretKey != "******" {
|
||||
if storage.AliyunOSS.SecretKey != config.MaskedSecret {
|
||||
t.Fatalf("configured secret was not masked: %q", storage.AliyunOSS.SecretKey)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,93 +77,6 @@ func (r *ResourceRegistry) Replace(resources Resources) {
|
|||
r.mu.Unlock()
|
||||
}
|
||||
|
||||
func (r *ResourceRegistry) Logger() *slog.Logger { return r.Snapshot().Logger }
|
||||
|
||||
func (r *ResourceRegistry) SetLogger(logger *slog.Logger) {
|
||||
r.update(func(resources *Resources) { resources.Logger = logger })
|
||||
}
|
||||
|
||||
func (r *ResourceRegistry) DB() *gorm.DB { return r.Snapshot().DB }
|
||||
|
||||
func (r *ResourceRegistry) SetDB(db *gorm.DB) {
|
||||
r.update(func(resources *Resources) { resources.DB = db })
|
||||
}
|
||||
|
||||
// NamedDB returns a configured secondary database by alias. An empty alias
|
||||
// resolves to the primary database.
|
||||
func (r *ResourceRegistry) NamedDB(name string) *gorm.DB {
|
||||
if name == "" {
|
||||
return r.DB()
|
||||
}
|
||||
return r.Snapshot().NamedDBs[name]
|
||||
}
|
||||
|
||||
// SetNamedDBs replaces the complete secondary-database alias set.
|
||||
func (r *ResourceRegistry) SetNamedDBs(databases map[string]*gorm.DB) {
|
||||
r.update(func(resources *Resources) { resources.NamedDBs = cloneDBMap(databases) })
|
||||
}
|
||||
|
||||
func (r *ResourceRegistry) Redis() redis.UniversalClient { return r.Snapshot().Redis }
|
||||
|
||||
func (r *ResourceRegistry) SetRedis(client redis.UniversalClient) {
|
||||
r.update(func(resources *Resources) { resources.Redis = client })
|
||||
}
|
||||
|
||||
// NamedRedis returns a configured secondary Redis client by alias. An empty
|
||||
// alias resolves to the primary Redis client.
|
||||
func (r *ResourceRegistry) NamedRedis(name string) redis.UniversalClient {
|
||||
if name == "" {
|
||||
return r.Redis()
|
||||
}
|
||||
return r.Snapshot().NamedRedis[name]
|
||||
}
|
||||
|
||||
// SetNamedRedis replaces the complete secondary-Redis alias set.
|
||||
func (r *ResourceRegistry) SetNamedRedis(clients map[string]redis.UniversalClient) {
|
||||
r.update(func(resources *Resources) { resources.NamedRedis = cloneRedisMap(clients) })
|
||||
}
|
||||
|
||||
func (r *ResourceRegistry) Mongo() *mongo.Client { return r.Snapshot().Mongo }
|
||||
|
||||
func (r *ResourceRegistry) SetMongo(client *mongo.Client) {
|
||||
r.update(func(resources *Resources) { resources.Mongo = client })
|
||||
}
|
||||
|
||||
func (r *ResourceRegistry) Storage() FileStorage { return r.Snapshot().Storage }
|
||||
|
||||
func (r *ResourceRegistry) SetStorage(storage FileStorage) {
|
||||
r.update(func(resources *Resources) { resources.Storage = storage })
|
||||
}
|
||||
|
||||
func (r *ResourceRegistry) MQ() platformmq.Registry { return r.Snapshot().MQ }
|
||||
|
||||
func (r *ResourceRegistry) SetMQ(registry platformmq.Registry) {
|
||||
r.update(func(resources *Resources) { resources.MQ = registry })
|
||||
}
|
||||
|
||||
func (r *ResourceRegistry) WebSocket() platformws.Hub { return r.Snapshot().WebSocket }
|
||||
|
||||
func (r *ResourceRegistry) SetWebSocket(hub platformws.Hub) {
|
||||
r.update(func(resources *Resources) { resources.WebSocket = hub })
|
||||
}
|
||||
|
||||
func (r *ResourceRegistry) Scheduler() Scheduler { return r.Snapshot().Scheduler }
|
||||
|
||||
func (r *ResourceRegistry) SetScheduler(scheduler Scheduler) {
|
||||
r.update(func(resources *Resources) { resources.Scheduler = scheduler })
|
||||
}
|
||||
|
||||
func (r *ResourceRegistry) update(change func(*Resources)) {
|
||||
if r == nil || change == nil {
|
||||
return
|
||||
}
|
||||
r.mu.Lock()
|
||||
resources := cloneResources(r.resources)
|
||||
change(&resources)
|
||||
r.resources = normalizeResources(resources)
|
||||
r.mu.Unlock()
|
||||
}
|
||||
|
||||
func normalizeResources(resources Resources) Resources {
|
||||
if resources.Logger == nil {
|
||||
resources.Logger = slog.Default()
|
||||
|
|
@ -248,45 +161,3 @@ func Install(resources Resources) *ResourceRegistry {
|
|||
func DefaultRegistry() *ResourceRegistry { return defaultResources }
|
||||
|
||||
func ResourceSnapshot() Resources { return defaultResources.Snapshot() }
|
||||
|
||||
func ReplaceResources(resources Resources) { defaultResources.Replace(resources) }
|
||||
|
||||
func Logger() *slog.Logger { return defaultResources.Logger() }
|
||||
|
||||
func SetLogger(logger *slog.Logger) { defaultResources.SetLogger(logger) }
|
||||
|
||||
func DB() *gorm.DB { return defaultResources.DB() }
|
||||
|
||||
func SetDB(db *gorm.DB) { defaultResources.SetDB(db) }
|
||||
|
||||
func NamedDB(name string) *gorm.DB { return defaultResources.NamedDB(name) }
|
||||
|
||||
func SetNamedDBs(databases map[string]*gorm.DB) { defaultResources.SetNamedDBs(databases) }
|
||||
|
||||
func Redis() redis.UniversalClient { return defaultResources.Redis() }
|
||||
|
||||
func SetRedis(client redis.UniversalClient) { defaultResources.SetRedis(client) }
|
||||
|
||||
func NamedRedis(name string) redis.UniversalClient { return defaultResources.NamedRedis(name) }
|
||||
|
||||
func SetNamedRedis(clients map[string]redis.UniversalClient) { defaultResources.SetNamedRedis(clients) }
|
||||
|
||||
func Mongo() *mongo.Client { return defaultResources.Mongo() }
|
||||
|
||||
func SetMongo(client *mongo.Client) { defaultResources.SetMongo(client) }
|
||||
|
||||
func Storage() FileStorage { return defaultResources.Storage() }
|
||||
|
||||
func SetStorage(storage FileStorage) { defaultResources.SetStorage(storage) }
|
||||
|
||||
func MQ() platformmq.Registry { return defaultResources.MQ() }
|
||||
|
||||
func SetMQ(registry platformmq.Registry) { defaultResources.SetMQ(registry) }
|
||||
|
||||
func WebSocket() platformws.Hub { return defaultResources.WebSocket() }
|
||||
|
||||
func SetWebSocket(hub platformws.Hub) { defaultResources.SetWebSocket(hub) }
|
||||
|
||||
func TaskScheduler() Scheduler { return defaultResources.Scheduler() }
|
||||
|
||||
func SetTaskScheduler(scheduler Scheduler) { defaultResources.SetScheduler(scheduler) }
|
||||
|
|
|
|||
|
|
@ -55,16 +55,16 @@ func (*webSocketStub) OnDisconnect(func(*platformws.Session)) {}
|
|||
|
||||
func TestResourceRegistryDefaults(t *testing.T) {
|
||||
registry := NewResourceRegistry()
|
||||
if registry.Logger() == nil {
|
||||
resources := registry.Snapshot()
|
||||
if resources.Logger == nil {
|
||||
t.Fatal("default logger is nil")
|
||||
}
|
||||
resources := registry.Snapshot()
|
||||
if resources.DB != nil || len(resources.NamedDBs) != 0 || resources.Redis != nil || len(resources.NamedRedis) != 0 || resources.Mongo != nil || resources.Storage != nil || resources.MQ != nil || resources.WebSocket != nil || resources.Scheduler != nil {
|
||||
t.Fatalf("unexpected initialized resource: %#v", resources)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceRegistryReplaceAndSetters(t *testing.T) {
|
||||
func TestResourceRegistryReplaceAndSnapshot(t *testing.T) {
|
||||
logger := slog.Default().With("test", true)
|
||||
db := &gorm.DB{}
|
||||
redisClient := redis.NewClient(&redis.Options{Addr: "127.0.0.1:6379"})
|
||||
|
|
@ -76,41 +76,33 @@ func TestResourceRegistryReplaceAndSetters(t *testing.T) {
|
|||
scheduler := &schedulerStub{}
|
||||
|
||||
registry := NewResourceRegistry()
|
||||
inputDBs := map[string]*gorm.DB{"reporting": db}
|
||||
inputRedis := map[string]redis.UniversalClient{"cache": redisClient}
|
||||
registry.Replace(Resources{
|
||||
Logger: logger, DB: db, NamedDBs: map[string]*gorm.DB{"reporting": db},
|
||||
Redis: redisClient, NamedRedis: map[string]redis.UniversalClient{"cache": redisClient}, Mongo: mongoClient,
|
||||
Logger: logger, DB: db, NamedDBs: inputDBs,
|
||||
Redis: redisClient, NamedRedis: inputRedis, Mongo: mongoClient,
|
||||
Storage: storage, MQ: mq, WebSocket: webSocket, Scheduler: scheduler,
|
||||
})
|
||||
resources := registry.Snapshot()
|
||||
if resources.Logger != logger || resources.DB != db || resources.Redis != redisClient || resources.Mongo != mongoClient || resources.Storage != storage || resources.MQ != mq || resources.WebSocket != webSocket || resources.Scheduler != scheduler {
|
||||
t.Fatalf("replacement snapshot does not match: %#v", resources)
|
||||
}
|
||||
if resources.NamedDBs["reporting"] != db || resources.NamedRedis["cache"] != redisClient {
|
||||
t.Fatal("named resource lookup returned the wrong resource")
|
||||
}
|
||||
|
||||
nextDB := &gorm.DB{}
|
||||
registry.SetDB(nextDB)
|
||||
if registry.DB() != nextDB {
|
||||
t.Fatal("database setter did not publish the new database")
|
||||
}
|
||||
if registry.Redis() != redisClient || registry.Storage() != storage {
|
||||
t.Fatal("database setter changed unrelated resources")
|
||||
}
|
||||
if registry.NamedDB("reporting") != db || registry.NamedDB("") != nextDB {
|
||||
t.Fatal("named database lookup returned the wrong resource")
|
||||
}
|
||||
if registry.NamedRedis("cache") != redisClient || registry.NamedRedis("") != redisClient {
|
||||
t.Fatal("named redis lookup returned the wrong resource")
|
||||
}
|
||||
inputDBs := map[string]*gorm.DB{"analytics": db}
|
||||
registry.SetNamedDBs(inputDBs)
|
||||
inputDBs["mutated"] = nextDB
|
||||
if registry.NamedDB("mutated") != nil || registry.NamedDB("analytics") != db {
|
||||
t.Fatal("named database map was not copied")
|
||||
}
|
||||
inputRedis := map[string]redis.UniversalClient{"sessions": redisClient}
|
||||
registry.SetNamedRedis(inputRedis)
|
||||
inputDBs["mutated"] = &gorm.DB{}
|
||||
inputRedis["mutated"] = redisClient
|
||||
if registry.NamedRedis("mutated") != nil || registry.NamedRedis("sessions") != redisClient {
|
||||
t.Fatal("named redis map was not copied")
|
||||
if _, exists := registry.Snapshot().NamedDBs["mutated"]; exists {
|
||||
t.Fatal("named database map was not copied on replacement")
|
||||
}
|
||||
if _, exists := registry.Snapshot().NamedRedis["mutated"]; exists {
|
||||
t.Fatal("named redis map was not copied on replacement")
|
||||
}
|
||||
|
||||
resources.NamedDBs["mutated"] = db
|
||||
if _, exists := registry.Snapshot().NamedDBs["mutated"]; exists {
|
||||
t.Fatal("snapshot shares its named database map with the registry")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,14 +132,16 @@ func TestResourceRegistryConcurrentAccess(t *testing.T) {
|
|||
go func() {
|
||||
defer wait.Done()
|
||||
for step := 0; step < iterations; step++ {
|
||||
registry.SetDB(&gorm.DB{})
|
||||
_ = registry.Snapshot()
|
||||
_ = registry.Logger()
|
||||
registry.Replace(Resources{DB: &gorm.DB{}})
|
||||
if registry.Snapshot().Logger == nil {
|
||||
t.Error("concurrent snapshot lost the default logger")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
wait.Wait()
|
||||
if registry.DB() == nil {
|
||||
t.Fatal("concurrent setters lost the database")
|
||||
if registry.Snapshot().DB == nil {
|
||||
t.Fatal("concurrent replacement lost the database")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,12 +322,12 @@ func maskConfigSecrets(value *config.Config) {
|
|||
return
|
||||
}
|
||||
if value.Admin.JWT != nil && value.Admin.JWT.SigningKey != "" {
|
||||
value.Admin.JWT.SigningKey = "******"
|
||||
value.Admin.JWT.SigningKey = config.MaskedSecret
|
||||
}
|
||||
if value.Admin.Email != nil && value.Admin.Email.Secret != "" {
|
||||
value.Admin.Email.Secret = "******"
|
||||
value.Admin.Email.Secret = config.MaskedSecret
|
||||
}
|
||||
maskStorageSecrets(value.Admin.Storage)
|
||||
config.MaskStorageSecrets(value.Admin.Storage)
|
||||
}
|
||||
|
||||
func maskDataSecrets(value *config.Data) {
|
||||
|
|
@ -335,24 +335,24 @@ func maskDataSecrets(value *config.Data) {
|
|||
return
|
||||
}
|
||||
if value.Database != nil {
|
||||
value.Database.Password = "******"
|
||||
value.Database.Password = config.MaskedSecret
|
||||
value.Database.Source = ""
|
||||
}
|
||||
if value.Redis != nil {
|
||||
value.Redis.Password = "******"
|
||||
value.Redis.Password = config.MaskedSecret
|
||||
}
|
||||
if value.Mongo != nil {
|
||||
value.Mongo.Password = "******"
|
||||
value.Mongo.Password = config.MaskedSecret
|
||||
}
|
||||
for _, item := range value.DatabaseList {
|
||||
if item != nil {
|
||||
item.Password = "******"
|
||||
item.Password = config.MaskedSecret
|
||||
item.Source = ""
|
||||
}
|
||||
}
|
||||
for _, item := range value.RedisList {
|
||||
if item != nil {
|
||||
item.Password = "******"
|
||||
item.Password = config.MaskedSecret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -365,10 +365,10 @@ func preserveConfigSecrets(next, current *config.Config) {
|
|||
if next.Admin == nil || current.Admin == nil {
|
||||
return
|
||||
}
|
||||
if next.Admin.JWT != nil && current.Admin.JWT != nil && maskedSecret(next.Admin.JWT.SigningKey) {
|
||||
if next.Admin.JWT != nil && current.Admin.JWT != nil && config.IsMaskedSecret(next.Admin.JWT.SigningKey) {
|
||||
next.Admin.JWT.SigningKey = current.Admin.JWT.SigningKey
|
||||
}
|
||||
if next.Admin.Email != nil && current.Admin.Email != nil && maskedSecret(next.Admin.Email.Secret) {
|
||||
if next.Admin.Email != nil && current.Admin.Email != nil && config.IsMaskedSecret(next.Admin.Email.Secret) {
|
||||
next.Admin.Email.Secret = current.Admin.Email.Secret
|
||||
}
|
||||
preserveStorageSecrets(next.Admin.Storage, current.Admin.Storage)
|
||||
|
|
@ -379,17 +379,17 @@ func preserveDataSecrets(next, current *config.Data) {
|
|||
return
|
||||
}
|
||||
if next.Database != nil && current.Database != nil {
|
||||
if maskedSecret(next.Database.Password) {
|
||||
if config.IsMaskedSecret(next.Database.Password) {
|
||||
next.Database.Password = current.Database.Password
|
||||
}
|
||||
if next.Database.Source == "" {
|
||||
next.Database.Source = current.Database.Source
|
||||
}
|
||||
}
|
||||
if next.Redis != nil && current.Redis != nil && maskedSecret(next.Redis.Password) {
|
||||
if next.Redis != nil && current.Redis != nil && config.IsMaskedSecret(next.Redis.Password) {
|
||||
next.Redis.Password = current.Redis.Password
|
||||
}
|
||||
if next.Mongo != nil && current.Mongo != nil && maskedSecret(next.Mongo.Password) {
|
||||
if next.Mongo != nil && current.Mongo != nil && config.IsMaskedSecret(next.Mongo.Password) {
|
||||
next.Mongo.Password = current.Mongo.Password
|
||||
}
|
||||
preserveDatabaseListSecrets(next.DatabaseList, current.DatabaseList)
|
||||
|
|
@ -414,7 +414,7 @@ func preserveDatabaseListSecrets(next, current []*config.Database) {
|
|||
if previous == nil {
|
||||
continue
|
||||
}
|
||||
if maskedSecret(item.Password) {
|
||||
if config.IsMaskedSecret(item.Password) {
|
||||
item.Password = previous.Password
|
||||
}
|
||||
if item.Source == "" {
|
||||
|
|
@ -438,43 +438,22 @@ func preserveRedisListSecrets(next, current []*config.Redis) {
|
|||
if previous == nil && index < len(current) {
|
||||
previous = current[index]
|
||||
}
|
||||
if previous != nil && maskedSecret(item.Password) {
|
||||
if previous != nil && config.IsMaskedSecret(item.Password) {
|
||||
item.Password = previous.Password
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func maskedSecret(value string) bool { return value == "" || value == "******" }
|
||||
|
||||
func objectStores(value *config.Storage) []*config.ObjectStore {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
return []*config.ObjectStore{value.AliyunOSS, value.HuaweiOBS, value.TencentCOS, value.AWSS3, value.CloudflareR2, value.Minio}
|
||||
}
|
||||
func maskStorageSecrets(value *config.Storage) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
if value.Qiniu != nil && value.Qiniu.SecretKey != "" {
|
||||
value.Qiniu.SecretKey = "******"
|
||||
}
|
||||
for _, item := range objectStores(value) {
|
||||
if item != nil && item.SecretKey != "" {
|
||||
item.SecretKey = "******"
|
||||
}
|
||||
}
|
||||
}
|
||||
func preserveStorageSecrets(next, current *config.Storage) {
|
||||
if next == nil || current == nil {
|
||||
return
|
||||
}
|
||||
if next.Qiniu != nil && current.Qiniu != nil && maskedSecret(next.Qiniu.SecretKey) {
|
||||
if next.Qiniu != nil && current.Qiniu != nil && config.IsMaskedSecret(next.Qiniu.SecretKey) {
|
||||
next.Qiniu.SecretKey = current.Qiniu.SecretKey
|
||||
}
|
||||
nextItems, currentItems := objectStores(next), objectStores(current)
|
||||
nextItems, currentItems := config.ObjectStores(next), config.ObjectStores(current)
|
||||
for index := range nextItems {
|
||||
if nextItems[index] != nil && currentItems[index] != nil && maskedSecret(nextItems[index].SecretKey) {
|
||||
if nextItems[index] != nil && currentItems[index] != nil && config.IsMaskedSecret(nextItems[index].SecretKey) {
|
||||
nextItems[index].SecretKey = currentItems[index].SecretKey
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
integrationbiz "kra/internal/biz/integration"
|
||||
"strings"
|
||||
|
||||
"kra/internal/config"
|
||||
"kra/internal/integration/mq"
|
||||
"kra/internal/integration/runtimeconfig"
|
||||
websocketintegration "kra/internal/integration/websocket"
|
||||
|
|
@ -73,11 +74,11 @@ func (t *ConnectivityTester) restoreMaskedSecrets(kind, provider string, values
|
|||
}
|
||||
for key := range masked {
|
||||
value, _ := values[key].(string)
|
||||
if strings.TrimSpace(value) != "******" {
|
||||
if strings.TrimSpace(value) != config.MaskedSecret {
|
||||
continue
|
||||
}
|
||||
prior, _ := currentValues[key].(string)
|
||||
if strings.TrimSpace(prior) == "" || strings.TrimSpace(prior) == "******" {
|
||||
if config.IsMaskedSecret(strings.TrimSpace(prior)) {
|
||||
return fmt.Errorf("配置字段 %s 已脱敏,请重新填写后再测试", key)
|
||||
}
|
||||
values[key] = prior
|
||||
|
|
|
|||
|
|
@ -14,17 +14,13 @@ func NewAnnouncement(service *service.AnnouncementService) *Announcement {
|
|||
return &Announcement{service: service}
|
||||
}
|
||||
|
||||
func announcementInput(req dto.AnnouncementRequest) service.AnnouncementInput {
|
||||
return service.AnnouncementInput{ID: req.ID, Title: req.Title, Content: req.Content, UserID: req.UserID, Attachments: req.Attachments}
|
||||
}
|
||||
|
||||
func (h *Announcement) Create(c *gin.Context) {
|
||||
var req dto.AnnouncementRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
if err := h.service.Create(c.Request.Context(), announcementInput(req)); err != nil {
|
||||
if err := h.service.Create(c.Request.Context(), &req); err != nil {
|
||||
Fail(c, "创建失败")
|
||||
return
|
||||
}
|
||||
|
|
@ -53,7 +49,7 @@ func (h *Announcement) Update(c *gin.Context) {
|
|||
Fail(c, err.Error())
|
||||
return
|
||||
}
|
||||
if err := h.service.Update(c.Request.Context(), announcementInput(req)); err != nil {
|
||||
if err := h.service.Update(c.Request.Context(), &req); err != nil {
|
||||
Fail(c, "更新失败")
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package middleware
|
|||
import (
|
||||
"context"
|
||||
"kra/internal/biz/system"
|
||||
httpx "kra/pkg/httpx"
|
||||
|
||||
"kra/internal/config"
|
||||
"kra/internal/utils/routepath"
|
||||
|
|
@ -19,11 +20,11 @@ func AccessControl(runtime *config.Store, access accessController) gin.HandlerFu
|
|||
return func(c *gin.Context) {
|
||||
claims := Claims(c)
|
||||
if claims == nil {
|
||||
NoAuth(c, "未登录或非法访问")
|
||||
httpx.NoAuth(c, "未登录或非法访问")
|
||||
return
|
||||
}
|
||||
if access == nil {
|
||||
Write(c, CodeError, gin.H{}, "权限服务不可用")
|
||||
httpx.Write(c, httpx.CodeError, gin.H{}, "权限服务不可用")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
|
@ -36,13 +37,13 @@ func AccessControl(runtime *config.Store, access accessController) gin.HandlerFu
|
|||
}
|
||||
allowed, err := access.Authorize(c.Request.Context(), claims.AuthorityID, policyPath, c.Request.Method)
|
||||
if err != nil || !allowed {
|
||||
Write(c, CodeError, gin.H{}, "权限不足")
|
||||
httpx.Write(c, httpx.CodeError, gin.H{}, "权限不足")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
requestContext, err := access.ContextWithDataScope(c.Request.Context(), claims.AuthorityID, claims.ID)
|
||||
if err != nil {
|
||||
Write(c, CodeError, gin.H{}, "数据权限解析失败")
|
||||
httpx.Write(c, httpx.CodeError, gin.H{}, "数据权限解析失败")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"errors"
|
||||
"io"
|
||||
"kra/internal/biz/system"
|
||||
httpx "kra/pkg/httpx"
|
||||
"log/slog"
|
||||
"mime"
|
||||
"net/http"
|
||||
|
|
@ -51,7 +52,7 @@ func AccessLog(runtime *config.Store, logger *slog.Logger, version string) gin.H
|
|||
c.Header("X-Kra-Version", version)
|
||||
requestReadFailed := c.Request.ContentLength > bodyLimit
|
||||
if requestReadFailed {
|
||||
c.AbortWithStatusJSON(http.StatusRequestEntityTooLarge, gin.H{"code": CodeError, "msg": "请求体超过大小上限"})
|
||||
c.AbortWithStatusJSON(http.StatusRequestEntityTooLarge, gin.H{"code": httpx.CodeError, "msg": "请求体超过大小上限"})
|
||||
} else if c.Request.Body != nil && !mediaUpload {
|
||||
limited := http.MaxBytesReader(c.Writer, c.Request.Body, bodyLimit)
|
||||
var err error
|
||||
|
|
@ -60,9 +61,9 @@ func AccessLog(runtime *config.Store, logger *slog.Logger, version string) gin.H
|
|||
requestReadFailed = true
|
||||
var tooLarge *http.MaxBytesError
|
||||
if errors.As(err, &tooLarge) {
|
||||
c.AbortWithStatusJSON(http.StatusRequestEntityTooLarge, gin.H{"code": CodeError, "msg": "请求体超过大小上限"})
|
||||
c.AbortWithStatusJSON(http.StatusRequestEntityTooLarge, gin.H{"code": httpx.CodeError, "msg": "请求体超过大小上限"})
|
||||
} else {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"code": CodeError, "msg": "请求体读取失败"})
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"code": httpx.CodeError, "msg": "请求体读取失败"})
|
||||
}
|
||||
} else {
|
||||
c.Request.Body = io.NopCloser(bytes.NewReader(requestBody))
|
||||
|
|
@ -204,9 +205,8 @@ func paymentConfigSummary(body []byte) string {
|
|||
func redactHeaders(headers map[string][]string) map[string]string {
|
||||
out := make(map[string]string, len(headers))
|
||||
for key, values := range headers {
|
||||
lower := strings.ToLower(key)
|
||||
if lower == "authorization" || lower == "cookie" || lower == "set-cookie" || lower == "x-token" {
|
||||
out[key] = "***"
|
||||
if isSensitiveHeader(key) {
|
||||
out[key] = redactedValue
|
||||
} else {
|
||||
out[key] = strings.Join(values, ",")
|
||||
}
|
||||
|
|
@ -220,23 +220,13 @@ func redactQuery(raw string) string {
|
|||
}
|
||||
values, _ := url.ParseQuery(raw)
|
||||
for key := range values {
|
||||
if sensitiveQueryKey(key) {
|
||||
values[key] = []string{"***"}
|
||||
if isSensitivePayloadKey(key) {
|
||||
values[key] = []string{redactedValue}
|
||||
}
|
||||
}
|
||||
return values.Encode()
|
||||
}
|
||||
|
||||
func sensitiveQueryKey(key string) bool {
|
||||
normalized := strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(key, "_", ""), "-", ""))
|
||||
switch normalized {
|
||||
case "token", "accesstoken", "refreshtoken", "authorization", "apikey", "secret":
|
||||
return true
|
||||
default:
|
||||
return strings.HasSuffix(normalized, "token")
|
||||
}
|
||||
}
|
||||
|
||||
func stringValueFromContext(c *gin.Context, key string) string {
|
||||
value, _ := c.Get(key)
|
||||
return stringValue(value)
|
||||
|
|
|
|||
|
|
@ -135,25 +135,12 @@ func operationRequestBody(raw []byte, contentType string, limit int) string {
|
|||
return text
|
||||
}
|
||||
|
||||
// operationSecretKeys holds the normalized JSON keys whose values never reach
|
||||
// the operation record. Keys are compared after lowercasing and stripping
|
||||
// separators, so "new_password" and "newPassword" both match "newpassword".
|
||||
var operationSecretKeys = map[string]struct{}{
|
||||
"password": {}, "newpassword": {}, "oldpassword": {}, "confirmpassword": {},
|
||||
"passwd": {}, "pwd": {}, "token": {}, "accesstoken": {}, "refreshtoken": {},
|
||||
"secret": {}, "clientsecret": {}, "apikey": {}, "privatekey": {}, "idcard": {},
|
||||
"appkey": {}, "mchkey": {}, "apiv3key": {}, "clientcert": {}, "clientkey": {},
|
||||
"platformcert": {}, "platformserialno": {}, "credentialcode": {}, "certfile": {},
|
||||
"keyfile": {}, "publickey": {}, "rootcert": {}, "appcert": {}, "webhookid": {},
|
||||
}
|
||||
|
||||
func maskOperationBody(value any) {
|
||||
switch current := value.(type) {
|
||||
case map[string]any:
|
||||
for key, item := range current {
|
||||
normalized := strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(key, "_", ""), "-", ""))
|
||||
if _, secret := operationSecretKeys[normalized]; secret {
|
||||
current[key] = "***"
|
||||
if isSensitivePayloadKey(key) {
|
||||
current[key] = redactedValue
|
||||
continue
|
||||
}
|
||||
maskOperationBody(item)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"kra/internal/biz/system"
|
||||
httpx "kra/pkg/httpx"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -43,11 +44,11 @@ func AuthenticateWebSocket(c *gin.Context, auth TokenAuthenticator) bool {
|
|||
func authenticate(c *gin.Context, auth TokenAuthenticator, allowQueryToken bool) bool {
|
||||
token := RequestToken(c, allowQueryToken)
|
||||
if token == "" {
|
||||
NoAuth(c, "未登录或非法访问,请登录")
|
||||
httpx.NoAuth(c, "未登录或非法访问,请登录")
|
||||
return false
|
||||
}
|
||||
if auth == nil {
|
||||
NoAuth(c, "认证服务不可用")
|
||||
httpx.NoAuth(c, "认证服务不可用")
|
||||
return false
|
||||
}
|
||||
// Followers of a singleflight flight must not inherit the leader's request
|
||||
|
|
@ -61,20 +62,20 @@ func authenticate(c *gin.Context, auth TokenAuthenticator, allowQueryToken bool)
|
|||
return auth.AuthenticateToken(ctx, token)
|
||||
})
|
||||
if err != nil {
|
||||
SetTokenCookie(c, "", -1)
|
||||
NoAuth(c, tokenErrorMessage(err))
|
||||
httpx.SetTokenCookie(c, "", -1)
|
||||
httpx.NoAuth(c, tokenErrorMessage(err))
|
||||
return false
|
||||
}
|
||||
authentication, ok := value.(*system.TokenAuthentication)
|
||||
if !ok || authentication == nil || authentication.Claims == nil {
|
||||
SetTokenCookie(c, "", -1)
|
||||
NoAuth(c, "无法处理此token")
|
||||
httpx.SetTokenCookie(c, "", -1)
|
||||
httpx.NoAuth(c, "无法处理此token")
|
||||
return false
|
||||
}
|
||||
if authentication.Refreshed != nil {
|
||||
c.Header("new-token", authentication.Refreshed.Value)
|
||||
c.Header("new-expires-at", strconv.FormatInt(authentication.Refreshed.ExpiresAt.Unix(), 10))
|
||||
SetTokenCookie(c, authentication.Refreshed.Value, int(authentication.Refreshed.TTL.Seconds()))
|
||||
httpx.SetTokenCookie(c, authentication.Refreshed.Value, int(authentication.Refreshed.TTL.Seconds()))
|
||||
}
|
||||
c.Set(claimsKey, authentication.Claims)
|
||||
return true
|
||||
|
|
@ -140,6 +141,6 @@ func MustChangePassword() gin.HandlerFunc {
|
|||
c.Next()
|
||||
return
|
||||
}
|
||||
c.AbortWithStatusJSON(http.StatusConflict, Response{Code: CodePasswordChangeRequired, Data: gin.H{"needChangePassword": true}, Msg: "密码已过期,请先修改密码"})
|
||||
c.AbortWithStatusJSON(http.StatusConflict, httpx.Response{Code: httpx.CodePasswordChangeRequired, Data: gin.H{"needChangePassword": true}, Msg: "密码已过期,请先修改密码"})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package middleware
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
httpx "kra/pkg/httpx"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ func ErrorAudit(logger *slog.Logger) gin.HandlerFunc {
|
|||
if auditPersistFailed != true && (strings.Contains(c.Request.URL.Path, "/sysError/") || strings.Contains(c.Request.URL.Path, "/logViewer/") || c.Writer.Status() >= 300 && c.Writer.Status() < 500) {
|
||||
return
|
||||
}
|
||||
var response Response
|
||||
var response httpx.Response
|
||||
var body []byte
|
||||
if value, ok := c.Get(ctxRespBufferKey); ok {
|
||||
if buffer, valid := value.(*bytes.Buffer); valid {
|
||||
|
|
@ -34,7 +35,7 @@ func ErrorAudit(logger *slog.Logger) gin.HandlerFunc {
|
|||
if json.Unmarshal(body, &response) != nil && privateErrors == "" {
|
||||
return
|
||||
}
|
||||
if response.Code == CodeSuccess && privateErrors == "" {
|
||||
if response.Code == httpx.CodeSuccess && privateErrors == "" {
|
||||
return
|
||||
}
|
||||
if privateErrors == "" && expectedClientFailure(response.Msg) {
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
httpx "kra/pkg/httpx"
|
||||
)
|
||||
|
||||
const (
|
||||
CodeSuccess = httpx.CodeSuccess
|
||||
CodeError = httpx.CodeError
|
||||
CodePasswordChangeRequired = httpx.CodePasswordChangeRequired
|
||||
)
|
||||
|
||||
type Response = httpx.Response
|
||||
|
||||
func Write(c *gin.Context, code int, data any, message string) { httpx.Write(c, code, data, message) }
|
||||
func NoAuth(c *gin.Context, message string) { httpx.NoAuth(c, message) }
|
||||
func SetTokenCookie(c *gin.Context, value string, maxAge int) { httpx.SetTokenCookie(c, value, maxAge) }
|
||||
|
|
@ -2,6 +2,7 @@ package middleware
|
|||
|
||||
import (
|
||||
"kra/internal/service"
|
||||
httpx "kra/pkg/httpx"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -22,7 +23,7 @@ func SecurityRateLimit(settings *service.SecurityService) gin.HandlerFunc {
|
|||
}
|
||||
config, err := settings.CurrentSecurity(c.Request.Context())
|
||||
if err != nil || config == nil {
|
||||
c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"code": CodeError, "msg": "安全服务暂不可用"})
|
||||
c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"code": httpx.CodeError, "msg": "安全服务暂不可用"})
|
||||
return
|
||||
}
|
||||
if !config.LimitEnable {
|
||||
|
|
@ -40,11 +41,11 @@ func SecurityRateLimit(settings *service.SecurityService) gin.HandlerFunc {
|
|||
key := "KRA_SecLimit:" + c.ClientIP() + ":" + route
|
||||
count, cacheErr := settings.IncrementRateLimit(c.Request.Context(), key, time.Duration(window)*time.Second)
|
||||
if cacheErr != nil {
|
||||
c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"code": CodeError, "msg": "安全服务暂不可用"})
|
||||
c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{"code": httpx.CodeError, "msg": "安全服务暂不可用"})
|
||||
return
|
||||
}
|
||||
if int(count) > config.LimitCount {
|
||||
c.JSON(200, gin.H{"code": CodeError, "msg": "请求太过频繁,请稍后再试"})
|
||||
c.JSON(200, gin.H{"code": httpx.CodeError, "msg": "请求太过频繁,请稍后再试"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"kra/internal/service"
|
||||
systemservice "kra/internal/service/system"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
|
@ -38,7 +38,7 @@ func (c rateLimitCache) Increment(context.Context, string, time.Duration) (int64
|
|||
|
||||
func TestSecurityRateLimitMatchesResponseContract(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
settings := service.NewSecurityService(system.NewSecurityUsecase(rateLimitSecurityRepo{}, rateLimitCache{}, nil, nil))
|
||||
settings := systemservice.NewSecurityService(system.NewSecurityUsecase(rateLimitSecurityRepo{}, rateLimitCache{}, nil, nil))
|
||||
engine := gin.New()
|
||||
engine.Use(SecurityRateLimit(settings))
|
||||
engine.POST("/base/login", func(c *gin.Context) { c.Status(http.StatusNoContent) })
|
||||
|
|
@ -56,7 +56,7 @@ func TestSecurityRateLimitMatchesResponseContract(t *testing.T) {
|
|||
|
||||
func TestSecurityRateLimitFailsClosedWhenCacheIsUnavailable(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
settings := service.NewSecurityService(system.NewSecurityUsecase(rateLimitSecurityRepo{}, rateLimitCache{err: errors.New("cache unavailable")}, nil, nil))
|
||||
settings := systemservice.NewSecurityService(system.NewSecurityUsecase(rateLimitSecurityRepo{}, rateLimitCache{err: errors.New("cache unavailable")}, nil, nil))
|
||||
engine := gin.New()
|
||||
called := false
|
||||
engine.Use(SecurityRateLimit(settings))
|
||||
|
|
|
|||
|
|
@ -64,9 +64,8 @@ func recoveryRequestDump(request *http.Request) string {
|
|||
clone := request.Clone(request.Context())
|
||||
clone.Header = request.Header.Clone()
|
||||
for key := range clone.Header {
|
||||
switch strings.ToLower(key) {
|
||||
case "authorization", "cookie", "set-cookie", "x-token", "proxy-authorization":
|
||||
clone.Header[key] = []string{"***"}
|
||||
if isSensitiveHeader(key) {
|
||||
clone.Header[key] = []string{redactedValue}
|
||||
}
|
||||
}
|
||||
if request.URL != nil {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
package middleware
|
||||
|
||||
import "strings"
|
||||
|
||||
// redactedValue replaces a sensitive value in every log line and audit record.
|
||||
const redactedValue = "***"
|
||||
|
||||
// sensitiveHeaders lists the headers whose value never reaches a log, compared
|
||||
// after lowercasing.
|
||||
var sensitiveHeaders = map[string]struct{}{
|
||||
"authorization": {}, "proxy-authorization": {}, "cookie": {}, "set-cookie": {}, "x-token": {},
|
||||
}
|
||||
|
||||
// sensitivePayloadKeys holds the normalized query and JSON body keys whose
|
||||
// values never reach a log or an operation record. Keys are compared after
|
||||
// lowercasing and stripping separators, so "new_password" and "newPassword"
|
||||
// both match "newpassword".
|
||||
var sensitivePayloadKeys = map[string]struct{}{
|
||||
"password": {}, "newpassword": {}, "oldpassword": {}, "confirmpassword": {},
|
||||
"passwd": {}, "pwd": {}, "token": {}, "accesstoken": {}, "refreshtoken": {},
|
||||
"secret": {}, "clientsecret": {}, "apikey": {}, "privatekey": {}, "idcard": {},
|
||||
"appkey": {}, "mchkey": {}, "apiv3key": {}, "clientcert": {}, "clientkey": {},
|
||||
"platformcert": {}, "platformserialno": {}, "credentialcode": {}, "certfile": {},
|
||||
"keyfile": {}, "publickey": {}, "rootcert": {}, "appcert": {}, "webhookid": {},
|
||||
"authorization": {},
|
||||
}
|
||||
|
||||
func isSensitiveHeader(key string) bool {
|
||||
_, sensitive := sensitiveHeaders[strings.ToLower(key)]
|
||||
return sensitive
|
||||
}
|
||||
|
||||
// isSensitivePayloadKey also matches every key ending in "token" so provider
|
||||
// specific token names stay masked without being enumerated.
|
||||
func isSensitivePayloadKey(key string) bool {
|
||||
normalized := strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(key, "_", ""), "-", ""))
|
||||
if _, sensitive := sensitivePayloadKeys[normalized]; sensitive {
|
||||
return true
|
||||
}
|
||||
return strings.HasSuffix(normalized, "token")
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package router
|
||||
|
||||
import "kra/internal/server/handler"
|
||||
|
||||
type Set = handler.Set
|
||||
type Announcement = handler.Announcement
|
||||
type API = handler.API
|
||||
type APIToken = handler.APIToken
|
||||
type Audit = handler.Audit
|
||||
type Authority = handler.Authority
|
||||
type Dictionary = handler.Dictionary
|
||||
type Email = handler.Email
|
||||
type Export = handler.Export
|
||||
type Media = handler.Media
|
||||
type Menu = handler.Menu
|
||||
type Navigation = handler.Navigation
|
||||
type Organization = handler.Organization
|
||||
type Parameter = handler.Parameter
|
||||
type Payment = handler.Payment
|
||||
type Permission = handler.Permission
|
||||
type Public = handler.Public
|
||||
type Session = handler.Session
|
||||
type SystemConfig = handler.SystemConfig
|
||||
type Task = handler.Task
|
||||
type User = handler.User
|
||||
type Version = handler.Version
|
||||
type IntegrationConfig = handler.IntegrationConfig
|
||||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterAnnouncement(private, public *gin.RouterGroup, h *Announcement) {
|
||||
func RegisterAnnouncement(private, public *gin.RouterGroup, h *handler.Announcement) {
|
||||
privateInfo := private.Group("/info")
|
||||
privateInfo.POST("/createInfo", h.Create)
|
||||
privateInfo.DELETE("/deleteInfo", h.Delete)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterAPI(group, public *gin.RouterGroup, engine *gin.Engine, h *API) {
|
||||
func RegisterAPI(group, public *gin.RouterGroup, engine *gin.Engine, h *handler.API) {
|
||||
api := group.Group("/api")
|
||||
api.POST("/getApiList", h.List)
|
||||
api.POST("/getAllApis", h.All)
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterAPIToken(group *gin.RouterGroup, handler *APIToken) {
|
||||
func RegisterAPIToken(group *gin.RouterGroup, h *handler.APIToken) {
|
||||
router := group.Group("/sysApiToken")
|
||||
router.POST("/createApiToken", handler.Create)
|
||||
router.POST("/getApiTokenList", handler.List)
|
||||
router.POST("/deleteApiToken", handler.Delete)
|
||||
router.POST("/createApiToken", h.Create)
|
||||
router.POST("/getApiTokenList", h.List)
|
||||
router.POST("/deleteApiToken", h.Delete)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterAudit(group, public *gin.RouterGroup, h *Audit) {
|
||||
func RegisterAudit(group, public *gin.RouterGroup, h *handler.Audit) {
|
||||
operations := group.Group("/sysOperationRecord")
|
||||
operations.GET("/getSysOperationRecordList", h.Operations)
|
||||
operations.GET("/findSysOperationRecord", h.Operation)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterAuthority(group *gin.RouterGroup, h *Authority) {
|
||||
func RegisterAuthority(group *gin.RouterGroup, h *handler.Authority) {
|
||||
router := group.Group("/authority")
|
||||
router.POST("/getAuthorityList", h.List)
|
||||
router.POST("/createAuthority", h.Create)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterDictionary(group *gin.RouterGroup, h *Dictionary) {
|
||||
func RegisterDictionary(group *gin.RouterGroup, h *handler.Dictionary) {
|
||||
dictionaries := group.Group("/sysDictionary")
|
||||
dictionaries.POST("/createSysDictionary", h.Create)
|
||||
dictionaries.PUT("/updateSysDictionary", h.Update)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterEmail(group *gin.RouterGroup, h *Email) {
|
||||
func RegisterEmail(group *gin.RouterGroup, h *handler.Email) {
|
||||
email := group.Group("/email")
|
||||
email.POST("/emailTest", h.Test)
|
||||
email.POST("/sendEmail", h.Send)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterExport(group, public *gin.RouterGroup, h *Export) {
|
||||
func RegisterExport(group, public *gin.RouterGroup, h *handler.Export) {
|
||||
router := group.Group("/sysExportTemplate")
|
||||
router.POST("/createSysExportTemplate", h.Create)
|
||||
router.PUT("/updateSysExportTemplate", h.Update)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
package router
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
|
||||
func RegisterIntegrationConfig(group *gin.RouterGroup, handler *IntegrationConfig) {
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterIntegrationConfig(group *gin.RouterGroup, h *handler.IntegrationConfig) {
|
||||
configs := group.Group("/integration/configs")
|
||||
configs.GET("/:kind", handler.List)
|
||||
configs.GET("/:kind/:provider", handler.Find)
|
||||
configs.PUT("/:kind/:provider", handler.Save)
|
||||
configs.POST("/:kind/:provider/test", handler.Test)
|
||||
configs.DELETE("/:kind/:provider", handler.Delete)
|
||||
configs.GET("/:kind", h.List)
|
||||
configs.GET("/:kind/:provider", h.Find)
|
||||
configs.PUT("/:kind/:provider", h.Save)
|
||||
configs.POST("/:kind/:provider/test", h.Test)
|
||||
configs.DELETE("/:kind/:provider", h.Delete)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterMedia(group *gin.RouterGroup, h *Media) {
|
||||
func RegisterMedia(group *gin.RouterGroup, h *handler.Media) {
|
||||
files := group.Group("/fileUploadAndDownload")
|
||||
files.POST("/upload", h.Upload)
|
||||
files.POST("/getFileList", h.List)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterMenu(group *gin.RouterGroup, h *Menu) {
|
||||
func RegisterMenu(group *gin.RouterGroup, h *handler.Menu) {
|
||||
router := group.Group("/menu")
|
||||
router.POST("/getMenuList", h.List)
|
||||
router.POST("/getBaseMenuTree", h.Tree)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterOrganization(group *gin.RouterGroup, h *Organization) {
|
||||
func RegisterOrganization(group *gin.RouterGroup, h *handler.Organization) {
|
||||
departments := group.Group("/department")
|
||||
departments.POST("/getDepartmentList", h.ListDepartments)
|
||||
departments.POST("/createDepartment", h.CreateDepartment)
|
||||
|
|
|
|||
|
|
@ -2,15 +2,16 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterParameter(group *gin.RouterGroup, handler *Parameter) {
|
||||
func RegisterParameter(group *gin.RouterGroup, h *handler.Parameter) {
|
||||
router := group.Group("/sysParams")
|
||||
router.POST("/createSysParams", handler.Create)
|
||||
router.PUT("/updateSysParams", handler.Update)
|
||||
router.DELETE("/deleteSysParams", handler.Delete)
|
||||
router.DELETE("/deleteSysParamsByIds", handler.DeleteMany)
|
||||
router.GET("/findSysParams", handler.Find)
|
||||
router.GET("/getSysParam", handler.Get)
|
||||
router.GET("/getSysParamsList", handler.List)
|
||||
router.POST("/createSysParams", h.Create)
|
||||
router.PUT("/updateSysParams", h.Update)
|
||||
router.DELETE("/deleteSysParams", h.Delete)
|
||||
router.DELETE("/deleteSysParamsByIds", h.DeleteMany)
|
||||
router.GET("/findSysParams", h.Find)
|
||||
router.GET("/getSysParam", h.Get)
|
||||
router.GET("/getSysParamsList", h.List)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterPayment(group, public *gin.RouterGroup, h *Payment) {
|
||||
func RegisterPayment(group, public *gin.RouterGroup, h *handler.Payment) {
|
||||
payment := group.Group("/payment")
|
||||
payment.GET("/orders", h.Orders)
|
||||
payment.POST("/providers/:provider/test", h.TestProvider)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterPermission(group *gin.RouterGroup, h *Permission) {
|
||||
func RegisterPermission(group *gin.RouterGroup, h *handler.Permission) {
|
||||
buttons := group.Group("/authorityBtn")
|
||||
buttons.POST("/getAuthorityBtn", h.Buttons)
|
||||
buttons.POST("/setAuthorityBtn", h.SetButtons)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterPublic(group *gin.RouterGroup, engine *gin.Engine, handler *Public) {
|
||||
func RegisterPublic(group *gin.RouterGroup, engine *gin.Engine, h *handler.Public) {
|
||||
base := group.Group("/base")
|
||||
base.POST("/captcha", handler.Captcha)
|
||||
base.POST("/login", handler.Login)
|
||||
base.POST("/captcha", h.Captcha)
|
||||
base.POST("/login", h.Login)
|
||||
init := group.Group("/init")
|
||||
init.POST("/checkdb", handler.CheckDatabase)
|
||||
init.POST("/initdb", handler.InitializeDatabase(engine))
|
||||
init.POST("/checkdb", h.CheckDatabase)
|
||||
init.POST("/initdb", h.InitializeDatabase(engine))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"kra/internal/server/handler"
|
||||
platformmodule "kra/pkg/module"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Routes struct {
|
||||
handlers *Set
|
||||
handlers *handler.Set
|
||||
}
|
||||
|
||||
func NewRoutes(handlers *Set) *Routes { return &Routes{handlers: handlers} }
|
||||
func NewRoutes(handlers *handler.Set) *Routes { return &Routes{handlers: handlers} }
|
||||
|
||||
var _ platformmodule.RouteRegistrar = (*Routes)(nil)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,16 +2,17 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterSystemConfig(group *gin.RouterGroup, handler *SystemConfig) {
|
||||
func RegisterSystemConfig(group *gin.RouterGroup, h *handler.SystemConfig) {
|
||||
security := group.Group("/securityConfig")
|
||||
security.GET("/getSecurityConfig", handler.GetSecurity)
|
||||
security.POST("/setSecurityConfig", handler.SetSecurity)
|
||||
security.GET("/getSecurityConfig", h.GetSecurity)
|
||||
security.POST("/setSecurityConfig", h.SetSecurity)
|
||||
|
||||
system := group.Group("/system")
|
||||
system.POST("/getSystemConfig", handler.Get)
|
||||
system.POST("/setSystemConfig", handler.Set)
|
||||
system.POST("/reloadSystem", handler.Reload)
|
||||
system.POST("/getServerInfo", handler.ServerInfo)
|
||||
system.POST("/getSystemConfig", h.Get)
|
||||
system.POST("/setSystemConfig", h.Set)
|
||||
system.POST("/reloadSystem", h.Reload)
|
||||
system.POST("/getServerInfo", h.ServerInfo)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterTask(group *gin.RouterGroup, h *Task) {
|
||||
func RegisterTask(group *gin.RouterGroup, h *handler.Task) {
|
||||
router := group.Group("/timedTask")
|
||||
router.POST("/createTimedTask", h.Create)
|
||||
router.PUT("/updateTimedTask", h.Update)
|
||||
|
|
|
|||
|
|
@ -2,27 +2,28 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterUser(group *gin.RouterGroup, handler *User) {
|
||||
func RegisterUser(group *gin.RouterGroup, h *handler.User) {
|
||||
user := group.Group("/user")
|
||||
user.POST("/getUserList", handler.List)
|
||||
user.POST("/admin_register", handler.Create)
|
||||
user.PUT("/setUserInfo", handler.Update)
|
||||
user.PUT("/setSelfInfo", handler.UpdateSelf)
|
||||
user.DELETE("/deleteUser", handler.Delete)
|
||||
user.POST("/resetPassword", handler.ResetPassword)
|
||||
user.POST("/changePassword", handler.ChangePassword)
|
||||
user.PUT("/setSelfSetting", handler.SetSelfSetting)
|
||||
user.POST("/setUserAuthorities", handler.SetAuthorities)
|
||||
user.POST("/setUserAuthority", handler.SwitchAuthority)
|
||||
user.GET("/getUserInfo", handler.Get)
|
||||
user.POST("/getUserList", h.List)
|
||||
user.POST("/admin_register", h.Create)
|
||||
user.PUT("/setUserInfo", h.Update)
|
||||
user.PUT("/setSelfInfo", h.UpdateSelf)
|
||||
user.DELETE("/deleteUser", h.Delete)
|
||||
user.POST("/resetPassword", h.ResetPassword)
|
||||
user.POST("/changePassword", h.ChangePassword)
|
||||
user.PUT("/setSelfSetting", h.SetSelfSetting)
|
||||
user.POST("/setUserAuthorities", h.SetAuthorities)
|
||||
user.POST("/setUserAuthority", h.SwitchAuthority)
|
||||
user.GET("/getUserInfo", h.Get)
|
||||
}
|
||||
|
||||
func RegisterNavigation(group *gin.RouterGroup, handler *Navigation) {
|
||||
group.Group("/menu").POST("/getMenu", handler.Menu)
|
||||
func RegisterNavigation(group *gin.RouterGroup, h *handler.Navigation) {
|
||||
group.Group("/menu").POST("/getMenu", h.Menu)
|
||||
}
|
||||
|
||||
func RegisterSession(group *gin.RouterGroup, handler *Session) {
|
||||
group.Group("/jwt").POST("/jsonInBlacklist", handler.Logout)
|
||||
func RegisterSession(group *gin.RouterGroup, h *handler.Session) {
|
||||
group.Group("/jwt").POST("/jsonInBlacklist", h.Logout)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ package router
|
|||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"kra/internal/server/handler"
|
||||
)
|
||||
|
||||
func RegisterVersion(group *gin.RouterGroup, h *Version) {
|
||||
func RegisterVersion(group *gin.RouterGroup, h *handler.Version) {
|
||||
router := group.Group("/sysVersion")
|
||||
router.DELETE("/deleteSysVersion", h.Delete)
|
||||
router.DELETE("/deleteSysVersionByIds", h.DeleteMany)
|
||||
|
|
|
|||
|
|
@ -1,27 +1,21 @@
|
|||
package service
|
||||
|
||||
// This package is a compatibility facade for the transport layer. Concrete
|
||||
// implementations live under service/system, service/payment,
|
||||
// service/integration, and service/task; aliases here preserve the original
|
||||
// service.* API used by handlers and the composition root.
|
||||
// This package is the transport layer's entry point into the service tier.
|
||||
// Concrete implementations live under service/system, service/payment,
|
||||
// service/integration, and service/task; the aliases here give handlers one
|
||||
// import instead of four, and Wire composes the module provider sets directly.
|
||||
|
||||
import (
|
||||
"kra/internal/biz/integration"
|
||||
paymentbiz "kra/internal/biz/payment"
|
||||
"kra/internal/biz/system"
|
||||
taskbiz "kra/internal/biz/task"
|
||||
"kra/internal/service/dto"
|
||||
integrationservice "kra/internal/service/integration"
|
||||
paymentservice "kra/internal/service/payment"
|
||||
systemservice "kra/internal/service/system"
|
||||
taskservice "kra/internal/service/task"
|
||||
"kra/internal/utils/routepath"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
type AccessControlService = systemservice.AccessControlService
|
||||
type AnnouncementInput = systemservice.AnnouncementInput
|
||||
type AnnouncementService = systemservice.AnnouncementService
|
||||
type APIService = systemservice.APIService
|
||||
type AuditService = systemservice.AuditService
|
||||
|
|
@ -32,7 +26,6 @@ type DepartmentService = systemservice.DepartmentService
|
|||
type DictionaryService = systemservice.DictionaryService
|
||||
type EmailService = systemservice.EmailService
|
||||
type ExportService = systemservice.ExportService
|
||||
type ExportToken = systemservice.ExportToken
|
||||
type LogViewerService = systemservice.LogViewerService
|
||||
type MediaService = systemservice.MediaService
|
||||
type MenuService = systemservice.MenuService
|
||||
|
|
@ -40,7 +33,6 @@ type ParameterService = systemservice.ParameterService
|
|||
type PermissionService = systemservice.PermissionService
|
||||
type PositionService = systemservice.PositionService
|
||||
type SecurityService = systemservice.SecurityService
|
||||
type PasswordPolicyError = systemservice.PasswordPolicyError
|
||||
type SystemConfigService = systemservice.SystemConfigService
|
||||
type TokenService = systemservice.TokenService
|
||||
type VersionService = systemservice.VersionService
|
||||
|
|
@ -49,90 +41,9 @@ type IntegrationConfigService = integrationservice.IntegrationConfigService
|
|||
type TaskService = taskservice.TaskService
|
||||
type UserService = systemservice.UserService
|
||||
|
||||
func NewAccessControlService(uc *system.AccessControlUsecase) *AccessControlService {
|
||||
return systemservice.NewAccessControlService(uc)
|
||||
}
|
||||
func NewAnnouncementService(uc *system.AnnouncementUsecase) *AnnouncementService {
|
||||
return systemservice.NewAnnouncementService(uc)
|
||||
}
|
||||
func NewAPIService(uc *system.APIUsecase, settings system.RuntimeSettings) *APIService {
|
||||
return systemservice.NewAPIService(uc, settings)
|
||||
}
|
||||
func NewAuditService(uc *system.AuditUsecase) *AuditService {
|
||||
return systemservice.NewAuditService(uc)
|
||||
}
|
||||
func NewAuditRecorder(uc *system.AuditRecorderUsecase) *AuditRecorder {
|
||||
return systemservice.NewAuditRecorder(uc)
|
||||
}
|
||||
func NewAuthService(uc *system.AuthenticationUsecase) *AuthService {
|
||||
return systemservice.NewAuthService(uc)
|
||||
}
|
||||
func NewAuthorityService(uc *system.AuthorityUsecase) *AuthorityService {
|
||||
return systemservice.NewAuthorityService(uc)
|
||||
}
|
||||
func NewDepartmentService(uc *system.DepartmentUsecase) *DepartmentService {
|
||||
return systemservice.NewDepartmentService(uc)
|
||||
}
|
||||
func NewDictionaryService(uc *system.DictionaryUsecase) *DictionaryService {
|
||||
return systemservice.NewDictionaryService(uc)
|
||||
}
|
||||
func NewEmailService(uc *system.EmailUsecase) *EmailService {
|
||||
return systemservice.NewEmailService(uc)
|
||||
}
|
||||
func NewExportService(uc *system.ExportUsecase, cache system.Cache) *ExportService {
|
||||
return systemservice.NewExportService(uc, cache)
|
||||
}
|
||||
func NewIntegrationConfigService(uc *integration.IntegrationConfigUsecase) *IntegrationConfigService {
|
||||
return integrationservice.NewIntegrationConfigService(uc)
|
||||
}
|
||||
func NewLogViewerService(uc *system.LogViewerUsecase) *LogViewerService {
|
||||
return systemservice.NewLogViewerService(uc)
|
||||
}
|
||||
func NewMediaService(uc *system.MediaUsecase, settings system.RuntimeSettings) *MediaService {
|
||||
return systemservice.NewMediaService(uc, settings)
|
||||
}
|
||||
func NewMenuService(uc *system.MenuUsecase) *MenuService {
|
||||
return systemservice.NewMenuService(uc)
|
||||
}
|
||||
func NewParameterService(uc *system.ParameterUsecase) *ParameterService {
|
||||
return systemservice.NewParameterService(uc)
|
||||
}
|
||||
func NewPaymentService(uc *paymentbiz.PaymentUsecase) *PaymentService {
|
||||
return paymentservice.NewPaymentService(uc)
|
||||
}
|
||||
func NewPermissionService(uc *system.PermissionUsecase) *PermissionService {
|
||||
return systemservice.NewPermissionService(uc)
|
||||
}
|
||||
func NewPositionService(uc *system.PositionUsecase) *PositionService {
|
||||
return systemservice.NewPositionService(uc)
|
||||
}
|
||||
func NewSecurityService(uc *system.SecurityUsecase) *SecurityService {
|
||||
return systemservice.NewSecurityService(uc)
|
||||
}
|
||||
func NewSystemConfigService(uc *system.SystemConfigUsecase, settings system.RuntimeSettings) *SystemConfigService {
|
||||
return systemservice.NewSystemConfigService(uc, settings)
|
||||
}
|
||||
func NewTaskService(uc *taskbiz.TaskApplicationUsecase) *TaskService {
|
||||
return taskservice.NewTaskService(uc)
|
||||
}
|
||||
func NewTokenService(uc *system.TokenUsecase, issuer system.TokenIssuer) *TokenService {
|
||||
return systemservice.NewTokenService(uc, issuer)
|
||||
}
|
||||
func NewUserService(uc *system.UserUsecase, settings *SecurityService) *UserService {
|
||||
return systemservice.NewUserService(uc, settings)
|
||||
}
|
||||
func NewVersionService(uc *system.VersionUsecase) *VersionService {
|
||||
return systemservice.NewVersionService(uc)
|
||||
}
|
||||
|
||||
var ErrExportTokenInvalid = systemservice.ErrExportTokenInvalid
|
||||
var ErrExportTokenMalformed = systemservice.ErrExportTokenMalformed
|
||||
var ErrExportTokenType = systemservice.ErrExportTokenType
|
||||
|
||||
func NormalizeRoutePath(path, routerPrefix string) string {
|
||||
return routepath.Normalize(path, routerPrefix)
|
||||
}
|
||||
|
||||
func IsPasswordPolicyError(err error) bool { return systemservice.IsPasswordPolicyError(err) }
|
||||
|
||||
func DefaultPaymentCallbackAck(provider string, success bool) dto.PaymentCallbackAck {
|
||||
|
|
|
|||
|
|
@ -9,14 +9,6 @@ import (
|
|||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type AnnouncementInput struct {
|
||||
ID uint
|
||||
Title string
|
||||
Content string
|
||||
UserID *int
|
||||
Attachments json.RawMessage
|
||||
}
|
||||
|
||||
type AnnouncementService struct{ uc *system.AnnouncementUsecase }
|
||||
|
||||
func NewAnnouncementService(uc *system.AnnouncementUsecase) *AnnouncementService {
|
||||
|
|
@ -27,15 +19,15 @@ func announcementDTO(item *system.Announcement) *dto.AnnouncementResponse {
|
|||
return &dto.AnnouncementResponse{ID: item.ID, CreatedAt: item.CreatedAt, UpdatedAt: item.UpdatedAt, DeletedAt: nil, Title: item.Title, Content: item.Content, UserID: item.UserID, Attachments: json.RawMessage(item.Attachments)}
|
||||
}
|
||||
|
||||
func announcementDO(in AnnouncementInput) *system.Announcement {
|
||||
func announcementDO(in *dto.AnnouncementRequest) *system.Announcement {
|
||||
return &system.Announcement{ID: in.ID, Title: in.Title, Content: in.Content, UserID: in.UserID, Attachments: in.Attachments}
|
||||
}
|
||||
|
||||
func (s *AnnouncementService) Create(ctx context.Context, in AnnouncementInput) error {
|
||||
func (s *AnnouncementService) Create(ctx context.Context, in *dto.AnnouncementRequest) error {
|
||||
return s.uc.Create(ctx, announcementDO(in))
|
||||
}
|
||||
|
||||
func (s *AnnouncementService) Update(ctx context.Context, in AnnouncementInput) error {
|
||||
func (s *AnnouncementService) Update(ctx context.Context, in *dto.AnnouncementRequest) error {
|
||||
return s.uc.Update(ctx, announcementDO(in))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,9 +56,6 @@ func (s *AuditService) DeleteOperations(ctx context.Context, ids []int) error {
|
|||
func (s *AuditRecorder) RecordLogin(ctx context.Context, v *system.LoginLog) error {
|
||||
return s.uc.RecordLogin(ctx, v)
|
||||
}
|
||||
func (s *AuditRecorder) RecordLoginRequest(ctx context.Context, value *dto.LoginLogRequest) error {
|
||||
return s.RecordLogin(ctx, &system.LoginLog{Username: value.Username, IP: value.IP, Status: value.Status, ErrorMessage: value.ErrorMessage, Agent: value.Agent, UserID: value.UserID})
|
||||
}
|
||||
func (s *AuditService) LoginsFilter(ctx context.Context, page, size int, username string, status bool) ([]*dto.LoginLogResponse, int64, error) {
|
||||
return s.Logins(ctx, page, size, &system.LoginLog{Username: username, Status: status, FilterByStatus: status})
|
||||
}
|
||||
|
|
@ -94,9 +91,6 @@ func (s *AuditService) DeleteLogins(ctx context.Context, ids []int) error {
|
|||
func (s *AuditRecorder) RecordDataAccess(ctx context.Context, v *system.DataAccessLog) error {
|
||||
return s.uc.RecordDataAccess(ctx, v)
|
||||
}
|
||||
func (s *AuditRecorder) RecordDataAccessRequest(ctx context.Context, value *dto.DataAccessRecordRequest) error {
|
||||
return s.RecordDataAccess(ctx, &system.DataAccessLog{EventType: value.EventType, Operation: value.Operation, UserID: value.UserID, AuthorityID: value.AuthorityID, RequestID: value.RequestID, Method: value.Method, Path: value.Path, Detail: value.Detail})
|
||||
}
|
||||
func (s *AuditService) DataAccessRequest(ctx context.Context, req *dto.DataAccessListRequest) ([]*dto.DataAccessLogResponse, int64, error) {
|
||||
return s.DataAccess(ctx, req.Page, req.PageSize, &system.DataAccessLog{EventType: req.EventType, TargetTable: req.TargetTable})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,3 @@ func (s *EmailService) Test(ctx context.Context) error { return s.uc.Test(ctx) }
|
|||
func (s *EmailService) Send(ctx context.Context, to, subject, body string) error {
|
||||
return s.uc.Send(ctx, to, subject, body)
|
||||
}
|
||||
|
||||
func (s *EmailService) Alert(ctx context.Context, subject, body string) error {
|
||||
return s.uc.Alert(ctx, subject, body)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,10 +64,6 @@ func (s *SecurityService) CaptchaSettings() system.CaptchaSettings {
|
|||
return s.uc.CaptchaRuntimeSettings()
|
||||
}
|
||||
|
||||
func (s *SecurityService) ActiveTokenMatches(ctx context.Context, username, token string) (bool, error) {
|
||||
return s.uc.ActiveTokenMatches(ctx, username, token)
|
||||
}
|
||||
|
||||
func (s *SecurityService) RotateActiveToken(ctx context.Context, username, oldToken, newToken string, expiration time.Duration) error {
|
||||
return s.uc.RotateActiveToken(ctx, username, oldToken, newToken, expiration)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,14 +7,6 @@ import (
|
|||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type userInput struct {
|
||||
ID uint
|
||||
Username, Password, NickName, HeaderImg, Phone, Email string
|
||||
AuthorityID uint
|
||||
Enable int
|
||||
AuthorityIDs []uint
|
||||
}
|
||||
|
||||
type UserService struct {
|
||||
uc *system.UserUsecase
|
||||
settings *SecurityService
|
||||
|
|
@ -24,28 +16,39 @@ func NewUserService(uc *system.UserUsecase, settings *SecurityService) *UserServ
|
|||
return &UserService{uc: uc, settings: settings}
|
||||
}
|
||||
|
||||
func userRequestInput(value *dto.UserRequest) userInput {
|
||||
return userInput{ID: value.ID, Username: value.Username, Password: value.Password, NickName: value.NickName, HeaderImg: value.HeaderImg, AuthorityID: value.AuthorityID, AuthorityIDs: value.AuthorityIDs, Enable: value.Enable, Phone: value.Phone, Email: value.Email}
|
||||
}
|
||||
func (s *UserService) ListUsersRequest(ctx context.Context, value *dto.UserListRequest) ([]*dto.UserResponse, int64, error) {
|
||||
return s.ListUsers(ctx, value.Page, value.PageSize, &system.UserListFilter{Username: value.Username, NickName: value.NickName, Phone: value.Phone, Email: value.Email, OrderKey: value.OrderKey, Desc: value.Desc})
|
||||
}
|
||||
func (s *UserService) CreateUserRequest(ctx context.Context, value *dto.UserRequest) (*dto.UserResponse, error) {
|
||||
return s.createUser(ctx, userRequestInput(value))
|
||||
}
|
||||
func (s *UserService) UpdateUserRequest(ctx context.Context, value *dto.UserRequest) error {
|
||||
return s.updateUser(ctx, userRequestInput(value))
|
||||
}
|
||||
func (s *UserService) UpdateSelfUserRequest(ctx context.Context, id uint, value *dto.SelfUserRequest) error {
|
||||
return s.updateSelfUser(ctx, userInput{ID: id, NickName: value.NickName, HeaderImg: value.HeaderImg, Phone: value.Phone, Email: value.Email, Enable: value.Enable})
|
||||
users, total, err := s.uc.ListUsers(ctx, value.Page, value.PageSize, &system.UserListFilter{Username: value.Username, NickName: value.NickName, Phone: value.Phone, Email: value.Email, OrderKey: value.OrderKey, Desc: value.Desc})
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
result := make([]*dto.UserResponse, 0, len(users))
|
||||
for _, user := range users {
|
||||
result = append(result, convertUser(user))
|
||||
}
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
func (s *UserService) User(ctx context.Context, id uint) (*dto.UserResponse, error) {
|
||||
value, err := s.uc.User(ctx, id)
|
||||
func (s *UserService) CreateUserRequest(ctx context.Context, value *dto.UserRequest) (*dto.UserResponse, error) {
|
||||
if err := s.settings.ValidatePassword(ctx, value.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
security, _ := s.settings.CurrentSecurity(ctx)
|
||||
mustChange := security != nil && security.ForceNewUserChangePassword
|
||||
user, err := s.uc.CreateUser(ctx, &system.User{Username: value.Username, Password: value.Password, NickName: value.NickName, HeaderImg: value.HeaderImg, AuthorityID: value.AuthorityID, Phone: value.Phone, Email: value.Email, Enable: value.Enable, MustChangePassword: mustChange}, value.AuthorityIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertUser(value), nil
|
||||
return convertUser(user), nil
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateUserRequest(ctx context.Context, value *dto.UserRequest) error {
|
||||
// The compatible ChangeUserInfo payload uses authorityIds for role assignment; the
|
||||
// standalone authorityId field is not applied by setUserInfo.
|
||||
return s.uc.UpdateUser(ctx, &system.User{ID: value.ID, NickName: value.NickName, HeaderImg: value.HeaderImg, Phone: value.Phone, Email: value.Email, Enable: value.Enable}, value.AuthorityIDs)
|
||||
}
|
||||
|
||||
func (s *UserService) UpdateSelfUserRequest(ctx context.Context, id uint, value *dto.SelfUserRequest) error {
|
||||
return s.uc.UpdateSelfUser(ctx, &system.User{ID: id, NickName: value.NickName, HeaderImg: value.HeaderImg, Phone: value.Phone, Email: value.Email, Enable: value.Enable})
|
||||
}
|
||||
|
||||
func (s *UserService) UserByUUID(ctx context.Context, uuid string) (*dto.UserResponse, error) {
|
||||
|
|
@ -64,18 +67,6 @@ func (s *UserService) Menus(ctx context.Context, authorityID uint) ([]*dto.Dynam
|
|||
return dynamicMenuResponses(menus), nil
|
||||
}
|
||||
|
||||
func (s *UserService) ListUsers(ctx context.Context, page, pageSize int, filter *system.UserListFilter) ([]*dto.UserResponse, int64, error) {
|
||||
users, total, err := s.uc.ListUsers(ctx, page, pageSize, filter)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
result := make([]*dto.UserResponse, 0, len(users))
|
||||
for _, user := range users {
|
||||
result = append(result, convertUser(user))
|
||||
}
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
func (s *UserService) Authorities(ctx context.Context) ([]*dto.AuthorityResponse, error) {
|
||||
values, err := s.uc.Authorities(ctx)
|
||||
if err != nil {
|
||||
|
|
@ -88,26 +79,6 @@ func (s *UserService) Authorities(ctx context.Context) ([]*dto.AuthorityResponse
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (s *UserService) createUser(ctx context.Context, input userInput) (*dto.UserResponse, error) {
|
||||
if err := s.settings.ValidatePassword(ctx, input.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
security, _ := s.settings.CurrentSecurity(ctx)
|
||||
mustChange := security != nil && security.ForceNewUserChangePassword
|
||||
user, err := s.uc.CreateUser(ctx, &system.User{Username: input.Username, Password: input.Password, NickName: input.NickName, HeaderImg: input.HeaderImg, AuthorityID: input.AuthorityID, Phone: input.Phone, Email: input.Email, Enable: input.Enable, MustChangePassword: mustChange}, input.AuthorityIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertUser(user), nil
|
||||
}
|
||||
func (s *UserService) updateUser(ctx context.Context, input userInput) error {
|
||||
// The compatible ChangeUserInfo payload uses authorityIds for role assignment; the
|
||||
// standalone authorityId field is not applied by setUserInfo.
|
||||
return s.uc.UpdateUser(ctx, &system.User{ID: input.ID, NickName: input.NickName, HeaderImg: input.HeaderImg, Phone: input.Phone, Email: input.Email, Enable: input.Enable}, input.AuthorityIDs)
|
||||
}
|
||||
func (s *UserService) updateSelfUser(ctx context.Context, input userInput) error {
|
||||
return s.uc.UpdateSelfUser(ctx, &system.User{ID: input.ID, NickName: input.NickName, HeaderImg: input.HeaderImg, Phone: input.Phone, Email: input.Email, Enable: input.Enable})
|
||||
}
|
||||
func (s *UserService) DeleteUser(ctx context.Context, id uint) error {
|
||||
return s.uc.DeleteUser(ctx, id)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue