mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 17:27:23 +00:00
feat: System api (#3461)
* feat: start system api * feat: remove auth * feat: change gitignore * feat: run system api * feat: remove clear view form admin api * feat: search instances * feat: add instance * fix: set primary domain * Update .gitignore * fix: add instance * fix: add instance * fix: handle errors * fix: handle instance name * fix: test Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
parent
a7816a43b1
commit
3d5891eb11
2
.gitignore
vendored
2
.gitignore
vendored
@ -58,7 +58,7 @@ openapi/**/*.json
|
|||||||
/internal/api/ui/console/static/*
|
/internal/api/ui/console/static/*
|
||||||
|
|
||||||
# local
|
# local
|
||||||
build/local/cloud.env
|
build/local/*.env
|
||||||
migrations/cockroach/migrate_cloud.go
|
migrations/cockroach/migrate_cloud.go
|
||||||
.notifications
|
.notifications
|
||||||
.artifacts
|
.artifacts
|
||||||
|
@ -24,6 +24,8 @@ type DefaultInstance struct {
|
|||||||
domain string
|
domain string
|
||||||
defaults systemdefaults.SystemDefaults
|
defaults systemdefaults.SystemDefaults
|
||||||
zitadelRoles []authz.RoleMapping
|
zitadelRoles []authz.RoleMapping
|
||||||
|
baseURL string
|
||||||
|
externalSecure bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mig *DefaultInstance) Execute(ctx context.Context) error {
|
func (mig *DefaultInstance) Execute(ctx context.Context) error {
|
||||||
@ -45,7 +47,8 @@ func (mig *DefaultInstance) Execute(ctx context.Context) error {
|
|||||||
mig.zitadelRoles,
|
mig.zitadelRoles,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
webauthn_helper.Config{},
|
//TODO: Livio will fix this, but it ZITADEL doesn't run without this
|
||||||
|
webauthn_helper.Config{DisplayName: "HELLO LIVIO", ID: "RPID"},
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
@ -54,8 +57,12 @@ func (mig *DefaultInstance) Execute(ctx context.Context) error {
|
|||||||
nil,
|
nil,
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
ctx = authz.WithRequestedDomain(ctx, mig.domain)
|
ctx = authz.WithRequestedDomain(ctx, mig.domain)
|
||||||
_, err = cmd.SetUpInstance(ctx, &mig.InstanceSetup)
|
|
||||||
|
_, _, err = cmd.SetUpInstance(ctx, &mig.InstanceSetup, mig.externalSecure, mig.baseURL)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
"github.com/caos/zitadel/internal/command"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
@ -15,20 +16,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Database database.Config
|
Database database.Config
|
||||||
SystemDefaults systemdefaults.SystemDefaults
|
SystemDefaults systemdefaults.SystemDefaults
|
||||||
InternalAuthZ authz.Config
|
InternalAuthZ authz.Config
|
||||||
ExternalPort uint16
|
ExternalPort uint16
|
||||||
ExternalDomain string
|
ExternalDomain string
|
||||||
ExternalSecure bool
|
ExternalSecure bool
|
||||||
Log *logging.Config
|
Log *logging.Config
|
||||||
EncryptionKeys *encryptionKeyConfig
|
EncryptionKeys *encryptionKeyConfig
|
||||||
|
DefaultInstance command.InstanceSetup
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustNewConfig(v *viper.Viper) *Config {
|
func MustNewConfig(v *viper.Viper) *Config {
|
||||||
config := new(Config)
|
config := new(Config)
|
||||||
err := v.Unmarshal(config)
|
err := v.Unmarshal(config,
|
||||||
logging.OnError(err).Fatal("unable to read config")
|
viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
|
||||||
|
hook.Base64ToBytesHookFunc(),
|
||||||
|
hook.TagToLanguageHookFunc(),
|
||||||
|
mapstructure.StringToTimeDurationHookFunc(),
|
||||||
|
mapstructure.StringToSliceHookFunc(","),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
err = config.Log.SetLogger()
|
err = config.Log.SetLogger()
|
||||||
logging.OnError(err).Fatal("unable to set logger")
|
logging.OnError(err).Fatal("unable to set logger")
|
||||||
|
@ -51,6 +51,12 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
|||||||
steps.s1ProjectionTable = &ProjectionTable{dbClient: dbClient}
|
steps.s1ProjectionTable = &ProjectionTable{dbClient: dbClient}
|
||||||
steps.s2AssetsTable = &AssetTable{dbClient: dbClient}
|
steps.s2AssetsTable = &AssetTable{dbClient: dbClient}
|
||||||
|
|
||||||
|
instanceSetup := config.DefaultInstance
|
||||||
|
instanceSetup.InstanceName = steps.S3DefaultInstance.InstanceSetup.InstanceName
|
||||||
|
instanceSetup.CustomDomain = steps.S3DefaultInstance.InstanceSetup.CustomDomain
|
||||||
|
instanceSetup.Org = steps.S3DefaultInstance.InstanceSetup.Org
|
||||||
|
steps.S3DefaultInstance.InstanceSetup = instanceSetup
|
||||||
|
|
||||||
steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address = strings.TrimSpace(steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address)
|
steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address = strings.TrimSpace(steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address)
|
||||||
if steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address == "" {
|
if steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address == "" {
|
||||||
steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address = "admin@" + config.ExternalDomain
|
steps.S3DefaultInstance.InstanceSetup.Org.Human.Email.Address = "admin@" + config.ExternalDomain
|
||||||
@ -63,13 +69,14 @@ func Setup(config *Config, steps *Steps, masterKey string) {
|
|||||||
steps.S3DefaultInstance.domain = config.ExternalDomain
|
steps.S3DefaultInstance.domain = config.ExternalDomain
|
||||||
steps.S3DefaultInstance.zitadelRoles = config.InternalAuthZ.RolePermissionMappings
|
steps.S3DefaultInstance.zitadelRoles = config.InternalAuthZ.RolePermissionMappings
|
||||||
steps.S3DefaultInstance.userEncryptionKey = config.EncryptionKeys.User
|
steps.S3DefaultInstance.userEncryptionKey = config.EncryptionKeys.User
|
||||||
steps.S3DefaultInstance.InstanceSetup.Zitadel.IsDevMode = !config.ExternalSecure
|
steps.S3DefaultInstance.externalSecure = config.ExternalSecure
|
||||||
steps.S3DefaultInstance.InstanceSetup.Zitadel.BaseURL = http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
steps.S3DefaultInstance.baseURL = http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
||||||
steps.S3DefaultInstance.InstanceSetup.Zitadel.IsDevMode = !config.ExternalSecure
|
|
||||||
steps.S3DefaultInstance.InstanceSetup.Zitadel.BaseURL = http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
migration.Migrate(ctx, eventstoreClient, steps.s1ProjectionTable)
|
err = migration.Migrate(ctx, eventstoreClient, steps.s1ProjectionTable)
|
||||||
migration.Migrate(ctx, eventstoreClient, steps.s2AssetsTable)
|
logging.OnError(err).Fatal("unable to migrate step 1")
|
||||||
migration.Migrate(ctx, eventstoreClient, steps.S3DefaultInstance)
|
err = migration.Migrate(ctx, eventstoreClient, steps.s2AssetsTable)
|
||||||
|
logging.OnError(err).Fatal("unable to migrate step 3")
|
||||||
|
err = migration.Migrate(ctx, eventstoreClient, steps.S3DefaultInstance)
|
||||||
|
logging.OnError(err).Fatal("unable to migrate step 4")
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
@ -2,6 +2,9 @@ package start
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
|
"github.com/caos/zitadel/internal/command"
|
||||||
|
"github.com/caos/zitadel/internal/config/hook"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
admin_es "github.com/caos/zitadel/internal/admin/repository/eventsourcing"
|
admin_es "github.com/caos/zitadel/internal/admin/repository/eventsourcing"
|
||||||
@ -42,14 +45,20 @@ type Config struct {
|
|||||||
InternalAuthZ internal_authz.Config
|
InternalAuthZ internal_authz.Config
|
||||||
SystemDefaults systemdefaults.SystemDefaults
|
SystemDefaults systemdefaults.SystemDefaults
|
||||||
EncryptionKeys *encryptionKeyConfig
|
EncryptionKeys *encryptionKeyConfig
|
||||||
|
DefaultInstance command.InstanceSetup
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustNewConfig(v *viper.Viper) *Config {
|
func MustNewConfig(v *viper.Viper) *Config {
|
||||||
config := new(Config)
|
config := new(Config)
|
||||||
|
|
||||||
err := v.Unmarshal(config)
|
err := v.Unmarshal(config,
|
||||||
logging.OnError(err).Fatal("unable to read config")
|
viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
|
||||||
|
hook.Base64ToBytesHookFunc(),
|
||||||
|
hook.TagToLanguageHookFunc(),
|
||||||
|
mapstructure.StringToTimeDurationHookFunc(),
|
||||||
|
mapstructure.StringToSliceHookFunc(","),
|
||||||
|
)),
|
||||||
|
)
|
||||||
err = config.Log.SetLogger()
|
err = config.Log.SetLogger()
|
||||||
logging.OnError(err).Fatal("unable to set logger")
|
logging.OnError(err).Fatal("unable to set logger")
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
"github.com/caos/oidc/pkg/op"
|
"github.com/caos/oidc/pkg/op"
|
||||||
|
"github.com/caos/zitadel/internal/api/grpc/system"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@ -142,7 +143,7 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman
|
|||||||
}
|
}
|
||||||
verifier := internal_authz.Start(repo)
|
verifier := internal_authz.Start(repo)
|
||||||
|
|
||||||
apis := api.New(config.Port, router, &repo, config.InternalAuthZ, config.ExternalSecure, config.HTTP2HostHeader)
|
authenticatedAPIs := api.New(config.Port, router, &repo, config.InternalAuthZ, config.ExternalSecure, config.HTTP2HostHeader)
|
||||||
authRepo, err := auth_es.Start(config.Auth, config.SystemDefaults, commands, queries, dbClient, assets.HandlerPrefix, keys.OIDC, keys.User)
|
authRepo, err := auth_es.Start(config.Auth, config.SystemDefaults, commands, queries, dbClient, assets.HandlerPrefix, keys.OIDC, keys.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error starting auth repo: %w", err)
|
return fmt.Errorf("error starting auth repo: %w", err)
|
||||||
@ -151,18 +152,21 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error starting admin repo: %w", err)
|
return fmt.Errorf("error starting admin repo: %w", err)
|
||||||
}
|
}
|
||||||
if err := apis.RegisterServer(ctx, admin.CreateServer(commands, queries, adminRepo, config.SystemDefaults.Domain, assets.HandlerPrefix, keys.User)); err != nil {
|
if err := authenticatedAPIs.RegisterServer(ctx, system.CreateServer(commands, queries, adminRepo, config.DefaultInstance, config.ExternalPort, config.ExternalDomain, config.ExternalSecure)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := apis.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, assets.HandlerPrefix, keys.User)); err != nil {
|
if err := authenticatedAPIs.RegisterServer(ctx, admin.CreateServer(commands, queries, adminRepo, config.SystemDefaults.Domain, assets.HandlerPrefix, keys.User)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := apis.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, assets.HandlerPrefix, keys.User)); err != nil {
|
if err := authenticatedAPIs.RegisterServer(ctx, management.CreateServer(commands, queries, config.SystemDefaults, assets.HandlerPrefix, keys.User)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := authenticatedAPIs.RegisterServer(ctx, auth.CreateServer(commands, queries, authRepo, config.SystemDefaults, assets.HandlerPrefix, keys.User)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader)
|
instanceInterceptor := middleware.InstanceInterceptor(queries, config.HTTP1HostHeader)
|
||||||
apis.RegisterHandler(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator, store, queries, instanceInterceptor.Handler))
|
authenticatedAPIs.RegisterHandler(assets.HandlerPrefix, assets.NewHandler(commands, verifier, config.InternalAuthZ, id.SonyFlakeGenerator, store, queries, instanceInterceptor.Handler))
|
||||||
|
|
||||||
userAgentInterceptor, err := middleware.NewUserAgentHandler(config.UserAgentCookie, keys.UserAgentCookieKey, config.ExternalDomain, id.SonyFlakeGenerator, config.ExternalSecure)
|
userAgentInterceptor, err := middleware.NewUserAgentHandler(config.UserAgentCookie, keys.UserAgentCookieKey, config.ExternalDomain, id.SonyFlakeGenerator, config.ExternalSecure)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -174,26 +178,26 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to start oidc provider: %w", err)
|
return fmt.Errorf("unable to start oidc provider: %w", err)
|
||||||
}
|
}
|
||||||
apis.RegisterHandler(oidc.HandlerPrefix, oidcProvider.HttpHandler())
|
authenticatedAPIs.RegisterHandler(oidc.HandlerPrefix, oidcProvider.HttpHandler())
|
||||||
|
|
||||||
openAPIHandler, err := openapi.Start()
|
openAPIHandler, err := openapi.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to start openapi handler: %w", err)
|
return fmt.Errorf("unable to start openapi handler: %w", err)
|
||||||
}
|
}
|
||||||
apis.RegisterHandler(openapi.HandlerPrefix, openAPIHandler)
|
authenticatedAPIs.RegisterHandler(openapi.HandlerPrefix, openAPIHandler)
|
||||||
|
|
||||||
baseURL := http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
baseURL := http_util.BuildHTTP(config.ExternalDomain, config.ExternalPort, config.ExternalSecure)
|
||||||
c, err := console.Start(config.Console, config.ExternalDomain, baseURL, issuer, instanceInterceptor.Handler)
|
c, err := console.Start(config.Console, config.ExternalDomain, baseURL, issuer, instanceInterceptor.Handler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to start console: %w", err)
|
return fmt.Errorf("unable to start console: %w", err)
|
||||||
}
|
}
|
||||||
apis.RegisterHandler(console.HandlerPrefix, c)
|
authenticatedAPIs.RegisterHandler(console.HandlerPrefix, c)
|
||||||
|
|
||||||
l, err := login.CreateLogin(config.Login, commands, queries, authRepo, store, config.SystemDefaults, console.HandlerPrefix+"/", config.ExternalDomain, baseURL, op.AuthCallbackURL(oidcProvider), config.ExternalSecure, userAgentInterceptor, instanceInterceptor.Handler, keys.User, keys.IDPConfig, keys.CSRFCookieKey)
|
l, err := login.CreateLogin(config.Login, commands, queries, authRepo, store, config.SystemDefaults, console.HandlerPrefix+"/", config.ExternalDomain, baseURL, op.AuthCallbackURL(oidcProvider), config.ExternalSecure, userAgentInterceptor, instanceInterceptor.Handler, keys.User, keys.IDPConfig, keys.CSRFCookieKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to start login: %w", err)
|
return fmt.Errorf("unable to start login: %w", err)
|
||||||
}
|
}
|
||||||
apis.RegisterHandler(login.HandlerPrefix, l.Handler())
|
authenticatedAPIs.RegisterHandler(login.HandlerPrefix, l.Handler())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1427,21 +1427,6 @@ they represent the delta of the event happend on the objects
|
|||||||
POST: /views/_search
|
POST: /views/_search
|
||||||
|
|
||||||
|
|
||||||
### ClearView
|
|
||||||
|
|
||||||
> **rpc** ClearView([ClearViewRequest](#clearviewrequest))
|
|
||||||
[ClearViewResponse](#clearviewresponse)
|
|
||||||
|
|
||||||
Truncates the delta of the change stream
|
|
||||||
be carefull with this function because ZITADEL has to
|
|
||||||
recompute the deltas after they got cleared.
|
|
||||||
Search requests will return wrong results until all deltas are recomputed
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
POST: /views/{database}/{view_name}
|
|
||||||
|
|
||||||
|
|
||||||
### ListFailedEvents
|
### ListFailedEvents
|
||||||
|
|
||||||
> **rpc** ListFailedEvents([ListFailedEventsRequest](#listfailedeventsrequest))
|
> **rpc** ListFailedEvents([ListFailedEventsRequest](#listfailedeventsrequest))
|
||||||
@ -1463,7 +1448,7 @@ For example if the SMTP-API wasn't able to send an email at the first time
|
|||||||
|
|
||||||
Deletes the event from failed events view.
|
Deletes the event from failed events view.
|
||||||
the event is not removed from the change stream
|
the event is not removed from the change stream
|
||||||
This call is usefull if the system was able to process the event later.
|
This call is usefull if the system was able to process the event later.
|
||||||
e.g. if the second try of sending an email was successful. the first try produced a
|
e.g. if the second try of sending an email was successful. the first try produced a
|
||||||
failed event. You can find out if it worked on the `failure_count`
|
failed event. You can find out if it worked on the `failure_count`
|
||||||
|
|
||||||
@ -1718,24 +1703,6 @@ This is an empty request
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
### ClearViewRequest
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
| Field | Type | Description | Validation |
|
|
||||||
| ----- | ---- | ----------- | ----------- |
|
|
||||||
| database | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
|
||||||
| view_name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### ClearViewResponse
|
|
||||||
This is an empty response
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### DeactivateIDPRequest
|
### DeactivateIDPRequest
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,13 +70,13 @@ DomainPrimaryQuery is always equals
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
### IdQuery
|
### IdsQuery
|
||||||
IdQuery is always equals
|
IdQuery is always equals
|
||||||
|
|
||||||
|
|
||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| id | string | - | string.max_len: 200<br /> |
|
| ids | repeated string | - | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -91,7 +91,6 @@ IdQuery is always equals
|
|||||||
| details | zitadel.v1.ObjectDetails | - | |
|
| details | zitadel.v1.ObjectDetails | - | |
|
||||||
| state | State | - | |
|
| state | State | - | |
|
||||||
| name | string | - | |
|
| name | string | - | |
|
||||||
| version | string | - | |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -102,19 +101,7 @@ IdQuery is always equals
|
|||||||
|
|
||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.id_query | IdQuery | - | |
|
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.id_query | IdsQuery | - | |
|
||||||
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.state_query | StateQuery | - | |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### StateQuery
|
|
||||||
StateQuery is always equals
|
|
||||||
|
|
||||||
|
|
||||||
| Field | Type | Description | Validation |
|
|
||||||
| ----- | ---- | ----------- | ----------- |
|
|
||||||
| state | State | - | enum.defined_only: true<br /> |
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ Returns a list of ZITADEL instances/tenants
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
POST: /instances
|
POST: /instances/_search
|
||||||
|
|
||||||
|
|
||||||
### GetInstance
|
### GetInstance
|
||||||
@ -70,18 +70,6 @@ This might take some time
|
|||||||
DELETE: /instances/{id}
|
DELETE: /instances/{id}
|
||||||
|
|
||||||
|
|
||||||
### GetUsage
|
|
||||||
|
|
||||||
> **rpc** GetUsage([GetUsageRequest](#getusagerequest))
|
|
||||||
[GetUsageResponse](#getusageresponse)
|
|
||||||
|
|
||||||
Returns the usage metrics of an instance
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GET: /instances/{id}/usage
|
|
||||||
|
|
||||||
|
|
||||||
### ListDomains
|
### ListDomains
|
||||||
|
|
||||||
> **rpc** ListDomains([ListDomainsRequest](#listdomainsrequest))
|
> **rpc** ListDomains([ListDomainsRequest](#listdomainsrequest))
|
||||||
@ -91,7 +79,7 @@ Returns the custom domains of an instance
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
GET: /instances/{id}/domains
|
POST: /instances/{id}/domains/_search
|
||||||
|
|
||||||
|
|
||||||
### AddDomain
|
### AddDomain
|
||||||
@ -227,13 +215,12 @@ failed event. You can find out if it worked on the `failure_count`
|
|||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| instance_name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
| instance_name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||||
| first_org_name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
| first_org_name | string | - | string.max_len: 200<br /> |
|
||||||
| custom_domain | string | - | string.max_len: 200<br /> |
|
| custom_domain | string | - | string.max_len: 200<br /> |
|
||||||
| owner_first_name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
| owner_first_name | string | - | string.max_len: 200<br /> |
|
||||||
| owner_last_name | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
| owner_last_name | string | - | string.max_len: 200<br /> |
|
||||||
| owner_email | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
| owner_email | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
||||||
| owner_username | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
| owner_username | string | - | string.max_len: 200<br /> |
|
||||||
| password | string | - | string.min_len: 1<br /> string.max_len: 200<br /> |
|
|
||||||
| request_limit | uint64 | - | |
|
| request_limit | uint64 | - | |
|
||||||
| action_mins_limit | uint64 | - | |
|
| action_mins_limit | uint64 | - | |
|
||||||
|
|
||||||
@ -247,6 +234,7 @@ failed event. You can find out if it worked on the `failure_count`
|
|||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| id | string | - | |
|
| id | string | - | |
|
||||||
|
| details | zitadel.v1.ObjectDetails | - | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,7 +69,9 @@ func (a *API) RegisterServer(ctx context.Context, grpcServer server.Server) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
a.RegisterHandler(prefix, handler)
|
a.RegisterHandler(prefix, handler)
|
||||||
a.verifier.RegisterServer(grpcServer.AppName(), grpcServer.MethodPrefix(), grpcServer.AuthMethods())
|
if a.verifier != nil {
|
||||||
|
a.verifier.RegisterServer(grpcServer.AppName(), grpcServer.MethodPrefix(), grpcServer.AuthMethods())
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package admin_test
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
admin_grpc "github.com/caos/zitadel/internal/api/grpc/admin"
|
|
||||||
"github.com/caos/zitadel/internal/test"
|
"github.com/caos/zitadel/internal/test"
|
||||||
"github.com/caos/zitadel/internal/view/model"
|
"github.com/caos/zitadel/internal/view/model"
|
||||||
admin_pb "github.com/caos/zitadel/pkg/grpc/admin"
|
admin_pb "github.com/caos/zitadel/pkg/grpc/admin"
|
||||||
@ -34,7 +33,7 @@ func TestFailedEventsToPbFields(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got := admin_grpc.FailedEventsViewToPb(tt.args.failedEvents)
|
got := FailedEventsViewToPb(tt.args.failedEvents)
|
||||||
for _, g := range got {
|
for _, g := range got {
|
||||||
test.AssertFieldsMapped(t, g)
|
test.AssertFieldsMapped(t, g)
|
||||||
}
|
}
|
||||||
@ -64,7 +63,7 @@ func TestFailedEventToPbFields(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
converted := admin_grpc.FailedEventViewToPb(tt.args.failedEvent)
|
converted := FailedEventViewToPb(tt.args.failedEvent)
|
||||||
test.AssertFieldsMapped(t, converted)
|
test.AssertFieldsMapped(t, converted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,7 +88,7 @@ func TestRemoveFailedEventRequestToModelFields(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
converted := admin_grpc.RemoveFailedEventRequestToModel(tt.args.req)
|
converted := RemoveFailedEventRequestToModel(tt.args.req)
|
||||||
test.AssertFieldsMapped(t, converted, "FailureCount", "ErrMsg")
|
test.AssertFieldsMapped(t, converted, "FailureCount", "ErrMsg")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,16 +22,3 @@ func (s *Server) ListViews(ctx context.Context, _ *admin_pb.ListViewsRequest) (*
|
|||||||
convertedCurrentSequences = append(convertedCurrentSequences, convertedViews...)
|
convertedCurrentSequences = append(convertedCurrentSequences, convertedViews...)
|
||||||
return &admin_pb.ListViewsResponse{Result: convertedCurrentSequences}, nil
|
return &admin_pb.ListViewsResponse{Result: convertedCurrentSequences}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ClearView(ctx context.Context, req *admin_pb.ClearViewRequest) (*admin_pb.ClearViewResponse, error) {
|
|
||||||
var err error
|
|
||||||
if req.Database != "zitadel" {
|
|
||||||
err = s.administrator.ClearView(ctx, req.Database, req.ViewName)
|
|
||||||
} else {
|
|
||||||
err = s.query.ClearCurrentSequence(ctx, req.ViewName)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &admin_pb.ClearViewResponse{}, nil
|
|
||||||
}
|
|
||||||
|
@ -7,6 +7,46 @@ import (
|
|||||||
instance_pb "github.com/caos/zitadel/pkg/grpc/instance"
|
instance_pb "github.com/caos/zitadel/pkg/grpc/instance"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func InstancesToPb(instances []*query.Instance) []*instance_pb.Instance {
|
||||||
|
list := make([]*instance_pb.Instance, len(instances))
|
||||||
|
for i, instance := range instances {
|
||||||
|
list[i] = InstanceToPb(instance)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func InstanceToPb(instance *query.Instance) *instance_pb.Instance {
|
||||||
|
return &instance_pb.Instance{
|
||||||
|
Details: object.ToViewDetailsPb(
|
||||||
|
instance.Sequence,
|
||||||
|
instance.CreationDate,
|
||||||
|
instance.ChangeDate,
|
||||||
|
instance.InstanceID(),
|
||||||
|
),
|
||||||
|
Id: instance.InstanceID(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InstanceQueriesToModel(queries []*instance_pb.Query) (_ []query.SearchQuery, err error) {
|
||||||
|
q := make([]query.SearchQuery, len(queries))
|
||||||
|
for i, query := range queries {
|
||||||
|
q[i], err = InstanceQueryToModel(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InstanceQueryToModel(searchQuery *instance_pb.Query) (query.SearchQuery, error) {
|
||||||
|
switch q := searchQuery.Query.(type) {
|
||||||
|
case *instance_pb.Query_IdQuery:
|
||||||
|
return query.NewInstanceIDsListSearchQuery(q.IdQuery.Ids...)
|
||||||
|
default:
|
||||||
|
return nil, errors.ThrowInvalidArgument(nil, "INST-3m0se", "List.Query.Invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func DomainQueriesToModel(queries []*instance_pb.DomainSearchQuery) (_ []query.SearchQuery, err error) {
|
func DomainQueriesToModel(queries []*instance_pb.DomainSearchQuery) (_ []query.SearchQuery, err error) {
|
||||||
q := make([]query.SearchQuery, len(queries))
|
q := make([]query.SearchQuery, len(queries))
|
||||||
for i, query := range queries {
|
for i, query := range queries {
|
||||||
@ -27,7 +67,7 @@ func DomainQueryToModel(searchQuery *instance_pb.DomainSearchQuery) (query.Searc
|
|||||||
case *instance_pb.DomainSearchQuery_PrimaryQuery:
|
case *instance_pb.DomainSearchQuery_PrimaryQuery:
|
||||||
return query.NewInstanceDomainPrimarySearchQuery(q.PrimaryQuery.Primary)
|
return query.NewInstanceDomainPrimarySearchQuery(q.PrimaryQuery.Primary)
|
||||||
default:
|
default:
|
||||||
return nil, errors.ThrowInvalidArgument(nil, "ORG-Ags42", "List.Query.Invalid")
|
return nil, errors.ThrowInvalidArgument(nil, "INST-Ags42", "List.Query.Invalid")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,10 @@ import (
|
|||||||
|
|
||||||
func AuthorizationInterceptor(verifier *authz.TokenVerifier, authConfig authz.Config) grpc.UnaryServerInterceptor {
|
func AuthorizationInterceptor(verifier *authz.TokenVerifier, authConfig authz.Config) grpc.UnaryServerInterceptor {
|
||||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||||
|
//TODO: Change as soon as we know how to authenticate system api
|
||||||
|
if verifier == nil {
|
||||||
|
return handler(ctx, req)
|
||||||
|
}
|
||||||
return authorize(ctx, req, info, handler, verifier, authConfig)
|
return authorize(ctx, req, info, handler, verifier, authConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
@ -16,13 +17,19 @@ type InstanceVerifier interface {
|
|||||||
GetInstance(ctx context.Context)
|
GetInstance(ctx context.Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InstanceInterceptor(verifier authz.InstanceVerifier, headerName string) grpc.UnaryServerInterceptor {
|
func InstanceInterceptor(verifier authz.InstanceVerifier, headerName string, ignoredServices ...string) grpc.UnaryServerInterceptor {
|
||||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||||
return setInstance(ctx, req, info, handler, verifier, headerName)
|
return setInstance(ctx, req, info, handler, verifier, headerName, ignoredServices...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setInstance(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, verifier authz.InstanceVerifier, headerName string) (_ interface{}, err error) {
|
func setInstance(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, verifier authz.InstanceVerifier, headerName string, ignoredServices ...string) (_ interface{}, err error) {
|
||||||
|
for _, service := range ignoredServices {
|
||||||
|
if strings.HasPrefix(info.FullMethod, service) {
|
||||||
|
return handler(ctx, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
host, err := hostNameFromContext(ctx, headerName)
|
host, err := hostNameFromContext(ctx, headerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Error(codes.PermissionDenied, err.Error())
|
return nil, status.Error(codes.PermissionDenied, err.Error())
|
||||||
|
@ -30,7 +30,8 @@ func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, querie
|
|||||||
middleware.SentryHandler(),
|
middleware.SentryHandler(),
|
||||||
middleware.NoCacheInterceptor(),
|
middleware.NoCacheInterceptor(),
|
||||||
middleware.ErrorHandler(),
|
middleware.ErrorHandler(),
|
||||||
middleware.InstanceInterceptor(queries, hostHeaderName),
|
//TODO: Handle Ignored Services
|
||||||
|
middleware.InstanceInterceptor(queries, hostHeaderName, "/zitadel.system.v1.SystemService"),
|
||||||
middleware.AuthorizationInterceptor(verifier, authConfig),
|
middleware.AuthorizationInterceptor(verifier, authConfig),
|
||||||
middleware.TranslationHandler(queries),
|
middleware.TranslationHandler(queries),
|
||||||
middleware.ValidationHandler(),
|
middleware.ValidationHandler(),
|
||||||
|
37
internal/api/grpc/system/failed_event.go
Normal file
37
internal/api/grpc/system/failed_event.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/query"
|
||||||
|
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) ListFailedEvents(ctx context.Context, req *system_pb.ListFailedEventsRequest) (*system_pb.ListFailedEventsResponse, error) {
|
||||||
|
failedEventsOld, err := s.administrator.GetFailedEvents(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
convertedOld := FailedEventsViewToPb(failedEventsOld)
|
||||||
|
|
||||||
|
failedEvents, err := s.query.SearchFailedEvents(ctx, new(query.FailedEventSearchQueries))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
convertedNew := FailedEventsToPb(failedEvents)
|
||||||
|
convertedOld = append(convertedOld, convertedNew...)
|
||||||
|
return &system_pb.ListFailedEventsResponse{Result: convertedOld}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) RemoveFailedEvent(ctx context.Context, req *system_pb.RemoveFailedEventRequest) (*system_pb.RemoveFailedEventResponse, error) {
|
||||||
|
var err error
|
||||||
|
if req.Database != "zitadel" {
|
||||||
|
err = s.administrator.RemoveFailedEvent(ctx, RemoveFailedEventRequestToModel(req))
|
||||||
|
} else {
|
||||||
|
err = s.query.RemoveFailedEvent(ctx, req.ViewName, req.FailedSequence)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &system_pb.RemoveFailedEventResponse{}, nil
|
||||||
|
}
|
51
internal/api/grpc/system/failed_event_converter.go
Normal file
51
internal/api/grpc/system/failed_event_converter.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/zitadel/internal/query"
|
||||||
|
"github.com/caos/zitadel/internal/view/model"
|
||||||
|
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FailedEventsViewToPb(failedEvents []*model.FailedEvent) []*system_pb.FailedEvent {
|
||||||
|
events := make([]*system_pb.FailedEvent, len(failedEvents))
|
||||||
|
for i, failedEvent := range failedEvents {
|
||||||
|
events[i] = FailedEventViewToPb(failedEvent)
|
||||||
|
}
|
||||||
|
return events
|
||||||
|
}
|
||||||
|
|
||||||
|
func FailedEventViewToPb(failedEvent *model.FailedEvent) *system_pb.FailedEvent {
|
||||||
|
return &system_pb.FailedEvent{
|
||||||
|
Database: failedEvent.Database,
|
||||||
|
ViewName: failedEvent.ViewName,
|
||||||
|
FailedSequence: failedEvent.FailedSequence,
|
||||||
|
FailureCount: failedEvent.FailureCount,
|
||||||
|
ErrorMessage: failedEvent.ErrMsg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FailedEventsToPb(failedEvents *query.FailedEvents) []*system_pb.FailedEvent {
|
||||||
|
events := make([]*system_pb.FailedEvent, len(failedEvents.FailedEvents))
|
||||||
|
for i, failedEvent := range failedEvents.FailedEvents {
|
||||||
|
events[i] = FailedEventToPb(failedEvent)
|
||||||
|
}
|
||||||
|
return events
|
||||||
|
}
|
||||||
|
|
||||||
|
func FailedEventToPb(failedEvent *query.FailedEvent) *system_pb.FailedEvent {
|
||||||
|
return &system_pb.FailedEvent{
|
||||||
|
Database: "zitadel",
|
||||||
|
ViewName: failedEvent.ProjectionName,
|
||||||
|
FailedSequence: failedEvent.FailedSequence,
|
||||||
|
FailureCount: failedEvent.FailureCount,
|
||||||
|
ErrorMessage: failedEvent.Error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveFailedEventRequestToModel(req *system_pb.RemoveFailedEventRequest) *model.FailedEvent {
|
||||||
|
return &model.FailedEvent{
|
||||||
|
Database: req.Database,
|
||||||
|
ViewName: req.ViewName,
|
||||||
|
FailedSequence: req.FailedSequence,
|
||||||
|
}
|
||||||
|
}
|
95
internal/api/grpc/system/failed_event_converter_test.go
Normal file
95
internal/api/grpc/system/failed_event_converter_test.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package system_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
system_grpc "github.com/caos/zitadel/internal/api/grpc/system"
|
||||||
|
"github.com/caos/zitadel/internal/test"
|
||||||
|
"github.com/caos/zitadel/internal/view/model"
|
||||||
|
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFailedEventsToPbFields(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
failedEvents []*model.FailedEvent
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "all fields",
|
||||||
|
args: args{
|
||||||
|
failedEvents: []*model.FailedEvent{
|
||||||
|
{
|
||||||
|
Database: "admin",
|
||||||
|
ViewName: "users",
|
||||||
|
FailedSequence: 456,
|
||||||
|
FailureCount: 5,
|
||||||
|
ErrMsg: "some error",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := system_grpc.FailedEventsViewToPb(tt.args.failedEvents)
|
||||||
|
for _, g := range got {
|
||||||
|
test.AssertFieldsMapped(t, g)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFailedEventToPbFields(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
failedEvent *model.FailedEvent
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"all fields",
|
||||||
|
args{
|
||||||
|
failedEvent: &model.FailedEvent{
|
||||||
|
Database: "admin",
|
||||||
|
ViewName: "users",
|
||||||
|
FailedSequence: 456,
|
||||||
|
FailureCount: 5,
|
||||||
|
ErrMsg: "some error",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
converted := system_grpc.FailedEventViewToPb(tt.args.failedEvent)
|
||||||
|
test.AssertFieldsMapped(t, converted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveFailedEventRequestToModelFields(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
req *system_pb.RemoveFailedEventRequest
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"all fields",
|
||||||
|
args{
|
||||||
|
req: &system_pb.RemoveFailedEventRequest{
|
||||||
|
Database: "admin",
|
||||||
|
ViewName: "users",
|
||||||
|
FailedSequence: 456,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
converted := system_grpc.RemoveFailedEventRequestToModel(tt.args.req)
|
||||||
|
test.AssertFieldsMapped(t, converted, "FailureCount", "ErrMsg")
|
||||||
|
}
|
||||||
|
}
|
127
internal/api/grpc/system/instance.go
Normal file
127
internal/api/grpc/system/instance.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
|
instance_grpc "github.com/caos/zitadel/internal/api/grpc/instance"
|
||||||
|
"github.com/caos/zitadel/internal/api/grpc/object"
|
||||||
|
object_pb "github.com/caos/zitadel/pkg/grpc/object"
|
||||||
|
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) ListInstances(ctx context.Context, req *system_pb.ListInstancesRequest) (*system_pb.ListInstancesResponse, error) {
|
||||||
|
queries, err := ListInstancesRequestToModel(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := s.query.SearchInstances(ctx, queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &system_pb.ListInstancesResponse{
|
||||||
|
Result: instance_grpc.InstancesToPb(result.Instances),
|
||||||
|
Details: &object_pb.ListDetails{
|
||||||
|
TotalResult: result.Count,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetInstance(ctx context.Context, req *system_pb.GetInstanceRequest) (*system_pb.GetInstanceResponse, error) {
|
||||||
|
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||||
|
instance, err := s.query.Instance(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &system_pb.GetInstanceResponse{
|
||||||
|
Instance: instance_grpc.InstanceToPb(instance),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) AddInstance(ctx context.Context, req *system_pb.AddInstanceRequest) (*system_pb.AddInstanceResponse, error) {
|
||||||
|
id, details, err := s.command.SetUpInstance(ctx, AddInstancePbToSetupInstance(req, s.DefaultInstance), s.ExternalSecure, s.BaseURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &system_pb.AddInstanceResponse{
|
||||||
|
Id: id,
|
||||||
|
Details: object.AddToDetailsPb(
|
||||||
|
details.Sequence,
|
||||||
|
details.EventDate,
|
||||||
|
details.ResourceOwner,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListDomains(ctx context.Context, req *system_pb.ListDomainsRequest) (*system_pb.ListDomainsResponse, error) {
|
||||||
|
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||||
|
queries, err := ListInstanceDomainsRequestToModel(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
domains, err := s.query.SearchInstanceDomains(ctx, queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &system_pb.ListDomainsResponse{
|
||||||
|
Result: instance_grpc.DomainsToPb(domains.Domains),
|
||||||
|
Details: object.ToListDetails(
|
||||||
|
domains.Count,
|
||||||
|
domains.Sequence,
|
||||||
|
domains.Timestamp,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) AddDomain(ctx context.Context, req *system_pb.AddDomainRequest) (*system_pb.AddDomainResponse, error) {
|
||||||
|
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||||
|
instance, err := s.query.Instance(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ctx = authz.WithInstance(ctx, instance)
|
||||||
|
details, err := s.command.AddInstanceDomain(ctx, req.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &system_pb.AddDomainResponse{
|
||||||
|
Details: object.AddToDetailsPb(
|
||||||
|
details.Sequence,
|
||||||
|
details.EventDate,
|
||||||
|
details.ResourceOwner,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) RemoveDomain(ctx context.Context, req *system_pb.RemoveDomainRequest) (*system_pb.RemoveDomainResponse, error) {
|
||||||
|
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||||
|
details, err := s.command.RemoveInstanceDomain(ctx, req.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &system_pb.RemoveDomainResponse{
|
||||||
|
Details: object.ChangeToDetailsPb(
|
||||||
|
details.Sequence,
|
||||||
|
details.EventDate,
|
||||||
|
details.ResourceOwner,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) SetPrimaryDomain(ctx context.Context, req *system_pb.SetPrimaryDomainRequest) (*system_pb.SetPrimaryDomainResponse, error) {
|
||||||
|
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||||
|
details, err := s.command.SetPrimaryInstanceDomain(ctx, req.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &system_pb.SetPrimaryDomainResponse{
|
||||||
|
Details: object.ChangeToDetailsPb(
|
||||||
|
details.Sequence,
|
||||||
|
details.EventDate,
|
||||||
|
details.ResourceOwner,
|
||||||
|
),
|
||||||
|
}, nil
|
||||||
|
}
|
97
internal/api/grpc/system/instance_converter.go
Normal file
97
internal/api/grpc/system/instance_converter.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
instance_grpc "github.com/caos/zitadel/internal/api/grpc/instance"
|
||||||
|
"github.com/caos/zitadel/internal/api/grpc/object"
|
||||||
|
"github.com/caos/zitadel/internal/command"
|
||||||
|
"github.com/caos/zitadel/internal/query"
|
||||||
|
instance_pb "github.com/caos/zitadel/pkg/grpc/instance"
|
||||||
|
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AddInstancePbToSetupInstance(req *system_pb.AddInstanceRequest, defaultInstance command.InstanceSetup) *command.InstanceSetup {
|
||||||
|
if req.InstanceName != "" {
|
||||||
|
defaultInstance.InstanceName = req.InstanceName
|
||||||
|
defaultInstance.Org.Name = req.InstanceName
|
||||||
|
}
|
||||||
|
if req.CustomDomain != "" {
|
||||||
|
defaultInstance.CustomDomain = req.CustomDomain
|
||||||
|
}
|
||||||
|
if req.FirstOrgName != "" {
|
||||||
|
defaultInstance.Org.Name = req.FirstOrgName
|
||||||
|
}
|
||||||
|
if req.OwnerEmail != "" {
|
||||||
|
defaultInstance.Org.Human.Email.Address = req.OwnerEmail
|
||||||
|
}
|
||||||
|
if req.OwnerUsername != "" {
|
||||||
|
defaultInstance.Org.Human.Username = req.OwnerUsername
|
||||||
|
}
|
||||||
|
if req.OwnerFirstName != "" {
|
||||||
|
defaultInstance.Org.Human.FirstName = req.OwnerFirstName
|
||||||
|
}
|
||||||
|
if req.OwnerLastName != "" {
|
||||||
|
defaultInstance.Org.Human.LastName = req.OwnerLastName
|
||||||
|
}
|
||||||
|
return &defaultInstance
|
||||||
|
}
|
||||||
|
func ListInstancesRequestToModel(req *system_pb.ListInstancesRequest) (*query.InstanceSearchQueries, error) {
|
||||||
|
offset, limit, asc := object.ListQueryToModel(req.Query)
|
||||||
|
queries, err := instance_grpc.InstanceQueriesToModel(req.Queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &query.InstanceSearchQueries{
|
||||||
|
SearchRequest: query.SearchRequest{
|
||||||
|
Offset: offset,
|
||||||
|
Limit: limit,
|
||||||
|
Asc: asc,
|
||||||
|
SortingColumn: fieldNameToInstanceColumn(req.SortingColumn),
|
||||||
|
},
|
||||||
|
Queries: queries,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fieldNameToInstanceColumn(fieldName instance_pb.FieldName) query.Column {
|
||||||
|
switch fieldName {
|
||||||
|
case instance_pb.FieldName_FIELD_NAME_ID:
|
||||||
|
return query.InstanceColumnID
|
||||||
|
case instance_pb.FieldName_FIELD_NAME_NAME:
|
||||||
|
return query.InstanceColumnName
|
||||||
|
case instance_pb.FieldName_FIELD_NAME_CREATION_DATE:
|
||||||
|
return query.InstanceColumnCreationDate
|
||||||
|
default:
|
||||||
|
return query.Column{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListInstanceDomainsRequestToModel(req *system_pb.ListDomainsRequest) (*query.InstanceDomainSearchQueries, error) {
|
||||||
|
offset, limit, asc := object.ListQueryToModel(req.Query)
|
||||||
|
queries, err := instance_grpc.DomainQueriesToModel(req.Queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &query.InstanceDomainSearchQueries{
|
||||||
|
SearchRequest: query.SearchRequest{
|
||||||
|
Offset: offset,
|
||||||
|
Limit: limit,
|
||||||
|
Asc: asc,
|
||||||
|
SortingColumn: fieldNameToInstanceDomainColumn(req.SortingColumn),
|
||||||
|
},
|
||||||
|
Queries: queries,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fieldNameToInstanceDomainColumn(fieldName instance_pb.DomainFieldName) query.Column {
|
||||||
|
switch fieldName {
|
||||||
|
case instance_pb.DomainFieldName_DOMAIN_FIELD_NAME_DOMAIN:
|
||||||
|
return query.InstanceDomainDomainCol
|
||||||
|
case instance_pb.DomainFieldName_DOMAIN_FIELD_NAME_GENERATED:
|
||||||
|
return query.InstanceDomainIsGeneratedCol
|
||||||
|
case instance_pb.DomainFieldName_DOMAIN_FIELD_NAME_PRIMARY:
|
||||||
|
return query.InstanceDomainIsPrimaryCol
|
||||||
|
case instance_pb.DomainFieldName_DOMAIN_FIELD_NAME_CREATION_DATE:
|
||||||
|
return query.InstanceDomainCreationDateCol
|
||||||
|
default:
|
||||||
|
return query.Column{}
|
||||||
|
}
|
||||||
|
}
|
75
internal/api/grpc/system/server.go
Normal file
75
internal/api/grpc/system/server.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/zitadel/internal/admin/repository"
|
||||||
|
http_util "github.com/caos/zitadel/internal/api/http"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/admin/repository/eventsourcing"
|
||||||
|
"github.com/caos/zitadel/internal/api/authz"
|
||||||
|
"github.com/caos/zitadel/internal/api/grpc/server"
|
||||||
|
"github.com/caos/zitadel/internal/command"
|
||||||
|
"github.com/caos/zitadel/internal/query"
|
||||||
|
"github.com/caos/zitadel/pkg/grpc/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
systemAPI = "System-API"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ system.SystemServiceServer = (*Server)(nil)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
system.UnimplementedSystemServiceServer
|
||||||
|
command *command.Commands
|
||||||
|
query *query.Queries
|
||||||
|
administrator repository.AdministratorRepository
|
||||||
|
DefaultInstance command.InstanceSetup
|
||||||
|
ExternalSecure bool
|
||||||
|
BaseURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Repository eventsourcing.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateServer(command *command.Commands,
|
||||||
|
query *query.Queries,
|
||||||
|
repo repository.Repository,
|
||||||
|
defaultInstance command.InstanceSetup,
|
||||||
|
externalPort uint16,
|
||||||
|
externalDomain string,
|
||||||
|
externalSecure bool) *Server {
|
||||||
|
return &Server{
|
||||||
|
command: command,
|
||||||
|
query: query,
|
||||||
|
administrator: repo,
|
||||||
|
DefaultInstance: defaultInstance,
|
||||||
|
ExternalSecure: externalSecure,
|
||||||
|
BaseURL: http_util.BuildHTTP(externalDomain, externalPort, externalSecure),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||||
|
system.RegisterSystemServiceServer(grpcServer, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) AppName() string {
|
||||||
|
return systemAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) MethodPrefix() string {
|
||||||
|
return system.SystemService_MethodPrefix
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||||
|
return system.SystemService_AuthMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) RegisterGateway() server.GatewayFunc {
|
||||||
|
return system.RegisterSystemServiceHandlerFromEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GatewayPathPrefix() string {
|
||||||
|
return "/system/v1"
|
||||||
|
}
|
37
internal/api/grpc/system/view.go
Normal file
37
internal/api/grpc/system/view.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/caos/zitadel/internal/query"
|
||||||
|
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) ListViews(ctx context.Context, _ *system_pb.ListViewsRequest) (*system_pb.ListViewsResponse, error) {
|
||||||
|
currentSequences, err := s.query.SearchCurrentSequences(ctx, new(query.CurrentSequencesSearchQueries))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
convertedCurrentSequences := CurrentSequencesToPb(currentSequences)
|
||||||
|
views, err := s.administrator.GetViews()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
convertedViews := ViewsToPb(views)
|
||||||
|
|
||||||
|
convertedCurrentSequences = append(convertedCurrentSequences, convertedViews...)
|
||||||
|
return &system_pb.ListViewsResponse{Result: convertedCurrentSequences}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ClearView(ctx context.Context, req *system_pb.ClearViewRequest) (*system_pb.ClearViewResponse, error) {
|
||||||
|
var err error
|
||||||
|
if req.Database != "zitadel" {
|
||||||
|
err = s.administrator.ClearView(ctx, req.Database, req.ViewName)
|
||||||
|
} else {
|
||||||
|
err = s.query.ClearCurrentSequence(ctx, req.ViewName)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &system_pb.ClearViewResponse{}, nil
|
||||||
|
}
|
43
internal/api/grpc/system/view_converter.go
Normal file
43
internal/api/grpc/system/view_converter.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/zitadel/internal/query"
|
||||||
|
"github.com/caos/zitadel/internal/view/model"
|
||||||
|
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ViewsToPb(views []*model.View) []*system_pb.View {
|
||||||
|
v := make([]*system_pb.View, len(views))
|
||||||
|
for i, view := range views {
|
||||||
|
v[i] = ViewToPb(view)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func ViewToPb(view *model.View) *system_pb.View {
|
||||||
|
return &system_pb.View{
|
||||||
|
Database: view.Database,
|
||||||
|
ViewName: view.ViewName,
|
||||||
|
LastSuccessfulSpoolerRun: timestamppb.New(view.LastSuccessfulSpoolerRun),
|
||||||
|
ProcessedSequence: view.CurrentSequence,
|
||||||
|
EventTimestamp: timestamppb.New(view.EventTimestamp),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CurrentSequencesToPb(currentSequences *query.CurrentSequences) []*system_pb.View {
|
||||||
|
v := make([]*system_pb.View, len(currentSequences.CurrentSequences))
|
||||||
|
for i, currentSequence := range currentSequences.CurrentSequences {
|
||||||
|
v[i] = CurrentSequenceToPb(currentSequence)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func CurrentSequenceToPb(currentSequence *query.CurrentSequence) *system_pb.View {
|
||||||
|
return &system_pb.View{
|
||||||
|
Database: "zitadel",
|
||||||
|
ViewName: currentSequence.ProjectionName,
|
||||||
|
ProcessedSequence: currentSequence.CurrentSequence,
|
||||||
|
EventTimestamp: timestamppb.New(currentSequence.Timestamp),
|
||||||
|
}
|
||||||
|
}
|
@ -28,10 +28,22 @@ const (
|
|||||||
consolePostLogoutPath = console.HandlerPrefix + "/signedout"
|
consolePostLogoutPath = console.HandlerPrefix + "/signedout"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type AddInstance struct {
|
||||||
|
InstanceName string
|
||||||
|
CustomDomain string
|
||||||
|
FirstOrgName string
|
||||||
|
OwnerEmail string
|
||||||
|
OwnerUsername string
|
||||||
|
OwnerFirstName string
|
||||||
|
OwnerLastName string
|
||||||
|
}
|
||||||
|
|
||||||
type InstanceSetup struct {
|
type InstanceSetup struct {
|
||||||
Org OrgSetup
|
zitadel ZitadelConfig
|
||||||
Zitadel ZitadelConfig
|
InstanceName string
|
||||||
Features struct {
|
CustomDomain string
|
||||||
|
Org OrgSetup
|
||||||
|
Features struct {
|
||||||
TierName string
|
TierName string
|
||||||
TierDescription string
|
TierDescription string
|
||||||
Retention time.Duration
|
Retention time.Duration
|
||||||
@ -120,9 +132,6 @@ type InstanceSetup struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ZitadelConfig struct {
|
type ZitadelConfig struct {
|
||||||
IsDevMode bool
|
|
||||||
BaseURL string
|
|
||||||
|
|
||||||
projectID string
|
projectID string
|
||||||
mgmtAppID string
|
mgmtAppID string
|
||||||
adminAppID string
|
adminAppID string
|
||||||
@ -131,41 +140,41 @@ type ZitadelConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *InstanceSetup) generateIDs() (err error) {
|
func (s *InstanceSetup) generateIDs() (err error) {
|
||||||
s.Zitadel.projectID, err = id.SonyFlakeGenerator.Next()
|
s.zitadel.projectID, err = id.SonyFlakeGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Zitadel.mgmtAppID, err = id.SonyFlakeGenerator.Next()
|
s.zitadel.mgmtAppID, err = id.SonyFlakeGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Zitadel.adminAppID, err = id.SonyFlakeGenerator.Next()
|
s.zitadel.adminAppID, err = id.SonyFlakeGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Zitadel.authAppID, err = id.SonyFlakeGenerator.Next()
|
s.zitadel.authAppID, err = id.SonyFlakeGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Zitadel.consoleAppID, err = id.SonyFlakeGenerator.Next()
|
s.zitadel.consoleAppID, err = id.SonyFlakeGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*domain.ObjectDetails, error) {
|
func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup, externalSecure bool, baseURL string) (string, *domain.ObjectDetails, error) {
|
||||||
instanceID, err := id.SonyFlakeGenerator.Next()
|
instanceID, err := id.SonyFlakeGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.eventstore.NewInstance(ctx, instanceID); err != nil {
|
if err = c.eventstore.NewInstance(ctx, instanceID); err != nil {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = authz.SetCtxData(authz.WithInstanceID(ctx, instanceID), authz.CtxData{OrgID: instanceID, ResourceOwner: instanceID})
|
ctx = authz.SetCtxData(authz.WithInstanceID(ctx, instanceID), authz.CtxData{OrgID: instanceID, ResourceOwner: instanceID})
|
||||||
@ -174,16 +183,16 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*do
|
|||||||
|
|
||||||
orgID, err := id.SonyFlakeGenerator.Next()
|
orgID, err := id.SonyFlakeGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
userID, err := id.SonyFlakeGenerator.Next()
|
userID, err := id.SonyFlakeGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = setup.generateIDs(); err != nil {
|
if err = setup.generateIDs(); err != nil {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
setup.Org.Human.PasswordChangeRequired = true
|
setup.Org.Human.PasswordChangeRequired = true
|
||||||
@ -191,9 +200,11 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*do
|
|||||||
instanceAgg := instance.NewAggregate(instanceID)
|
instanceAgg := instance.NewAggregate(instanceID)
|
||||||
orgAgg := org.NewAggregate(orgID)
|
orgAgg := org.NewAggregate(orgID)
|
||||||
userAgg := user.NewAggregate(userID, orgID)
|
userAgg := user.NewAggregate(userID, orgID)
|
||||||
projectAgg := project.NewAggregate(setup.Zitadel.projectID, orgID)
|
projectAgg := project.NewAggregate(setup.zitadel.projectID, orgID)
|
||||||
|
|
||||||
validations := []preparation.Validation{
|
validations := []preparation.Validation{
|
||||||
|
addInstance(instanceAgg, setup.InstanceName),
|
||||||
|
c.addGeneratedInstanceDomain(instanceAgg, setup.InstanceName),
|
||||||
SetDefaultFeatures(
|
SetDefaultFeatures(
|
||||||
instanceAgg,
|
instanceAgg,
|
||||||
setup.Features.TierName,
|
setup.Features.TierName,
|
||||||
@ -289,20 +300,24 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*do
|
|||||||
validations = append(validations, SetInstanceCustomTexts(instanceAgg, msg))
|
validations = append(validations, SetInstanceCustomTexts(instanceAgg, msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if setup.CustomDomain != "" {
|
||||||
|
validations = append(validations, c.addInstanceDomain(instanceAgg, setup.CustomDomain, false))
|
||||||
|
}
|
||||||
|
|
||||||
console := &addOIDCApp{
|
console := &addOIDCApp{
|
||||||
AddApp: AddApp{
|
AddApp: AddApp{
|
||||||
Aggregate: *projectAgg,
|
Aggregate: *projectAgg,
|
||||||
ID: setup.Zitadel.consoleAppID,
|
ID: setup.zitadel.consoleAppID,
|
||||||
Name: consoleAppName,
|
Name: consoleAppName,
|
||||||
},
|
},
|
||||||
Version: domain.OIDCVersionV1,
|
Version: domain.OIDCVersionV1,
|
||||||
RedirectUris: []string{setup.Zitadel.BaseURL + consoleRedirectPath},
|
RedirectUris: []string{baseURL + consoleRedirectPath},
|
||||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||||
ApplicationType: domain.OIDCApplicationTypeUserAgent,
|
ApplicationType: domain.OIDCApplicationTypeUserAgent,
|
||||||
AuthMethodType: domain.OIDCAuthMethodTypeNone,
|
AuthMethodType: domain.OIDCAuthMethodTypeNone,
|
||||||
PostLogoutRedirectUris: []string{setup.Zitadel.BaseURL + consolePostLogoutPath},
|
PostLogoutRedirectUris: []string{baseURL + consolePostLogoutPath},
|
||||||
DevMode: setup.Zitadel.IsDevMode,
|
DevMode: !externalSecure,
|
||||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||||
AccessTokenRoleAssertion: false,
|
AccessTokenRoleAssertion: false,
|
||||||
IDTokenRoleAssertion: false,
|
IDTokenRoleAssertion: false,
|
||||||
@ -323,7 +338,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*do
|
|||||||
&addAPIApp{
|
&addAPIApp{
|
||||||
AddApp: AddApp{
|
AddApp: AddApp{
|
||||||
Aggregate: *projectAgg,
|
Aggregate: *projectAgg,
|
||||||
ID: setup.Zitadel.mgmtAppID,
|
ID: setup.zitadel.mgmtAppID,
|
||||||
Name: mgmtAppName,
|
Name: mgmtAppName,
|
||||||
},
|
},
|
||||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
@ -335,7 +350,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*do
|
|||||||
&addAPIApp{
|
&addAPIApp{
|
||||||
AddApp: AddApp{
|
AddApp: AddApp{
|
||||||
Aggregate: *projectAgg,
|
Aggregate: *projectAgg,
|
||||||
ID: setup.Zitadel.adminAppID,
|
ID: setup.zitadel.adminAppID,
|
||||||
Name: adminAppName,
|
Name: adminAppName,
|
||||||
},
|
},
|
||||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
@ -347,7 +362,7 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*do
|
|||||||
&addAPIApp{
|
&addAPIApp{
|
||||||
AddApp: AddApp{
|
AddApp: AddApp{
|
||||||
Aggregate: *projectAgg,
|
Aggregate: *projectAgg,
|
||||||
ID: setup.Zitadel.authAppID,
|
ID: setup.zitadel.authAppID,
|
||||||
Name: authAppName,
|
Name: authAppName,
|
||||||
},
|
},
|
||||||
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
AuthMethodType: domain.APIAuthMethodTypePrivateKeyJWT,
|
||||||
@ -356,25 +371,35 @@ func (c *Commands) SetUpInstance(ctx context.Context, setup *InstanceSetup) (*do
|
|||||||
),
|
),
|
||||||
|
|
||||||
AddOIDCAppCommand(console, nil),
|
AddOIDCAppCommand(console, nil),
|
||||||
SetIAMConsoleID(instanceAgg, &console.ClientID, &setup.Zitadel.consoleAppID),
|
SetIAMConsoleID(instanceAgg, &console.ClientID, &setup.zitadel.consoleAppID),
|
||||||
)
|
)
|
||||||
|
|
||||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validations...)
|
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validations...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
events, err := c.eventstore.Push(ctx, cmds...)
|
events, err := c.eventstore.Push(ctx, cmds...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
return &domain.ObjectDetails{
|
return instanceID, &domain.ObjectDetails{
|
||||||
Sequence: events[len(events)-1].Sequence(),
|
Sequence: events[len(events)-1].Sequence(),
|
||||||
EventDate: events[len(events)-1].CreationDate(),
|
EventDate: events[len(events)-1].CreationDate(),
|
||||||
ResourceOwner: orgID,
|
ResourceOwner: orgID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addInstance(a *instance.Aggregate, instanceName string) preparation.Validation {
|
||||||
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
return []eventstore.Command{
|
||||||
|
instance.NewInstanceAddedEvent(ctx, &a.Aggregate, instanceName),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//SetIAMProject defines the command to set the id of the IAM project onto the instance
|
//SetIAMProject defines the command to set the id of the IAM project onto the instance
|
||||||
func SetIAMProject(a *instance.Aggregate, projectID string) preparation.Validation {
|
func SetIAMProject(a *instance.Aggregate, projectID string) preparation.Validation {
|
||||||
return func() (preparation.CreateCommands, error) {
|
return func() (preparation.CreateCommands, error) {
|
||||||
|
@ -67,6 +67,11 @@ func (c *Commands) RemoveInstanceDomain(ctx context.Context, instanceDomain stri
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Commands) addGeneratedInstanceDomain(a *instance.Aggregate, instanceName string) preparation.Validation {
|
||||||
|
domain := domain.NewGeneratedInstanceDomain(instanceName, c.iamDomain)
|
||||||
|
return c.addInstanceDomain(a, domain, true)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Commands) addInstanceDomain(a *instance.Aggregate, instanceDomain string, generated bool) preparation.Validation {
|
func (c *Commands) addInstanceDomain(a *instance.Aggregate, instanceDomain string, generated bool) preparation.Validation {
|
||||||
return func() (preparation.CreateCommands, error) {
|
return func() (preparation.CreateCommands, error) {
|
||||||
if instanceDomain = strings.TrimSpace(instanceDomain); instanceDomain == "" {
|
if instanceDomain = strings.TrimSpace(instanceDomain); instanceDomain == "" {
|
||||||
@ -80,28 +85,32 @@ func (c *Commands) addInstanceDomain(a *instance.Aggregate, instanceDomain strin
|
|||||||
if domainWriteModel.State == domain.InstanceDomainStateActive {
|
if domainWriteModel.State == domain.InstanceDomainStateActive {
|
||||||
return nil, errors.ThrowAlreadyExists(nil, "INST-i2nl", "Errors.Instance.Domain.AlreadyExists")
|
return nil, errors.ThrowAlreadyExists(nil, "INST-i2nl", "Errors.Instance.Domain.AlreadyExists")
|
||||||
}
|
}
|
||||||
|
events := []eventstore.Command{
|
||||||
|
instance.NewDomainAddedEvent(ctx, &a.Aggregate, instanceDomain, generated),
|
||||||
|
}
|
||||||
appWriteModel, err := c.getOIDCAppWriteModel(ctx, authz.GetInstance(ctx).ProjectID(), authz.GetInstance(ctx).ConsoleApplicationID(), "")
|
appWriteModel, err := c.getOIDCAppWriteModel(ctx, authz.GetInstance(ctx).ProjectID(), authz.GetInstance(ctx).ConsoleApplicationID(), "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
redirectUrls := append(appWriteModel.RedirectUris, instanceDomain+consoleRedirectPath)
|
if appWriteModel.State.Exists() {
|
||||||
logoutUrls := append(appWriteModel.PostLogoutRedirectUris, instanceDomain+consolePostLogoutPath)
|
redirectUrls := append(appWriteModel.RedirectUris, instanceDomain+consoleRedirectPath)
|
||||||
consoleChangeEvent, err := project.NewOIDCConfigChangedEvent(
|
logoutUrls := append(appWriteModel.PostLogoutRedirectUris, instanceDomain+consolePostLogoutPath)
|
||||||
ctx,
|
consoleChangeEvent, err := project.NewOIDCConfigChangedEvent(
|
||||||
ProjectAggregateFromWriteModel(&appWriteModel.WriteModel),
|
ctx,
|
||||||
appWriteModel.AppID,
|
ProjectAggregateFromWriteModel(&appWriteModel.WriteModel),
|
||||||
[]project.OIDCConfigChanges{
|
appWriteModel.AppID,
|
||||||
project.ChangeRedirectURIs(redirectUrls),
|
[]project.OIDCConfigChanges{
|
||||||
project.ChangePostLogoutRedirectURIs(logoutUrls),
|
project.ChangeRedirectURIs(redirectUrls),
|
||||||
},
|
project.ChangePostLogoutRedirectURIs(logoutUrls),
|
||||||
)
|
},
|
||||||
if err != nil {
|
)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
events = append(events, consoleChangeEvent)
|
||||||
}
|
}
|
||||||
return []eventstore.Command{
|
|
||||||
instance.NewDomainAddedEvent(ctx, &a.Aggregate, instanceDomain, generated),
|
return events, nil
|
||||||
consoleChangeEvent,
|
|
||||||
}, nil
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,7 +291,7 @@ func (c *Commands) VerifyOIDCClientSecret(ctx context.Context, projectID, appID,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !app.State.Exists() {
|
if !app.State.Exists() {
|
||||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.NoExisting")
|
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.NotExisting")
|
||||||
}
|
}
|
||||||
if !app.IsOIDC() {
|
if !app.IsOIDC() {
|
||||||
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-BHgn2", "Errors.Project.App.IsNotOIDC")
|
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-BHgn2", "Errors.Project.App.IsNotOIDC")
|
||||||
|
@ -23,5 +23,7 @@ func (f InstanceDomainState) Exists() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewGeneratedInstanceDomain(instanceName, iamDomain string) string {
|
func NewGeneratedInstanceDomain(instanceName, iamDomain string) string {
|
||||||
|
//TODO: Add random number/string to be unique
|
||||||
|
instanceName = strings.TrimSpace(instanceName)
|
||||||
return strings.ToLower(strings.ReplaceAll(instanceName, " ", "-") + "." + iamDomain)
|
return strings.ToLower(strings.ReplaceAll(instanceName, " ", "-") + "." + iamDomain)
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,12 @@ func Migrate(ctx context.Context, es *eventstore.Eventstore, migration Migration
|
|||||||
err = migration.Execute(ctx)
|
err = migration.Execute(ctx)
|
||||||
logging.OnError(err).Error("migration failed")
|
logging.OnError(err).Error("migration failed")
|
||||||
|
|
||||||
_, err = es.Push(ctx, setupDoneCmd(migration, err))
|
_, pushErr := es.Push(ctx, setupDoneCmd(migration, err))
|
||||||
return err
|
logging.OnError(pushErr).Error("migration failed")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return pushErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func shouldExec(ctx context.Context, es *eventstore.Eventstore, migration Migration) (should bool, err error) {
|
func shouldExec(ctx context.Context, es *eventstore.Eventstore, migration Migration) (should bool, err error) {
|
||||||
|
@ -23,6 +23,14 @@ var (
|
|||||||
name: projection.InstanceColumnID,
|
name: projection.InstanceColumnID,
|
||||||
table: instanceTable,
|
table: instanceTable,
|
||||||
}
|
}
|
||||||
|
InstanceColumnName = Column{
|
||||||
|
name: projection.InstanceColumnName,
|
||||||
|
table: instanceTable,
|
||||||
|
}
|
||||||
|
InstanceColumnCreationDate = Column{
|
||||||
|
name: projection.InstanceColumnCreationDate,
|
||||||
|
table: instanceTable,
|
||||||
|
}
|
||||||
InstanceColumnChangeDate = Column{
|
InstanceColumnChangeDate = Column{
|
||||||
name: projection.InstanceColumnChangeDate,
|
name: projection.InstanceColumnChangeDate,
|
||||||
table: instanceTable,
|
table: instanceTable,
|
||||||
@ -62,9 +70,10 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Instance struct {
|
type Instance struct {
|
||||||
ID string
|
ID string
|
||||||
ChangeDate time.Time
|
ChangeDate time.Time
|
||||||
Sequence uint64
|
CreationDate time.Time
|
||||||
|
Sequence uint64
|
||||||
|
|
||||||
GlobalOrgID string
|
GlobalOrgID string
|
||||||
IAMProjectID string
|
IAMProjectID string
|
||||||
@ -76,6 +85,11 @@ type Instance struct {
|
|||||||
Host string
|
Host string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Instances struct {
|
||||||
|
SearchResponse
|
||||||
|
Instances []*Instance
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Instance) InstanceID() string {
|
func (i *Instance) InstanceID() string {
|
||||||
return i.ID
|
return i.ID
|
||||||
}
|
}
|
||||||
@ -101,6 +115,14 @@ type InstanceSearchQueries struct {
|
|||||||
Queries []SearchQuery
|
Queries []SearchQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewInstanceIDsListSearchQuery(ids ...string) (SearchQuery, error) {
|
||||||
|
list := make([]interface{}, len(ids))
|
||||||
|
for i, value := range ids {
|
||||||
|
list[i] = value
|
||||||
|
}
|
||||||
|
return NewListQuery(InstanceColumnID, list, ListIn)
|
||||||
|
}
|
||||||
|
|
||||||
func (q *InstanceSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
func (q *InstanceSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||||
query = q.SearchRequest.toQuery(query)
|
query = q.SearchRequest.toQuery(query)
|
||||||
for _, q := range q.Queries {
|
for _, q := range q.Queries {
|
||||||
@ -109,6 +131,24 @@ func (q *InstanceSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder
|
|||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SearchInstances(ctx context.Context, queries *InstanceSearchQueries) (instances *Instances, err error) {
|
||||||
|
query, scan := prepareInstancesQuery()
|
||||||
|
stmt, args, err := queries.toQuery(query).ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ThrowInvalidArgument(err, "QUERY-M9fow", "Errors.Query.SQLStatement")
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := q.client.QueryContext(ctx, stmt, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ThrowInternal(err, "QUERY-3j98f", "Errors.Internal")
|
||||||
|
}
|
||||||
|
instances, err = scan(rows)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return instances, err
|
||||||
|
}
|
||||||
|
|
||||||
func (q *Queries) Instance(ctx context.Context) (*Instance, error) {
|
func (q *Queries) Instance(ctx context.Context) (*Instance, error) {
|
||||||
stmt, scan := prepareInstanceQuery(authz.GetInstance(ctx).RequestedDomain())
|
stmt, scan := prepareInstanceQuery(authz.GetInstance(ctx).RequestedDomain())
|
||||||
query, args, err := stmt.Where(sq.Eq{
|
query, args, err := stmt.Where(sq.Eq{
|
||||||
@ -146,6 +186,7 @@ func (q *Queries) GetDefaultLanguage(ctx context.Context) language.Tag {
|
|||||||
func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Instance, error)) {
|
func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Instance, error)) {
|
||||||
return sq.Select(
|
return sq.Select(
|
||||||
InstanceColumnID.identifier(),
|
InstanceColumnID.identifier(),
|
||||||
|
InstanceColumnCreationDate.identifier(),
|
||||||
InstanceColumnChangeDate.identifier(),
|
InstanceColumnChangeDate.identifier(),
|
||||||
InstanceColumnSequence.identifier(),
|
InstanceColumnSequence.identifier(),
|
||||||
InstanceColumnGlobalOrgID.identifier(),
|
InstanceColumnGlobalOrgID.identifier(),
|
||||||
@ -162,6 +203,7 @@ func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Insta
|
|||||||
lang := ""
|
lang := ""
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&instance.ID,
|
&instance.ID,
|
||||||
|
&instance.CreationDate,
|
||||||
&instance.ChangeDate,
|
&instance.ChangeDate,
|
||||||
&instance.Sequence,
|
&instance.Sequence,
|
||||||
&instance.GlobalOrgID,
|
&instance.GlobalOrgID,
|
||||||
@ -182,3 +224,58 @@ func prepareInstanceQuery(host string) (sq.SelectBuilder, func(*sql.Row) (*Insta
|
|||||||
return instance, nil
|
return instance, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prepareInstancesQuery() (sq.SelectBuilder, func(*sql.Rows) (*Instances, error)) {
|
||||||
|
return sq.Select(
|
||||||
|
InstanceColumnID.identifier(),
|
||||||
|
InstanceColumnCreationDate.identifier(),
|
||||||
|
InstanceColumnChangeDate.identifier(),
|
||||||
|
InstanceColumnSequence.identifier(),
|
||||||
|
InstanceColumnGlobalOrgID.identifier(),
|
||||||
|
InstanceColumnProjectID.identifier(),
|
||||||
|
InstanceColumnConsoleID.identifier(),
|
||||||
|
InstanceColumnConsoleAppID.identifier(),
|
||||||
|
InstanceColumnSetupStarted.identifier(),
|
||||||
|
InstanceColumnSetupDone.identifier(),
|
||||||
|
InstanceColumnDefaultLanguage.identifier(),
|
||||||
|
countColumn.identifier(),
|
||||||
|
).From(instanceTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||||
|
func(rows *sql.Rows) (*Instances, error) {
|
||||||
|
instances := make([]*Instance, 0)
|
||||||
|
var count uint64
|
||||||
|
for rows.Next() {
|
||||||
|
instance := new(Instance)
|
||||||
|
lang := ""
|
||||||
|
//TODO: Get Host
|
||||||
|
err := rows.Scan(
|
||||||
|
&instance.ID,
|
||||||
|
&instance.CreationDate,
|
||||||
|
&instance.ChangeDate,
|
||||||
|
&instance.Sequence,
|
||||||
|
&instance.GlobalOrgID,
|
||||||
|
&instance.IAMProjectID,
|
||||||
|
&instance.ConsoleID,
|
||||||
|
&instance.ConsoleAppID,
|
||||||
|
&instance.SetupStarted,
|
||||||
|
&instance.SetupDone,
|
||||||
|
&lang,
|
||||||
|
&count,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
instances = append(instances, instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rows.Close(); err != nil {
|
||||||
|
return nil, errors.ThrowInternal(err, "QUERY-8nlWW", "Errors.Query.CloseRows")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Instances{
|
||||||
|
Instances: instances,
|
||||||
|
SearchResponse: SearchResponse{
|
||||||
|
Count: count,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -34,6 +34,7 @@ func Test_InstancePrepares(t *testing.T) {
|
|||||||
want: want{
|
want: want{
|
||||||
sqlExpectations: mockQueries(
|
sqlExpectations: mockQueries(
|
||||||
regexp.QuoteMeta(`SELECT projections.instances.id,`+
|
regexp.QuoteMeta(`SELECT projections.instances.id,`+
|
||||||
|
` projections.instances.creation_date,`+
|
||||||
` projections.instances.change_date,`+
|
` projections.instances.change_date,`+
|
||||||
` projections.instances.sequence,`+
|
` projections.instances.sequence,`+
|
||||||
` projections.instances.global_org_id,`+
|
` projections.instances.global_org_id,`+
|
||||||
@ -64,6 +65,7 @@ func Test_InstancePrepares(t *testing.T) {
|
|||||||
want: want{
|
want: want{
|
||||||
sqlExpectations: mockQuery(
|
sqlExpectations: mockQuery(
|
||||||
regexp.QuoteMeta(`SELECT projections.instances.id,`+
|
regexp.QuoteMeta(`SELECT projections.instances.id,`+
|
||||||
|
` projections.instances.creation_date,`+
|
||||||
` projections.instances.change_date,`+
|
` projections.instances.change_date,`+
|
||||||
` projections.instances.sequence,`+
|
` projections.instances.sequence,`+
|
||||||
` projections.instances.global_org_id,`+
|
` projections.instances.global_org_id,`+
|
||||||
@ -76,6 +78,7 @@ func Test_InstancePrepares(t *testing.T) {
|
|||||||
` FROM projections.instances`),
|
` FROM projections.instances`),
|
||||||
[]string{
|
[]string{
|
||||||
"id",
|
"id",
|
||||||
|
"creation_date",
|
||||||
"change_date",
|
"change_date",
|
||||||
"sequence",
|
"sequence",
|
||||||
"global_org_id",
|
"global_org_id",
|
||||||
@ -89,6 +92,7 @@ func Test_InstancePrepares(t *testing.T) {
|
|||||||
[]driver.Value{
|
[]driver.Value{
|
||||||
"id",
|
"id",
|
||||||
testNow,
|
testNow,
|
||||||
|
testNow,
|
||||||
uint64(20211108),
|
uint64(20211108),
|
||||||
"global-org-id",
|
"global-org-id",
|
||||||
"project-id",
|
"project-id",
|
||||||
@ -102,6 +106,7 @@ func Test_InstancePrepares(t *testing.T) {
|
|||||||
},
|
},
|
||||||
object: &Instance{
|
object: &Instance{
|
||||||
ID: "id",
|
ID: "id",
|
||||||
|
CreationDate: testNow,
|
||||||
ChangeDate: testNow,
|
ChangeDate: testNow,
|
||||||
Sequence: 20211108,
|
Sequence: 20211108,
|
||||||
GlobalOrgID: "global-org-id",
|
GlobalOrgID: "global-org-id",
|
||||||
@ -121,6 +126,7 @@ func Test_InstancePrepares(t *testing.T) {
|
|||||||
want: want{
|
want: want{
|
||||||
sqlExpectations: mockQueryErr(
|
sqlExpectations: mockQueryErr(
|
||||||
regexp.QuoteMeta(`SELECT projections.instances.id,`+
|
regexp.QuoteMeta(`SELECT projections.instances.id,`+
|
||||||
|
` projections.instances.creation_date,`+
|
||||||
` projections.instances.change_date,`+
|
` projections.instances.change_date,`+
|
||||||
` projections.instances.sequence,`+
|
` projections.instances.sequence,`+
|
||||||
` projections.instances.global_org_id,`+
|
` projections.instances.global_org_id,`+
|
||||||
|
@ -14,7 +14,9 @@ const (
|
|||||||
InstanceProjectionTable = "projections.instances"
|
InstanceProjectionTable = "projections.instances"
|
||||||
|
|
||||||
InstanceColumnID = "id"
|
InstanceColumnID = "id"
|
||||||
|
InstanceColumnName = "name"
|
||||||
InstanceColumnChangeDate = "change_date"
|
InstanceColumnChangeDate = "change_date"
|
||||||
|
InstanceColumnCreationDate = "creation_date"
|
||||||
InstanceColumnGlobalOrgID = "global_org_id"
|
InstanceColumnGlobalOrgID = "global_org_id"
|
||||||
InstanceColumnProjectID = "iam_project_id"
|
InstanceColumnProjectID = "iam_project_id"
|
||||||
InstanceColumnConsoleID = "console_client_id"
|
InstanceColumnConsoleID = "console_client_id"
|
||||||
@ -36,10 +38,13 @@ func NewInstanceProjection(ctx context.Context, config crdb.StatementHandlerConf
|
|||||||
config.InitCheck = crdb.NewTableCheck(
|
config.InitCheck = crdb.NewTableCheck(
|
||||||
crdb.NewTable([]*crdb.Column{
|
crdb.NewTable([]*crdb.Column{
|
||||||
crdb.NewColumn(InstanceColumnID, crdb.ColumnTypeText),
|
crdb.NewColumn(InstanceColumnID, crdb.ColumnTypeText),
|
||||||
|
crdb.NewColumn(InstanceColumnName, crdb.ColumnTypeText, crdb.Default("")),
|
||||||
crdb.NewColumn(InstanceColumnChangeDate, crdb.ColumnTypeTimestamp),
|
crdb.NewColumn(InstanceColumnChangeDate, crdb.ColumnTypeTimestamp),
|
||||||
|
crdb.NewColumn(InstanceColumnCreationDate, crdb.ColumnTypeTimestamp),
|
||||||
crdb.NewColumn(InstanceColumnGlobalOrgID, crdb.ColumnTypeText, crdb.Default("")),
|
crdb.NewColumn(InstanceColumnGlobalOrgID, crdb.ColumnTypeText, crdb.Default("")),
|
||||||
crdb.NewColumn(InstanceColumnProjectID, crdb.ColumnTypeText, crdb.Default("")),
|
crdb.NewColumn(InstanceColumnProjectID, crdb.ColumnTypeText, crdb.Default("")),
|
||||||
crdb.NewColumn(InstanceColumnConsoleID, crdb.ColumnTypeText, crdb.Default("")),
|
crdb.NewColumn(InstanceColumnConsoleID, crdb.ColumnTypeText, crdb.Default("")),
|
||||||
|
crdb.NewColumn(InstanceColumnConsoleAppID, crdb.ColumnTypeText, crdb.Default("")),
|
||||||
crdb.NewColumn(InstanceColumnSequence, crdb.ColumnTypeInt64),
|
crdb.NewColumn(InstanceColumnSequence, crdb.ColumnTypeInt64),
|
||||||
crdb.NewColumn(InstanceColumnSetUpStarted, crdb.ColumnTypeInt64, crdb.Default(0)),
|
crdb.NewColumn(InstanceColumnSetUpStarted, crdb.ColumnTypeInt64, crdb.Default(0)),
|
||||||
crdb.NewColumn(InstanceColumnSetUpDone, crdb.ColumnTypeInt64, crdb.Default(0)),
|
crdb.NewColumn(InstanceColumnSetUpDone, crdb.ColumnTypeInt64, crdb.Default(0)),
|
||||||
@ -57,6 +62,10 @@ func (p *InstanceProjection) reducers() []handler.AggregateReducer {
|
|||||||
{
|
{
|
||||||
Aggregate: instance.AggregateType,
|
Aggregate: instance.AggregateType,
|
||||||
EventRedusers: []handler.EventReducer{
|
EventRedusers: []handler.EventReducer{
|
||||||
|
{
|
||||||
|
Event: instance.InstanceAddedEventType,
|
||||||
|
Reduce: p.reduceInstanceAdded,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Event: instance.GlobalOrgSetEventType,
|
Event: instance.GlobalOrgSetEventType,
|
||||||
Reduce: p.reduceGlobalOrgSet,
|
Reduce: p.reduceGlobalOrgSet,
|
||||||
@ -86,19 +95,38 @@ func (p *InstanceProjection) reducers() []handler.AggregateReducer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *InstanceProjection) reduceInstanceAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, ok := event.(*instance.InstanceAddedEvent)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-29nlS", "reduce.wrong.event.type %s", instance.InstanceAddedEventType)
|
||||||
|
}
|
||||||
|
return crdb.NewCreateStatement(
|
||||||
|
e,
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(InstanceColumnID, e.Aggregate().InstanceID),
|
||||||
|
handler.NewCol(InstanceColumnCreationDate, e.CreationDate()),
|
||||||
|
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
|
||||||
|
handler.NewCol(InstanceColumnSequence, e.Sequence()),
|
||||||
|
handler.NewCol(InstanceColumnName, e.Name),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *InstanceProjection) reduceGlobalOrgSet(event eventstore.Event) (*handler.Statement, error) {
|
func (p *InstanceProjection) reduceGlobalOrgSet(event eventstore.Event) (*handler.Statement, error) {
|
||||||
e, ok := event.(*instance.GlobalOrgSetEvent)
|
e, ok := event.(*instance.GlobalOrgSetEvent)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-2n9f2", "reduce.wrong.event.type %s", instance.GlobalOrgSetEventType)
|
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-2n9f2", "reduce.wrong.event.type %s", instance.GlobalOrgSetEventType)
|
||||||
}
|
}
|
||||||
return crdb.NewUpsertStatement(
|
return crdb.NewUpdateStatement(
|
||||||
e,
|
e,
|
||||||
[]handler.Column{
|
[]handler.Column{
|
||||||
handler.NewCol(InstanceColumnID, e.Aggregate().InstanceID),
|
|
||||||
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
|
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
|
||||||
handler.NewCol(InstanceColumnSequence, e.Sequence()),
|
handler.NewCol(InstanceColumnSequence, e.Sequence()),
|
||||||
handler.NewCol(InstanceColumnGlobalOrgID, e.OrgID),
|
handler.NewCol(InstanceColumnGlobalOrgID, e.OrgID),
|
||||||
},
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(InstanceColumnID, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,14 +135,16 @@ func (p *InstanceProjection) reduceIAMProjectSet(event eventstore.Event) (*handl
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-30o0e", "reduce.wrong.event.type %s", instance.ProjectSetEventType)
|
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-30o0e", "reduce.wrong.event.type %s", instance.ProjectSetEventType)
|
||||||
}
|
}
|
||||||
return crdb.NewUpsertStatement(
|
return crdb.NewUpdateStatement(
|
||||||
e,
|
e,
|
||||||
[]handler.Column{
|
[]handler.Column{
|
||||||
handler.NewCol(InstanceColumnID, e.Aggregate().InstanceID),
|
|
||||||
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
|
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
|
||||||
handler.NewCol(InstanceColumnSequence, e.Sequence()),
|
handler.NewCol(InstanceColumnSequence, e.Sequence()),
|
||||||
handler.NewCol(InstanceColumnProjectID, e.ProjectID),
|
handler.NewCol(InstanceColumnProjectID, e.ProjectID),
|
||||||
},
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(InstanceColumnID, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,15 +153,17 @@ func (p *InstanceProjection) reduceConsoleSet(event eventstore.Event) (*handler.
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Dgf11", "reduce.wrong.event.type %s", instance.ConsoleSetEventType)
|
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-Dgf11", "reduce.wrong.event.type %s", instance.ConsoleSetEventType)
|
||||||
}
|
}
|
||||||
return crdb.NewUpsertStatement(
|
return crdb.NewUpdateStatement(
|
||||||
e,
|
e,
|
||||||
[]handler.Column{
|
[]handler.Column{
|
||||||
handler.NewCol(InstanceColumnID, e.Aggregate().InstanceID),
|
|
||||||
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
|
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
|
||||||
handler.NewCol(InstanceColumnSequence, e.Sequence()),
|
handler.NewCol(InstanceColumnSequence, e.Sequence()),
|
||||||
handler.NewCol(InstanceColumnConsoleID, e.ClientID),
|
handler.NewCol(InstanceColumnConsoleID, e.ClientID),
|
||||||
handler.NewCol(InstanceColumnConsoleAppID, e.AppID),
|
handler.NewCol(InstanceColumnConsoleAppID, e.AppID),
|
||||||
},
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(InstanceColumnID, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,14 +172,16 @@ func (p *InstanceProjection) reduceDefaultLanguageSet(event eventstore.Event) (*
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-30o0e", "reduce.wrong.event.type %s", instance.DefaultLanguageSetEventType)
|
return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-30o0e", "reduce.wrong.event.type %s", instance.DefaultLanguageSetEventType)
|
||||||
}
|
}
|
||||||
return crdb.NewUpsertStatement(
|
return crdb.NewUpdateStatement(
|
||||||
e,
|
e,
|
||||||
[]handler.Column{
|
[]handler.Column{
|
||||||
handler.NewCol(InstanceColumnID, e.Aggregate().InstanceID),
|
|
||||||
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
|
handler.NewCol(InstanceColumnChangeDate, e.CreationDate()),
|
||||||
handler.NewCol(InstanceColumnSequence, e.Sequence()),
|
handler.NewCol(InstanceColumnSequence, e.Sequence()),
|
||||||
handler.NewCol(InstanceColumnDefaultLanguage, e.Language.String()),
|
handler.NewCol(InstanceColumnDefaultLanguage, e.Language.String()),
|
||||||
},
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(InstanceColumnID, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ func (p *InstanceDomainProjection) reducers() []handler.AggregateReducer {
|
|||||||
Reduce: p.reduceDomainAdded,
|
Reduce: p.reduceDomainAdded,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Event: instance.InstanceDomainAddedEventType,
|
Event: instance.InstanceDomainPrimarySetEventType,
|
||||||
Reduce: p.reduceDomainPrimarySet,
|
Reduce: p.reduceDomainPrimarySet,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -20,7 +20,37 @@ func TestInstanceProjection_reduces(t *testing.T) {
|
|||||||
args args
|
args args
|
||||||
reduce func(event eventstore.Event) (*handler.Statement, error)
|
reduce func(event eventstore.Event) (*handler.Statement, error)
|
||||||
want wantReduce
|
want wantReduce
|
||||||
}{
|
}{{
|
||||||
|
name: "reduceInstanceAdded",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(testEvent(
|
||||||
|
repository.EventType(instance.InstanceAddedEventType),
|
||||||
|
instance.AggregateType,
|
||||||
|
[]byte(`{"name": "Name"}`),
|
||||||
|
), instance.InstanceAddedEventMapper),
|
||||||
|
},
|
||||||
|
reduce: (&InstanceProjection{}).reduceInstanceAdded,
|
||||||
|
want: wantReduce{
|
||||||
|
projection: InstanceProjectionTable,
|
||||||
|
aggregateType: eventstore.AggregateType("instance"),
|
||||||
|
sequence: 15,
|
||||||
|
previousSequence: 10,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "INSERT INTO projections.instances (id, creation_date, change_date, sequence, name) VALUES ($1, $2, $3, $4, $5)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"instance-id",
|
||||||
|
anyArg{},
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"Name",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "reduceGlobalOrgSet",
|
name: "reduceGlobalOrgSet",
|
||||||
args: args{
|
args: args{
|
||||||
@ -39,12 +69,12 @@ func TestInstanceProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPSERT INTO projections.instances (id, change_date, sequence, global_org_id) VALUES ($1, $2, $3, $4)",
|
expectedStmt: "UPDATE projections.instances SET (change_date, sequence, global_org_id) = ($1, $2, $3) WHERE (id = $4)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"instance-id",
|
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
"orgid",
|
"orgid",
|
||||||
|
"instance-id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -69,12 +99,12 @@ func TestInstanceProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPSERT INTO projections.instances (id, change_date, sequence, iam_project_id) VALUES ($1, $2, $3, $4)",
|
expectedStmt: "UPDATE projections.instances SET (change_date, sequence, iam_project_id) = ($1, $2, $3) WHERE (id = $4)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"instance-id",
|
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
"project-id",
|
"project-id",
|
||||||
|
"instance-id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -99,12 +129,12 @@ func TestInstanceProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPSERT INTO projections.instances (id, change_date, sequence, default_language) VALUES ($1, $2, $3, $4)",
|
expectedStmt: "UPDATE projections.instances SET (change_date, sequence, default_language) = ($1, $2, $3) WHERE (id = $4)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"instance-id",
|
|
||||||
anyArg{},
|
anyArg{},
|
||||||
uint64(15),
|
uint64(15),
|
||||||
"en",
|
"en",
|
||||||
|
"instance-id",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -96,7 +96,7 @@ func NewDomainPrimarySetEvent(ctx context.Context, aggregate *eventstore.Aggrega
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DomainPrimarySetEventMapper(event *repository.Event) (eventstore.Event, error) {
|
func DomainPrimarySetEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||||
orgDomainAdded := &DomainAddedEvent{
|
orgDomainAdded := &DomainPrimarySetEvent{
|
||||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||||
}
|
}
|
||||||
err := json.Unmarshal(event.Data, orgDomainAdded)
|
err := json.Unmarshal(event.Data, orgDomainAdded)
|
||||||
|
@ -2525,34 +2525,6 @@ service AdminService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//Truncates the delta of the change stream
|
|
||||||
// be carefull with this function because ZITADEL has to
|
|
||||||
// recompute the deltas after they got cleared.
|
|
||||||
// Search requests will return wrong results until all deltas are recomputed
|
|
||||||
rpc ClearView(ClearViewRequest) returns (ClearViewResponse) {
|
|
||||||
option (google.api.http) = {
|
|
||||||
post: "/views/{database}/{view_name}";
|
|
||||||
};
|
|
||||||
|
|
||||||
option (zitadel.v1.auth_option) = {
|
|
||||||
permission: "iam.write";
|
|
||||||
};
|
|
||||||
|
|
||||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
|
||||||
tags: "views";
|
|
||||||
external_docs: {
|
|
||||||
url: "https://docs.zitadel.ch/concepts#Software_Architecture";
|
|
||||||
description: "details of ZITADEL's event driven software concepts";
|
|
||||||
};
|
|
||||||
responses: {
|
|
||||||
key: "200";
|
|
||||||
value: {
|
|
||||||
description: "View cleared";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//Returns event descriptions which cannot be processed.
|
//Returns event descriptions which cannot be processed.
|
||||||
// It's possible that some events need some retries.
|
// It's possible that some events need some retries.
|
||||||
// For example if the SMTP-API wasn't able to send an email at the first time
|
// For example if the SMTP-API wasn't able to send an email at the first time
|
||||||
@ -2582,7 +2554,7 @@ service AdminService {
|
|||||||
|
|
||||||
//Deletes the event from failed events view.
|
//Deletes the event from failed events view.
|
||||||
// the event is not removed from the change stream
|
// the event is not removed from the change stream
|
||||||
// This call is usefull if the system was able to process the event later.
|
// This call is usefull if the system was able to process the event later.
|
||||||
// e.g. if the second try of sending an email was successful. the first try produced a
|
// e.g. if the second try of sending an email was successful. the first try produced a
|
||||||
// failed event. You can find out if it worked on the `failure_count`
|
// failed event. You can find out if it worked on the `failure_count`
|
||||||
rpc RemoveFailedEvent(RemoveFailedEventRequest) returns (RemoveFailedEventResponse) {
|
rpc RemoveFailedEvent(RemoveFailedEventRequest) returns (RemoveFailedEventResponse) {
|
||||||
@ -4512,34 +4484,6 @@ message ListViewsResponse {
|
|||||||
repeated View result = 1;
|
repeated View result = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ClearViewRequest {
|
|
||||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
|
|
||||||
json_schema: {
|
|
||||||
required: ["database", "view_name"]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
string database = 1 [
|
|
||||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
|
||||||
example: "\"adminapi\"";
|
|
||||||
min_length: 1;
|
|
||||||
max_length: 200;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
string view_name = 2 [
|
|
||||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
|
||||||
example: "\"iam_members\"";
|
|
||||||
min_length: 1;
|
|
||||||
max_length: 200;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
//This is an empty response
|
|
||||||
message ClearViewResponse {}
|
|
||||||
|
|
||||||
//This is an empty request
|
//This is an empty request
|
||||||
message ListFailedEventsRequest {}
|
message ListFailedEventsRequest {}
|
||||||
|
|
||||||
|
@ -25,11 +25,6 @@ message Instance {
|
|||||||
example: "\"ZITADEL\"";
|
example: "\"ZITADEL\"";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
string version = 5 [
|
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
|
||||||
example: "\"v1.0.0\"";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
@ -44,31 +39,19 @@ message Query {
|
|||||||
oneof query {
|
oneof query {
|
||||||
option (validate.required) = true;
|
option (validate.required) = true;
|
||||||
|
|
||||||
IdQuery id_query = 1;
|
IdsQuery id_query = 1;
|
||||||
StateQuery state_query = 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//IdQuery is always equals
|
//IdQuery is always equals
|
||||||
message IdQuery {
|
message IdsQuery {
|
||||||
string id = 1 [
|
repeated string ids = 1 [
|
||||||
(validate.rules).string = {max_len: 200},
|
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
description: "4820840938402429";
|
description: "4820840938402429";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
//StateQuery is always equals
|
|
||||||
message StateQuery {
|
|
||||||
State state = 1 [
|
|
||||||
(validate.rules).enum.defined_only = true,
|
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
|
||||||
description: "current state of the instance";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
enum FieldName {
|
enum FieldName {
|
||||||
FIELD_NAME_UNSPECIFIED = 0;
|
FIELD_NAME_UNSPECIFIED = 0;
|
||||||
FIELD_NAME_ID = 1;
|
FIELD_NAME_ID = 1;
|
||||||
|
@ -105,7 +105,7 @@ service SystemService {
|
|||||||
// Returns a list of ZITADEL instances/tenants
|
// Returns a list of ZITADEL instances/tenants
|
||||||
rpc ListInstances(ListInstancesRequest) returns (ListInstancesResponse) {
|
rpc ListInstances(ListInstancesRequest) returns (ListInstancesResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/instances"
|
post: "/instances/_search"
|
||||||
body: "*"
|
body: "*"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -134,17 +134,11 @@ service SystemService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the usage metrics of an instance
|
|
||||||
rpc GetUsage(GetUsageRequest) returns (GetUsageResponse) {
|
|
||||||
option (google.api.http) = {
|
|
||||||
get: "/instances/{id}/usage";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the custom domains of an instance
|
// Returns the custom domains of an instance
|
||||||
rpc ListDomains(ListDomainsRequest) returns (ListDomainsResponse) {
|
rpc ListDomains(ListDomainsRequest) returns (ListDomainsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get: "/instances/{id}/domains";
|
post: "/instances/{id}/domains/_search";
|
||||||
|
body: "*"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,6 +172,7 @@ service SystemService {
|
|||||||
rpc ListViews(ListViewsRequest) returns (ListViewsResponse) {
|
rpc ListViews(ListViewsRequest) returns (ListViewsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/views/_search";
|
post: "/views/_search";
|
||||||
|
body: "*"
|
||||||
};
|
};
|
||||||
|
|
||||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
@ -229,6 +224,7 @@ service SystemService {
|
|||||||
rpc ListFailedEvents(ListFailedEventsRequest) returns (ListFailedEventsResponse) {
|
rpc ListFailedEvents(ListFailedEventsRequest) returns (ListFailedEventsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/failedevents/_search";
|
post: "/failedevents/_search";
|
||||||
|
body: "*"
|
||||||
};
|
};
|
||||||
|
|
||||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
@ -322,19 +318,19 @@ message GetInstanceResponse {
|
|||||||
|
|
||||||
message AddInstanceRequest {
|
message AddInstanceRequest {
|
||||||
string instance_name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string instance_name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
string first_org_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string first_org_name = 2 [(validate.rules).string = {max_len: 200}];
|
||||||
string custom_domain = 3 [(validate.rules).string = {max_len: 200}];
|
string custom_domain = 3 [(validate.rules).string = {max_len: 200}];
|
||||||
string owner_first_name = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string owner_first_name = 4 [(validate.rules).string = {max_len: 200}];
|
||||||
string owner_last_name = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string owner_last_name = 5 [(validate.rules).string = {max_len: 200}];
|
||||||
string owner_email = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string owner_email = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||||
string owner_username = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
string owner_username = 7 [(validate.rules).string = {max_len: 200}];
|
||||||
string password = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
uint64 request_limit = 8;
|
||||||
uint64 request_limit = 9;
|
uint64 action_mins_limit = 9;
|
||||||
uint64 action_mins_limit = 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message AddInstanceResponse {
|
message AddInstanceResponse {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
|
zitadel.v1.ObjectDetails details = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RemoveInstanceRequest {
|
message RemoveInstanceRequest {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user