feat: org command sides (#96)

* start org

* refactor(eventstore): filter in sql for querier

* feat(eventstore): Aggregate precondition

preconditions are checked right before insert. Insert is still transaction save

* feat(eventstore): check preconditions in repository

* test(eventstore): test precondition in models

* test(eventstore): precondition-tests

* start org

* refactor(eventstore): filter in sql for querier

* feat(eventstore): Aggregate precondition

preconditions are checked right before insert. Insert is still transaction save

* feat(admin): start implement org

* feat(eventstore): check preconditions in repository

* fix(eventstore): data as NULL if empty
refactor(eventstore): naming in sequence methods

* feat(admin): org command side

* feat(management): start org-repo

* feat(org): member

* fix: replace ObjectRoot.ID with ObjectRoot.AggregateID

* aggregateID

* add remove,change member

* refactor(org): namings

* refactor(eventstore): querier as type

* fix(precondition): rename validation from precondition to validation

* test(eventstore): isErr func instead of wantErr bool

* fix(tests): Data

* fix(eventstore): correct check for existing events in push,
simplify insert statement

* fix(eventstore): aggregate id public

* test(org): eventsourcing

* test(org): eventstore

* test(org): deactivate, reactivate, orgbyid

* test(org): getMemberByIDs

* tests

* running tests

* add user repo to admin

* thorw not found if no org found

* eventstore tests done

* lauft

* validate if user is already member of org

* modules

* delete unused file

* add member validation test

* return error if unable to validat member

* generate org id once,
set resourceowner of org

* Update internal/admin/repository/eventsourcing/eventstore/org.go

* Update internal/admin/repository/eventsourcing/eventstore/org.go

* Update internal/org/repository/eventsourcing/member_model.go

* Update internal/org/repository/eventsourcing/org.go

* Update internal/org/repository/eventsourcing/org.go

* Update internal/org/repository/eventsourcing/org_member.go

* Update internal/org/repository/eventsourcing/org_member.go

* Update internal/org/repository/eventsourcing/org_model.go

* Update internal/org/repository/eventsourcing/org.go

* Update internal/org/repository/eventsourcing/org_model.go

* Update internal/org/repository/eventsourcing/org_model.go

* typo

* correct user events

* usercreate for setuporg instead of userregister

* set data

* mod

* mod

* tests

* cleanup code

* code styling

* return member on add and change

* change username in startup

* girignore

* orgID as parameter in re-/deactive org

* startup config

* migration for admin_api-user

* probes fro admin

* move unique org

Co-authored-by: Fabiennne <fabienne.gerschwiler@gmail.com>
This commit is contained in:
Silvan 2020-05-13 14:22:29 +02:00 committed by GitHub
parent 7facd78026
commit 9e32740eb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 16694 additions and 13035 deletions

6
.gitignore vendored
View File

@ -25,5 +25,9 @@ debug
# credential
google-credentials
key.json
.keys/*
cockroach-data/*
cockroach-data/*
#binaries
cmd/zitadel/zitadel

View File

@ -56,7 +56,7 @@ func main() {
logging.Log("MAIN-53RF2").OnError(err).Fatal("error starting login ui")
}
if *adminEnabled {
admin.Start(ctx, conf.Admin, conf.AuthZ)
admin.Start(ctx, conf.Admin, conf.AuthZ, conf.SystemDefaults)
}
if *consoleEnabled {
err = console.Start(ctx, conf.Console)

View File

@ -26,7 +26,7 @@ Mgmt:
Host: $ZITADEL_EVENTSTORE_HOST
Port: $ZITADEL_EVENTSTORE_PORT
User: 'management'
Database: 'management'
Database: 'eventstore'
SSLmode: disable
Cache:
Type: 'fastcache'
@ -61,6 +61,20 @@ Admin:
GatewayPort: 50041
CustomHeaders:
- x-zitadel-
Repository:
Eventstore:
ServiceName: 'Admin'
Repository:
SQL:
Host: $ZITADEL_EVENTSTORE_HOST
Port: $ZITADEL_EVENTSTORE_PORT
User: 'admin_api'
Database: 'eventstore'
SSLmode: disable
Cache:
Type: 'fastcache'
Config:
MaxCacheSizeInByte: 10485760 #10mb
Console:
Port: 50050

25
go.mod
View File

@ -3,7 +3,7 @@ module github.com/caos/zitadel
go 1.14
require (
cloud.google.com/go v0.56.0 // indirect
cloud.google.com/go v0.57.0 // indirect
contrib.go.opencensus.io/exporter/stackdriver v0.13.1
github.com/BurntSushi/toml v0.3.1
github.com/DATA-DOG/go-sqlmock v1.4.1
@ -12,10 +12,10 @@ require (
github.com/Masterminds/sprig v2.22.0+incompatible
github.com/VictoriaMetrics/fastcache v1.5.7
github.com/allegro/bigcache v1.2.1
github.com/aws/aws-sdk-go v1.30.16 // indirect
github.com/aws/aws-sdk-go v1.30.25 // indirect
github.com/caos/logging v0.0.1
github.com/cockroachdb/cockroach-go v0.0.0-20200411195601-6f5842749cfc
github.com/envoyproxy/protoc-gen-validate v0.1.0
github.com/cockroachdb/cockroach-go v0.0.0-20200504194139-73ffeee90b62
github.com/envoyproxy/protoc-gen-validate v0.3.0
github.com/ghodss/yaml v1.0.0
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/mock v1.4.3
@ -27,27 +27,24 @@ require (
github.com/grpc-ecosystem/grpc-gateway v1.14.5
github.com/huandu/xstrings v1.3.1 // indirect
github.com/imdario/mergo v0.3.9 // indirect
github.com/jackc/pgconn v1.5.0 // indirect
github.com/jinzhu/gorm v1.9.12
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/lib/pq v1.5.2
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/nicksnyder/go-i18n/v2 v2.0.3
github.com/pquerna/otp v1.2.0
github.com/rs/cors v1.7.0
github.com/sirupsen/logrus v1.5.0 // indirect
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/sony/sonyflake v1.0.0
github.com/stretchr/testify v1.5.1
go.opencensus.io v0.22.3
golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect
golang.org/x/sys v0.0.0-20200428200454-593003d681fa // indirect
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f // indirect
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 // indirect
golang.org/x/text v0.3.2
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32
google.golang.org/api v0.22.0 // indirect
google.golang.org/appengine v1.6.6 // indirect
google.golang.org/genproto v0.0.0-20200428115010-c45acf45369a
golang.org/x/tools v0.0.0-20200512001501-aaeff5de670a
google.golang.org/api v0.24.0 // indirect
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380
google.golang.org/grpc v1.29.1
google.golang.org/protobuf v1.22.0
gopkg.in/yaml.v2 v2.2.8 // indirect

136
go.sum
View File

@ -11,6 +11,8 @@ cloud.google.com/go v0.53.0 h1:MZQCQQaRwOrAcuKjiHWHrgKykt4fZyuwF2dtiG3fGW8=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.56.0 h1:WRz29PgAsVEyPSDHyk+0fpEkwEFyfhHn+JbksT6gIL4=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0 h1:EpMNVUorLiZIELdMZbCYX/ByTFCdoYopYAGxaGVz9ms=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@ -50,10 +52,8 @@ github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQY
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.30.4 h1:dpQgypC3rld2Uuz+/2u+0nbfmmyEWxau6v1hdAlvoc8=
github.com/aws/aws-sdk-go v1.30.4/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.30.16 h1:1eabOZiVGl+XB02/VG9NpR+3fngaNc74pgb5RmyzgLY=
github.com/aws/aws-sdk-go v1.30.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.30.25 h1:89NXJkfpjnMEnsxkP8MVX+LDsoiLCSqevraLb5y4Mjk=
github.com/aws/aws-sdk-go v1.30.25/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/caos/logging v0.0.1 h1:YSGtO2/+5OWdwilBCou50akoDHAT/OhkbrolkVlR6U0=
@ -70,14 +70,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/cockroach-go v0.0.0-20200312223839-f565e4789405 h1:i1XXyBMAGL7NqogtoS6NHQ/IJwCbG0R725hAhEhldOI=
github.com/cockroachdb/cockroach-go v0.0.0-20200312223839-f565e4789405/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
github.com/cockroachdb/cockroach-go v0.0.0-20200411195601-6f5842749cfc h1:8pe9G3mY+h/qW3ysdFz9Eht4kbIsL0BS5FWih1Sn6JU=
github.com/cockroachdb/cockroach-go v0.0.0-20200411195601-6f5842749cfc/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/cockroachdb/cockroach-go v0.0.0-20200504194139-73ffeee90b62 h1:eqJbq0A8ev6101p/zV72eOM+Z3WZkgb66S7PVJQR9wI=
github.com/cockroachdb/cockroach-go v0.0.0-20200504194139-73ffeee90b62/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -131,8 +125,6 @@ github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgj
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4 h1:+EOh4OY6tjM6ZueeUKinl1f0U2820HzQOuf1iqMnsks=
github.com/golang/protobuf v1.4.0-rc.4/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
@ -153,6 +145,7 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -166,56 +159,16 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=
github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=
github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
github.com/grpc-ecosystem/grpc-gateway v1.14.4 h1:IOPK2xMPP3aV6/NPt4jt//ELFo3Vv8sDVD8j3+tleDU=
github.com/grpc-ecosystem/grpc-gateway v1.14.4/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
github.com/grpc-ecosystem/grpc-gateway v1.14.5 h1:aiLxiiVzAXb7wb3lAmubA69IokWOoUNe+E7TdGKh8yw=
github.com/grpc-ecosystem/grpc-gateway v1.14.5/go.mod h1:UJ0EZAp832vCd54Wev9N1BMKEyvcZ5+IM0AwDrnlkEc=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/huandu/xstrings v1.3.0 h1:gvV6jG9dTgFEncxo+AF7PH6MZXi/vZl25owA/8Dg8Wo=
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs=
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.5.0 h1:oFSOilzIZkyg787M1fEmyMfOUUvwj0daqYMfaWwNL4o=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1 h1:Rdjp4NFjwHnEslx2b66FfCI2S0LhO4itac3hXz6WX9M=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8 h1:Q3tB+ExeflWUW7AFcAhXqk40s9mnNYLk1nOkKNZ5GnU=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
@ -239,22 +192,11 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.4.0 h1:TmtCFbH+Aw0AixwyttznSMQDgbR5Yed/Gg6S8Funrhc=
github.com/lib/pq v1.4.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.5.2 h1:yTSXVswvWUOQ3k1sd7vJfDrbSl8lKuscqFJRqjC0ifw=
github.com/lib/pq v1.5.2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-sqlite3 v2.0.1+incompatible h1:xQ15muvnzGBHpIpdrNi1DA5x0+TcBZzsIDwmw9uTHzw=
github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
@ -278,21 +220,14 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM=
github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@ -301,36 +236,27 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8 h1:fpnn/HnJONpIu6hkXi1u/7rR0NzilgWr4T0JmWkEitk=
golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc h1:ZGI/fILM2+ueot/UixBSoj9188jCAxVHEZEGhqq67I4=
golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -373,7 +299,6 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -383,8 +308,9 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 h1:Jcxah/M+oLZ/R4/z5RzfPzGbPXnVDPkEDtf2JnuxN+U=
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -401,12 +327,9 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -414,7 +337,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab h1:FvshnhkKW+LO3HWHodML8kuVX8rnJTxKm9dFPuI68UM=
@ -429,8 +351,9 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20u
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200428200454-593003d681fa h1:yMbJOvnfYkO1dSAviTu/ZguZWLBTXx4xE3LYrxUCCiA=
golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 h1:OKbAoGs4fGM5cPLlVQLZGYkFC8OnOfgo6tt0Smf9XhM=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -447,7 +370,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@ -455,7 +377,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -476,12 +397,9 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 h1:kDtqNkeBrZb8B+atrj50B5XLHpzXXqcCdZPP/ApQ5NY=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b h1:AFZdJUT7jJYXQEC29hYH/WZkoV7+KhwxQGmdZ19yYoY=
golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 h1:Xvf3ZQTm5bjXPxhI7g+dwqsCqadK1rcNtwtszuatetk=
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512001501-aaeff5de670a h1:vAa2fXRLbiVN3N/xCnodIT36K4QKZQNyQFq3hQJfQ1U=
golang.org/x/tools v0.0.0-20200512001501-aaeff5de670a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
@ -498,10 +416,10 @@ google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.21.0 h1:zS+Q/CJJnVlXpXQVIz+lH0ZT2lBuT2ac7XD8Y/3w6hY=
google.golang.org/api v0.21.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0 h1:J1Pl9P2lnmYFSJvgs70DKELqHNh8CNWXPbud4njEE2s=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0 h1:cG03eaksBzhfSIk7JRGctfp3lanklcOM/mTGvow7BbQ=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -531,10 +449,9 @@ google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940 h1:MRHtG0U6SnaUb+s+LhNE1qt1FQ1wlhqr5E4usBKC0uA=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200403120447-c50568487044 h1:112OPFAnKD+XtZhdffFnz17dEbiCTCKfnNQCAWmwFzA=
google.golang.org/genproto v0.0.0-20200403120447-c50568487044/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200428115010-c45acf45369a h1:ykRcNp3dotYGpAEIYeWCGaefklVjVy/rnSvM3zNh6j8=
google.golang.org/genproto v0.0.0-20200428115010-c45acf45369a/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380 h1:xriR1EgvKfkKxIoU2uUvrMVl+H26359loFFUleSMXFo=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -553,8 +470,6 @@ google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLY
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.20.1 h1:ESRXHgpUBG5D2I5mmsQIyYxB/tQIZfSZ8wLyFDf/N/U=
google.golang.org/protobuf v1.20.1/go.mod h1:KqelGeouBkcbcuB3HCk4/YH2tmNLk6YSWA5LIWeI/lY=
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY=
@ -563,7 +478,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -0,0 +1,25 @@
package auth
import (
"context"
"github.com/caos/zitadel/internal/api/auth"
)
type TokenVerifier struct {
}
func Start() (v *TokenVerifier) {
return new(TokenVerifier)
}
func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) {
return "", "", "", nil
}
func (v *TokenVerifier) ResolveGrants(ctx context.Context, userID, orgID string) ([]*auth.Grant, error) {
return nil, nil
}
func (v *TokenVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) {
return "", nil
}

View File

@ -0,0 +1,11 @@
package model
import (
org_model "github.com/caos/zitadel/internal/org/model"
usr_model "github.com/caos/zitadel/internal/user/model"
)
type SetupOrg struct {
*org_model.Org
*usr_model.User
}

View File

@ -0,0 +1,60 @@
package eventstore
import (
"context"
admin_model "github.com/caos/zitadel/internal/admin/model"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/sdk"
org_model "github.com/caos/zitadel/internal/org/model"
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing"
)
type OrgRepo struct {
Eventstore eventstore.Eventstore
OrgEventstore *org_es.OrgEventstore
UserEventstore *usr_es.UserEventstore
}
func (repo *OrgRepo) SetUpOrg(ctx context.Context, setUp *admin_model.SetupOrg) (*admin_model.SetupOrg, error) {
org, aggregates, err := repo.OrgEventstore.PrepareCreateOrg(ctx, setUp.Org)
if err != nil {
return nil, err
}
user, userAggregate, err := repo.UserEventstore.PrepareCreateUser(ctx, setUp.User, org.AggregateID)
if err != nil {
return nil, err
}
aggregates = append(aggregates, userAggregate)
setupModel := &Setup{Org: org, User: user}
member := org_model.NewOrgMemberWithRoles(org.AggregateID, user.AggregateID, "ORG_ADMIN") //TODO: role as const
_, memberAggregate, err := repo.OrgEventstore.PrepareAddOrgMember(ctx, member)
if err != nil {
return nil, err
}
aggregates = append(aggregates, memberAggregate)
err = sdk.PushAggregates(ctx, repo.Eventstore.PushAggregates, setupModel.AppendEvents, aggregates...)
if err != nil {
return nil, err
}
return SetupToModel(setupModel), nil
}
func (repo *OrgRepo) OrgByID(ctx context.Context, id string) (*org_model.Org, error) {
return repo.OrgEventstore.OrgByID(ctx, org_model.NewOrg(id))
}
func (repo *OrgRepo) SearchOrgs(ctx context.Context) ([]*org_model.Org, error) {
return nil, errors.ThrowUnimplemented(nil, "EVENT-hFIHK", "search not implemented")
}
func (repo *OrgRepo) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) {
return repo.OrgEventstore.IsOrgUnique(ctx, name, domain)
}

View File

@ -0,0 +1,37 @@
package eventstore
import (
admin_model "github.com/caos/zitadel/internal/admin/model"
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
type Setup struct {
*org_es.Org
*usr_es.User
}
func (s *Setup) AppendEvents(events ...*es_models.Event) error {
for _, event := range events {
var err error
switch event.AggregateType {
case org_model.OrgAggregate:
err = s.Org.AppendEvent(event)
case usr_es.UserAggregate:
err = s.User.AppendEvent(event)
}
if err != nil {
return err
}
}
return nil
}
func SetupToModel(setup *Setup) *admin_model.SetupOrg {
return &admin_model.SetupOrg{
Org: org_es.OrgToModel(setup.Org),
User: usr_es.UserToModel(setup.User),
}
}

View File

@ -0,0 +1,23 @@
package eventstore
import (
"context"
usr_model "github.com/caos/zitadel/internal/user/model"
usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
)
type UserRepo struct {
UserEvents *usr_event.UserEventstore
}
func (repo *UserRepo) UserByID(ctx context.Context, id string) (project *usr_model.User, err error) {
return repo.UserEvents.UserByID(ctx, id)
}
func (repo *UserRepo) CreateUser(ctx context.Context, user *usr_model.User) (*usr_model.User, error) {
return repo.UserEvents.CreateUser(ctx, user)
}
func (repo *UserRepo) RegisterUser(ctx context.Context, user *usr_model.User, resourceOwner string) (*usr_model.User, error) {
return repo.UserEvents.RegisterUser(ctx, user, resourceOwner)
}

View File

@ -0,0 +1,68 @@
package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/eventstore"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
es_int "github.com/caos/zitadel/internal/eventstore"
es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing"
es_usr "github.com/caos/zitadel/internal/user/repository/eventsourcing"
)
type Config struct {
Eventstore es_int.Config
//View view.ViewConfig
//Spooler spooler.SpoolerConfig
}
type EsRepository struct {
//spooler *es_spooler.Spooler
eventstore.OrgRepo
}
func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) {
es, err := es_int.Start(conf.Eventstore)
if err != nil {
return nil, err
}
//view, sql, err := mgmt_view.StartView(conf.View)
//if err != nil {
// return nil, err
//}
//conf.Spooler.View = view
//conf.Spooler.EsClient = es.Client
//conf.Spooler.SQL = sql
//spool := spooler.StartSpooler(conf.Spooler)
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es})
user, err := es_usr.StartUser(es_usr.UserConfig{
Eventstore: es,
Cache: conf.Eventstore.Cache,
}, systemDefaults)
if err != nil {
return nil, err
}
return &EsRepository{
OrgRepo: eventstore.OrgRepo{
Eventstore: es,
OrgEventstore: org,
UserEventstore: user,
},
}, nil
}
func (repo *EsRepository) Health(ctx context.Context) error {
err := repo.Eventstore.Health(ctx)
if err != nil {
return err
}
err = repo.UserEventstore.Health(ctx)
if err != nil {
return err
}
return repo.OrgEventstore.Health(ctx)
}

View File

@ -0,0 +1,15 @@
package repository
import (
"context"
admin_model "github.com/caos/zitadel/internal/admin/model"
org_model "github.com/caos/zitadel/internal/org/model"
)
type OrgRepository interface {
SetUpOrg(context.Context, *admin_model.SetupOrg) (*admin_model.SetupOrg, error)
IsOrgUnique(ctx context.Context, name, domain string) (bool, error)
OrgByID(ctx context.Context, id string) (*org_model.Org, error)
SearchOrgs(ctx context.Context) ([]*org_model.Org, error)
}

View File

@ -0,0 +1,8 @@
package repository
import "context"
type Repository interface {
Health(ctx context.Context) error
OrgRepository
}

View File

@ -74,5 +74,5 @@ func readerFuncForFile(configFile string) (ReaderFunc, error) {
case ".toml":
return TOMLReader, nil
}
return nil, errors.ThrowUnimplementedf(nil, "file extension (%s) not supported", ext)
return nil, errors.ThrowUnimplementedf(nil, "CONFI-ZLk4u", "file extension (%s) not supported", ext)
}

View File

@ -0,0 +1,25 @@
package sql
import "database/sql/driver"
// Data represents a byte array that may be null.
// Data implements the sql.Scanner interface
type Data []byte
// Scan implements the Scanner interface.
func (data *Data) Scan(value interface{}) error {
if value == nil {
*data = nil
return nil
}
*data = Data(value.([]byte))
return nil
}
// Value implements the driver Valuer interface.
func (data Data) Value() (driver.Value, error) {
if len(data) == 0 {
return nil, nil
}
return []byte(data), nil
}

View File

@ -24,16 +24,13 @@ var (
expectedFilterEventsAggregateIDTypeLimit = regexp.MustCompile(selectEscaped + ` WHERE aggregate_id = \$1 AND aggregate_type = ANY\(\$2\) ORDER BY event_sequence LIMIT \$3`).String()
expectedGetAllEvents = regexp.MustCompile(selectEscaped + ` ORDER BY event_sequence`).String()
expectedInsertStatement = regexp.MustCompile(`insert into eventstore\.events ` +
expectedInsertStatement = regexp.MustCompile(`INSERT INTO eventstore\.events ` +
`\(event_type, aggregate_type, aggregate_id, aggregate_version, creation_date, event_data, editor_user, editor_service, resource_owner, previous_sequence\) ` +
`select \$1, \$2, \$3, \$4, coalesce\(\$5, now\(\)\), \$6, \$7, \$8, \$9, ` +
`case \(select exists\(select event_sequence from eventstore\.events where aggregate_type = \$10 AND aggregate_id = \$11\)\) ` +
`WHEN true then \(select event_sequence from eventstore\.events where aggregate_type = \$12 AND aggregate_id = \$13 order by event_sequence desc limit 1\) ` +
`ELSE NULL ` +
`end ` +
`where \(` +
`\(select count\(id\) from eventstore\.events where event_sequence >= COALESCE\(\$14, 0\) AND aggregate_type = \$15 AND aggregate_id = \$16\) = 1 OR ` +
`\(\(select count\(id\) from eventstore\.events where aggregate_type = \$17 and aggregate_id = \$18\) = 0 AND COALESCE\(\$19, 0\) = 0\)\) RETURNING id, event_sequence, creation_date`).String()
`SELECT \$1, \$2, \$3, \$4, COALESCE\(\$5, now\(\)\), \$6, \$7, \$8, \$9, \$10 ` +
`WHERE EXISTS \(SELECT 1 WHERE ` +
`EXISTS \(SELECT 1 FROM eventstore\.events WHERE event_sequence = COALESCE\(\$11, 0\) AND aggregate_type = \$12 AND aggregate_id = \$13\) OR ` +
`NOT EXISTS \(SELECT 1 FROM eventstore\.events WHERE aggregate_type = \$14 AND aggregate_id = \$15\) AND COALESCE\(\$16, 0\) = 0\) ` +
`RETURNING id, event_sequence, creation_date`).String()
)
type dbMock struct {
@ -105,9 +102,7 @@ func (db *dbMock) expectRollback(err error) *dbMock {
func (db *dbMock) expectInsertEvent(e *models.Event, returnedID string, returnedSequence uint64) *dbMock {
db.mock.ExpectQuery(expectedInsertStatement).
WithArgs(
e.Type, e.AggregateType, e.AggregateID, e.AggregateVersion, sqlmock.AnyArg(), e.Data, e.EditorUser, e.EditorService, e.ResourceOwner,
e.AggregateType, e.AggregateID,
e.AggregateType, e.AggregateID,
e.Type, e.AggregateType, e.AggregateID, e.AggregateVersion, sqlmock.AnyArg(), Data(e.Data), e.EditorUser, e.EditorService, e.ResourceOwner, Sequence(e.PreviousSequence),
Sequence(e.PreviousSequence), e.AggregateType, e.AggregateID,
e.AggregateType, e.AggregateID, Sequence(e.PreviousSequence),
).
@ -122,9 +117,7 @@ func (db *dbMock) expectInsertEvent(e *models.Event, returnedID string, returned
func (db *dbMock) expectInsertEventError(e *models.Event) *dbMock {
db.mock.ExpectQuery(expectedInsertStatement).
WithArgs(
e.Type, e.AggregateType, e.AggregateID, e.AggregateVersion, sqlmock.AnyArg(), e.Data, e.EditorUser, e.EditorService, e.ResourceOwner,
e.AggregateType, e.AggregateID,
e.AggregateType, e.AggregateID,
e.Type, e.AggregateType, e.AggregateID, e.AggregateVersion, sqlmock.AnyArg(), Data(e.Data), e.EditorUser, e.EditorService, e.ResourceOwner, Sequence(e.PreviousSequence),
Sequence(e.PreviousSequence), e.AggregateType, e.AggregateID,
e.AggregateType, e.AggregateID, Sequence(e.PreviousSequence),
).

View File

@ -54,6 +54,7 @@ func filter(querier Querier, searchQuery *es_models.SearchQuery) (events []*es_m
for rows.Next() {
event := new(models.Event)
var previousSequence Sequence
data := make(Data, 0)
err = rows.Scan(
&event.ID,
@ -61,7 +62,7 @@ func filter(querier Querier, searchQuery *es_models.SearchQuery) (events []*es_m
&event.Type,
&event.Sequence,
&previousSequence,
&event.Data,
&data,
&event.EditorService,
&event.EditorUser,
&event.ResourceOwner,
@ -76,6 +77,10 @@ func filter(querier Querier, searchQuery *es_models.SearchQuery) (events []*es_m
}
event.PreviousSequence = uint64(previousSequence)
event.Data = make([]byte, len(data))
copy(event.Data, data)
events = append(events, event)
}

View File

@ -11,19 +11,14 @@ import (
"github.com/cockroachdb/cockroach-go/crdb"
)
const insertStmt = "insert into eventstore.events " +
const insertStmt = "INSERT INTO eventstore.events " +
"(event_type, aggregate_type, aggregate_id, aggregate_version, creation_date, event_data, editor_user, editor_service, resource_owner, previous_sequence) " +
"select $1, $2, $3, $4, coalesce($5, now()), $6, $7, $8, $9, " +
// case is to set the highest sequence or NULL in previous_sequence
"case (select exists(select event_sequence from eventstore.events where aggregate_type = $10 AND aggregate_id = $11)) " +
"WHEN true then (select event_sequence from eventstore.events where aggregate_type = $12 AND aggregate_id = $13 order by event_sequence desc limit 1) " +
"ELSE NULL " +
"end " +
"where (" +
// exactly one event of requested aggregate must have a >= sequence (last inserted event)
"(select count(id) from eventstore.events where event_sequence >= COALESCE($14, 0) AND aggregate_type = $15 AND aggregate_id = $16) = 1 OR " +
// previous sequence = 0, no events must exist for the requested aggregate
"((select count(id) from eventstore.events where aggregate_type = $17 and aggregate_id = $18) = 0 AND COALESCE($19, 0) = 0)) " +
"SELECT $1, $2, $3, $4, COALESCE($5, now()), $6, $7, $8, $9, $10 " +
"WHERE EXISTS (SELECT 1 WHERE " +
// exactly one event of requested aggregate must have the given previous sequence as sequence (last inserted event)
"EXISTS (SELECT 1 FROM eventstore.events WHERE event_sequence = COALESCE($11, 0) AND aggregate_type = $12 AND aggregate_id = $13) OR " +
// if previous sequence = 0, no events must exist for the requested aggregate
"NOT EXISTS (SELECT 1 FROM eventstore.events WHERE aggregate_type = $14 AND aggregate_id = $15) AND COALESCE($16, 0) = 0) " +
"RETURNING id, event_sequence, creation_date"
func (db *SQL) PushAggregates(ctx context.Context, aggregates ...*models.Aggregate) (err error) {
@ -74,14 +69,7 @@ func precondtion(tx *sql.Tx, aggregate *models.Aggregate) error {
func insertEvents(stmt *sql.Stmt, previousSequence Sequence, events []*models.Event) error {
for _, event := range events {
if event.Data == nil || len(event.Data) == 0 {
//json decoder failes with EOF if json text is empty
event.Data = []byte("{}")
}
rows, err := stmt.Query(event.Type, event.AggregateType, event.AggregateID, event.AggregateVersion, event.CreationDate, event.Data, event.EditorUser, event.EditorService, event.ResourceOwner,
event.AggregateType, event.AggregateID,
event.AggregateType, event.AggregateID,
rows, err := stmt.Query(event.Type, event.AggregateType, event.AggregateID, event.AggregateVersion, event.CreationDate, Data(event.Data), event.EditorUser, event.EditorService, event.ResourceOwner, previousSequence,
previousSequence, event.AggregateType, event.AggregateID,
event.AggregateType, event.AggregateID, previousSequence)
@ -99,6 +87,7 @@ func insertEvents(stmt *sql.Stmt, previousSequence Sequence, events []*models.Ev
}
if !rowInserted {
logging.LogWithFields("SQL-5aATu", "aggregate", event.AggregateType, "id", event.AggregateID).Info("wrong sequence")
return caos_errs.ThrowAlreadyExists(nil, "SQL-GKcAa", "wrong sequence")
}

View File

@ -89,7 +89,6 @@ func TestSQL_PushAggregates(t *testing.T) {
ResourceOwner: "ro",
PreviousSequence: 34,
Type: "eventTyp",
Data: []byte("{}"),
AggregateVersion: "v0.0.1",
},
"asdfölk-234", 45).
@ -101,7 +100,6 @@ func TestSQL_PushAggregates(t *testing.T) {
ResourceOwner: "ro2",
PreviousSequence: 45,
Type: "eventTyp",
Data: []byte("{}"),
AggregateVersion: "v0.0.1",
}, "asdfölk-233", 46).
expectReleaseSavepoint(nil).
@ -151,7 +149,6 @@ func TestSQL_PushAggregates(t *testing.T) {
EditorUser: "usr",
ResourceOwner: "ro",
PreviousSequence: 34,
Data: []byte("{}"),
Type: "eventTyp",
AggregateVersion: "v0.0.1",
}, "asdfölk-233", 47).
@ -162,7 +159,6 @@ func TestSQL_PushAggregates(t *testing.T) {
EditorUser: "usr",
ResourceOwner: "ro",
PreviousSequence: 40,
Data: []byte("{}"),
Type: "eventTyp",
AggregateVersion: "v0.0.1",
}, "asdfölk-233", 48).
@ -410,8 +406,11 @@ func Test_precondtion(t *testing.T) {
t.FailNow()
}
err = precondtion(tx, tt.args.aggregate)
if (tt.isErr != nil && err == nil) || (tt.isErr != nil && !tt.isErr(err)) {
t.Error("precondtion() wrong error", err)
if (err != nil) && (tt.isErr == nil) {
t.Errorf("no error expected got: %v", err)
}
if tt.isErr != nil && !tt.isErr(err) {
t.Errorf("precondtion() wrong error %T, %v", err, err)
}
})
}

View File

@ -5,16 +5,16 @@ import (
)
// Sequence represents a number that may be null.
// Sequence implements the sql.Scanner interface so
// Sequence implements the sql.Scanner interface
type Sequence uint64
// Scan implements the Scanner interface.
func (n *Sequence) Scan(value interface{}) error {
func (seq *Sequence) Scan(value interface{}) error {
if value == nil {
*n = 0
*seq = 0
return nil
}
*n = Sequence(value.(int64))
*seq = Sequence(value.(int64))
return nil
}

View File

@ -15,7 +15,7 @@ func (at AggregateType) String() string {
type Aggregates []*Aggregate
type Aggregate struct {
id string
ID string
typ AggregateType
PreviousSequence uint64
version Version
@ -45,7 +45,7 @@ func (a *Aggregate) AppendEvent(typ EventType, payload interface{}) (*Aggregate,
CreationDate: time.Now(),
Data: data,
Type: typ,
AggregateID: a.id,
AggregateID: a.ID,
AggregateType: a.typ,
AggregateVersion: a.version,
EditorService: a.editorService,
@ -66,7 +66,7 @@ func (a *Aggregate) Validate() error {
if a == nil {
return errors.ThrowPreconditionFailed(nil, "MODEL-yi5AC", "aggregate is nil")
}
if a.id == "" {
if a.ID == "" {
return errors.ThrowPreconditionFailed(nil, "MODEL-FSjKV", "id not set")
}
if string(a.typ) == "" {

View File

@ -22,7 +22,7 @@ func (c *AggregateCreator) NewAggregate(ctx context.Context, id string, typ Aggr
resourceOwner := ctxData.OrgID
aggregate := &Aggregate{
id: id,
ID: id,
typ: typ,
PreviousSequence: previousSequence,
version: version,

View File

@ -83,7 +83,7 @@ func TestAggregateCreator_NewAggregate(t *testing.T) {
creator: &AggregateCreator{serviceName: "admin"},
wantErr: false,
want: &Aggregate{
id: "hodor",
ID: "hodor",
Events: make([]*Event, 0, 2),
typ: "user",
version: "v1.0.0",

View File

@ -114,7 +114,7 @@ func TestAggregate_Validate(t *testing.T) {
name: "no type error",
wantErr: true,
fields: fields{aggregate: &Aggregate{
id: "aggID",
ID: "aggID",
version: "v1.0.0",
editorService: "svc",
editorUser: "hodor",
@ -135,7 +135,7 @@ func TestAggregate_Validate(t *testing.T) {
name: "invalid version error",
wantErr: true,
fields: fields{aggregate: &Aggregate{
id: "aggID",
ID: "aggID",
typ: "user",
editorService: "svc",
editorUser: "hodor",
@ -156,7 +156,7 @@ func TestAggregate_Validate(t *testing.T) {
name: "no query in precondition error",
wantErr: true,
fields: fields{aggregate: &Aggregate{
id: "aggID",
ID: "aggID",
typ: "user",
version: "v1.0.0",
editorService: "svc",
@ -182,7 +182,7 @@ func TestAggregate_Validate(t *testing.T) {
name: "no func in precondition error",
wantErr: true,
fields: fields{aggregate: &Aggregate{
id: "aggID",
ID: "aggID",
typ: "user",
version: "v1.0.0",
editorService: "svc",
@ -208,7 +208,7 @@ func TestAggregate_Validate(t *testing.T) {
name: "validation without precondition ok",
wantErr: false,
fields: fields{aggregate: &Aggregate{
id: "aggID",
ID: "aggID",
typ: "user",
version: "v1.0.0",
editorService: "svc",
@ -231,7 +231,7 @@ func TestAggregate_Validate(t *testing.T) {
name: "validation with precondition ok",
wantErr: false,
fields: fields{aggregate: &Aggregate{
id: "aggID",
ID: "aggID",
typ: "user",
version: "v1.0.0",
editorService: "svc",

View File

@ -1,6 +1,8 @@
package models
import "github.com/caos/zitadel/internal/errors"
import (
"github.com/caos/zitadel/internal/errors"
)
type SearchQuery struct {
Limit uint64
@ -33,6 +35,10 @@ func (q *SearchQuery) AggregateIDFilter(id string) *SearchQuery {
return q.setFilter(NewFilter(Field_AggregateID, id, Operation_Equals))
}
func (q *SearchQuery) AggregateIDsFilter(ids ...string) *SearchQuery {
return q.setFilter(NewFilter(Field_AggregateID, ids, Operation_In))
}
func (q *SearchQuery) AggregateTypeFilter(types ...AggregateType) *SearchQuery {
return q.setFilter(NewFilter(Field_AggregateType, types, Operation_In))
}

View File

@ -0,0 +1,52 @@
package eventstore
import (
"context"
"github.com/caos/zitadel/internal/errors"
org_model "github.com/caos/zitadel/internal/org/model"
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
)
type OrgRepository struct {
*org_es.OrgEventstore
}
func (repo *OrgRepository) OrgByID(ctx context.Context, id string) (*org_model.Org, error) {
org := org_model.NewOrg(id)
return repo.OrgEventstore.OrgByID(ctx, org)
}
func (repo *OrgRepository) OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.Org, error) {
return nil, errors.ThrowUnimplemented(nil, "EVENT-GQoS8", "not implemented")
}
func (repo *OrgRepository) UpdateOrg(ctx context.Context, org *org_model.Org) (*org_model.Org, error) {
return nil, errors.ThrowUnimplemented(nil, "EVENT-RkurR", "not implemented")
}
func (repo *OrgRepository) DeactivateOrg(ctx context.Context, id string) (*org_model.Org, error) {
return repo.OrgEventstore.DeactivateOrg(ctx, id)
}
func (repo *OrgRepository) ReactivateOrg(ctx context.Context, id string) (*org_model.Org, error) {
return repo.OrgEventstore.ReactivateOrg(ctx, id)
}
func (repo *OrgRepository) OrgMemberByID(ctx context.Context, orgID, userID string) (member *org_model.OrgMember, err error) {
member = org_model.NewOrgMember(orgID, userID)
return repo.OrgEventstore.OrgMemberByIDs(ctx, member)
}
func (repo *OrgRepository) AddOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
return repo.OrgEventstore.AddOrgMember(ctx, member)
}
func (repo *OrgRepository) ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
return repo.OrgEventstore.ChangeOrgMember(ctx, member)
}
func (repo *OrgRepository) RemoveOrgMember(ctx context.Context, orgID, userID string) error {
member := org_model.NewOrgMember(orgID, userID)
return repo.OrgEventstore.RemoveOrgMember(ctx, member)
}

View File

@ -2,6 +2,7 @@ package eventsourcing
import (
"context"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/config/types"
es_int "github.com/caos/zitadel/internal/eventstore"
@ -10,6 +11,7 @@ import (
"github.com/caos/zitadel/internal/management/repository/eventsourcing/handler"
"github.com/caos/zitadel/internal/management/repository/eventsourcing/spooler"
mgmt_view "github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing"
es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing"
es_usr "github.com/caos/zitadel/internal/user/repository/eventsourcing"
es_grant "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing"
@ -24,6 +26,7 @@ type Config struct {
type EsRepository struct {
spooler *es_spol.Spooler
eventstore.OrgRepository
eventstore.ProjectRepo
eventstore.UserRepo
eventstore.UserGrantRepo
@ -65,14 +68,17 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error)
if err != nil {
return nil, err
}
org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es})
eventstoreRepos := handler.EventstoreRepos{ProjectEvents: project}
spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, eventstoreRepos)
return &EsRepository{
spool,
eventstore.ProjectRepo{conf.SearchLimit, project, view},
eventstore.UserRepo{conf.SearchLimit, user, view},
eventstore.UserGrantRepo{conf.SearchLimit, usergrant, view},
spooler: spool,
OrgRepository: eventstore.OrgRepository{org},
ProjectRepo: eventstore.ProjectRepo{conf.SearchLimit, project, view},
UserRepo: eventstore.UserRepo{conf.SearchLimit, user, view},
UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, usergrant, view},
}, nil
}

View File

@ -0,0 +1,21 @@
package repository
import (
"context"
org_model "github.com/caos/zitadel/internal/org/model"
)
type OrgRepository interface {
OrgByID(ctx context.Context, id string) (*org_model.Org, error)
OrgByDomainGlobal(ctx context.Context, domain string) (*org_model.Org, error)
UpdateOrg(ctx context.Context, org *org_model.Org) (*org_model.Org, error)
DeactivateOrg(ctx context.Context, id string) (*org_model.Org, error)
ReactivateOrg(ctx context.Context, id string) (*org_model.Org, error)
}
type OrgMemberRepository interface {
AddOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error)
ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error)
RemoveOrgMember(ctx context.Context, orgID, userID string) error
}

View File

@ -3,6 +3,8 @@ package repository
type Repository interface {
Health() error
ProjectRepository
OrgRepository
OrgMemberRepository
UserRepository
UserGrantRepository
}

View File

@ -0,0 +1,21 @@
package model
import es_models "github.com/caos/zitadel/internal/eventstore/models"
type OrgMember struct {
es_models.ObjectRoot
UserID string
Roles []string
}
func NewOrgMember(orgID, userID string) *OrgMember {
return &OrgMember{ObjectRoot: es_models.ObjectRoot{AggregateID: orgID}, UserID: userID}
}
func NewOrgMemberWithRoles(orgID, userID string, roles ...string) *OrgMember {
return &OrgMember{ObjectRoot: es_models.ObjectRoot{AggregateID: orgID}, UserID: userID, Roles: roles}
}
func (member *OrgMember) IsValid() bool {
return member.AggregateID != "" && member.UserID != ""
}

43
internal/org/model/org.go Normal file
View File

@ -0,0 +1,43 @@
package model
import (
es_models "github.com/caos/zitadel/internal/eventstore/models"
)
type Org struct {
es_models.ObjectRoot
State OrgState
Name string
Domain string
Members []*OrgMember
}
type OrgState int32
const (
ORGSTATE_ACTIVE OrgState = iota
ORGSTATE_INACTIVE
)
func NewOrg(id string) *Org {
return &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: id}, State: ORGSTATE_ACTIVE}
}
func (o *Org) IsActive() bool {
return o.State == ORGSTATE_ACTIVE
}
func (o *Org) IsValid() bool {
return o.Name != "" && o.Domain != ""
}
func (o *Org) ContainsMember(userID string) bool {
for _, member := range o.Members {
if member.UserID == userID {
return true
}
}
return false
}

View File

@ -0,0 +1,24 @@
package model
import "github.com/caos/zitadel/internal/eventstore/models"
const (
OrgAggregate models.AggregateType = "org"
OrgDomainAggregate models.AggregateType = "org.domain"
OrgNameAggregate models.AggregateType = "org.name"
OrgAdded models.EventType = "org.added"
OrgChanged models.EventType = "org.changed"
OrgDeactivated models.EventType = "org.deactivated"
OrgReactivated models.EventType = "org.reactivated"
OrgNameReserved models.EventType = "org.name.reserved"
OrgNameReleased models.EventType = "org.name.released"
OrgDomainReserved models.EventType = "org.domain.reserved"
OrgDomainReleased models.EventType = "org.domain.released"
OrgMemberAdded models.EventType = "org.member.added"
OrgMemberChanged models.EventType = "org.member.changed"
OrgMemberRemoved models.EventType = "org.member.removed"
)

View File

@ -0,0 +1,215 @@
package eventsourcing
import (
"context"
"strconv"
"github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
es_models "github.com/caos/zitadel/internal/eventstore/models"
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
org_model "github.com/caos/zitadel/internal/org/model"
)
type OrgEventstore struct {
eventstore.Eventstore
}
type OrgConfig struct {
eventstore.Eventstore
}
func StartOrg(conf OrgConfig) *OrgEventstore {
return &OrgEventstore{Eventstore: conf.Eventstore}
}
func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_model.Org) (*Org, []*es_models.Aggregate, error) {
if orgModel == nil || !orgModel.IsValid() {
return nil, nil, errors.ThrowInvalidArgument(nil, "EVENT-OeLSk", "org not valid")
}
id, err := idGenerator.NextID()
if err != nil {
return nil, nil, errors.ThrowInternal(err, "EVENT-OwciI", "id gen failed")
}
orgModel.AggregateID = strconv.FormatUint(id, 10)
org := OrgFromModel(orgModel)
aggregates, err := orgCreatedAggregates(ctx, es.AggregateCreator(), org)
return org, aggregates, err
}
func (es *OrgEventstore) CreateOrg(ctx context.Context, orgModel *org_model.Org) (*org_model.Org, error) {
org, aggregates, err := es.PrepareCreateOrg(ctx, orgModel)
err = es_sdk.PushAggregates(ctx, es.PushAggregates, org.AppendEvents, aggregates...)
if err != nil {
return nil, err
}
return OrgToModel(org), nil
}
func (es *OrgEventstore) OrgByID(ctx context.Context, org *org_model.Org) (*org_model.Org, error) {
if org == nil {
return nil, errors.ThrowInvalidArgument(nil, "EVENT-gQTYP", "org not set")
}
query, err := OrgByIDQuery(org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
esOrg := OrgFromModel(org)
err = es_sdk.Filter(ctx, es.FilterEvents, esOrg.AppendEvents, query)
if err != nil && !errors.IsNotFound(err) {
return nil, err
}
if esOrg.Sequence == 0 {
return nil, errors.ThrowNotFound(nil, "EVENT-kVLb2", "org not found")
}
return OrgToModel(esOrg), nil
}
func (es *OrgEventstore) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) {
var found bool
err = es_sdk.Filter(ctx, es.FilterEvents, isUniqueValidation(&found), OrgNameUniqueQuery(name))
if (err != nil && !errors.IsNotFound(err)) || found {
return false, err
}
err = es_sdk.Filter(ctx, es.FilterEvents, isUniqueValidation(&found), OrgDomainUniqueQuery(domain))
if err != nil && !errors.IsNotFound(err) {
return false, err
}
return !found, nil
}
func isUniqueValidation(unique *bool) func(events ...*es_models.Event) error {
return func(events ...*es_models.Event) error {
if len(events) == 0 {
return nil
}
*unique = *unique || events[0].Type == org_model.OrgDomainReserved || events[0].Type == org_model.OrgNameReserved
return nil
}
}
func (es *OrgEventstore) DeactivateOrg(ctx context.Context, orgID string) (*org_model.Org, error) {
existingOrg, err := es.OrgByID(ctx, org_model.NewOrg(orgID))
if err != nil {
return nil, errors.ThrowInvalidArgument(nil, "EVENT-oL9nT", "org not found")
}
org := OrgFromModel(existingOrg)
aggregate := orgDeactivateAggregate(es.AggregateCreator(), org)
err = es_sdk.Push(ctx, es.PushAggregates, org.AppendEvents, aggregate)
if err != nil {
return nil, err
}
return OrgToModel(org), nil
}
func (es *OrgEventstore) ReactivateOrg(ctx context.Context, orgID string) (*org_model.Org, error) {
existingOrg, err := es.OrgByID(ctx, org_model.NewOrg(orgID))
if err != nil {
return nil, errors.ThrowInvalidArgument(nil, "EVENT-oL9nT", "org not set")
}
org := OrgFromModel(existingOrg)
aggregate := orgReactivateAggregate(es.AggregateCreator(), org)
err = es_sdk.Push(ctx, es.PushAggregates, org.AppendEvents, aggregate)
if err != nil {
return nil, err
}
return OrgToModel(org), nil
}
func (es *OrgEventstore) OrgMemberByIDs(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
if member == nil || member.UserID == "" || member.AggregateID == "" {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-ld93d", "member not set")
}
org, err := es.OrgByID(ctx, &org_model.Org{ObjectRoot: member.ObjectRoot, Members: []*org_model.OrgMember{member}})
if err != nil {
return nil, err
}
for _, currentMember := range org.Members {
if currentMember.UserID == member.UserID {
return currentMember, nil
}
}
return nil, errors.ThrowNotFound(nil, "EVENT-SXji6", "member not found")
}
func (es *OrgEventstore) PrepareAddOrgMember(ctx context.Context, member *org_model.OrgMember) (*OrgMember, *es_models.Aggregate, error) {
if member == nil || !member.IsValid() {
return nil, nil, errors.ThrowPreconditionFailed(nil, "EVENT-9dk45", "UserID and Roles are required")
}
repoMember := OrgMemberFromModel(member)
addAggregate, err := orgMemberAddedAggregate(ctx, es.Eventstore.AggregateCreator(), repoMember)
return repoMember, addAggregate, err
}
func (es *OrgEventstore) AddOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
repoMember, addAggregate, err := es.PrepareAddOrgMember(ctx, member)
if err != nil {
return nil, err
}
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoMember.AppendEvents, addAggregate)
if err != nil {
return nil, err
}
return OrgMemberToModel(repoMember), nil
}
func (es *OrgEventstore) ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) {
if member == nil || !member.IsValid() {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-9dk45", "UserID and Roles are required")
}
existingMember, err := es.OrgMemberByIDs(ctx, member)
if err != nil {
return nil, err
}
member.ObjectRoot = existingMember.ObjectRoot
repoMember := OrgMemberFromModel(member)
repoExistingMember := OrgMemberFromModel(existingMember)
orgAggregate := orgMemberChangedAggregate(es.Eventstore.AggregateCreator(), repoExistingMember, repoMember)
err = es_sdk.Push(ctx, es.PushAggregates, repoMember.AppendEvents, orgAggregate)
if err != nil {
return nil, err
}
return OrgMemberToModel(repoMember), nil
}
func (es *OrgEventstore) RemoveOrgMember(ctx context.Context, member *org_model.OrgMember) error {
if member == nil || member.UserID == "" {
return errors.ThrowInvalidArgument(nil, "EVENT-d43fs", "UserID is required")
}
existingMember, err := es.OrgMemberByIDs(ctx, member)
if errors.IsNotFound(err) {
return nil
}
if err != nil {
return err
}
member.ObjectRoot = existingMember.ObjectRoot
repoMember := OrgMemberFromModel(member)
orgAggregate := orgMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoMember)
return es_sdk.Push(ctx, es.PushAggregates, repoMember.AppendEvents, orgAggregate)
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
package eventsourcing
import (
"encoding/json"
"reflect"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/org/model"
)
type OrgMember struct {
es_models.ObjectRoot `json:"-"`
UserID string `json:"userId,omitempty"`
Roles []string `json:"roles,omitempty"`
}
func (m *OrgMember) AppendEvents(events ...*es_models.Event) error {
for _, event := range events {
err := m.AppendEvent(event)
if err != nil {
return err
}
}
return nil
}
func (m *OrgMember) AppendEvent(event *es_models.Event) error {
m.ObjectRoot.AppendEvent(event)
return m.setData(event)
}
func (m *OrgMember) setData(event *es_models.Event) error {
err := json.Unmarshal(event.Data, m)
if err != nil {
return errors.ThrowInternal(err, "EVENT-Hz7Mb", "unable to unmarshal data")
}
return nil
}
func (m *OrgMember) Changes(updatedMember *OrgMember) map[string]interface{} {
changes := make(map[string]interface{}, 2)
if !reflect.DeepEqual(m.Roles, updatedMember.Roles) {
changes["roles"] = updatedMember.Roles
changes["userId"] = m.UserID
}
return changes
}
func OrgMemberFromEvent(member *OrgMember, event *es_models.Event) (*OrgMember, error) {
if member == nil {
member = new(OrgMember)
}
member.ObjectRoot.AppendEvent(event)
err := json.Unmarshal(event.Data, member)
if err != nil {
return nil, errors.ThrowInternal(err, "EVENT-D4qxo", "invalid event data")
}
return member, nil
}
func OrgMembersFromModel(members []*model.OrgMember) []*OrgMember {
convertedMembers := make([]*OrgMember, len(members))
for i, m := range members {
convertedMembers[i] = OrgMemberFromModel(m)
}
return convertedMembers
}
func OrgMemberFromModel(member *model.OrgMember) *OrgMember {
return &OrgMember{
ObjectRoot: member.ObjectRoot,
UserID: member.UserID,
Roles: member.Roles,
}
}
func OrgMembersToModel(members []*OrgMember) []*model.OrgMember {
convertedMembers := make([]*model.OrgMember, len(members))
for i, m := range members {
convertedMembers[i] = OrgMemberToModel(m)
}
return convertedMembers
}
func OrgMemberToModel(member *OrgMember) *model.OrgMember {
return &model.OrgMember{
ObjectRoot: member.ObjectRoot,
UserID: member.UserID,
Roles: member.Roles,
}
}

View File

@ -0,0 +1,195 @@
package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
"github.com/sony/sonyflake"
)
var idGenerator = sonyflake.NewSonyflake(sonyflake.Settings{})
func OrgByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
if id == "" {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dke74", "id should be filled")
}
return OrgQuery(latestSequence).
AggregateIDFilter(id), nil
}
func OrgDomainUniqueQuery(domain string) *es_models.SearchQuery {
return es_models.NewSearchQuery().
AggregateTypeFilter(org_model.OrgDomainAggregate).
AggregateIDFilter(domain).
OrderDesc().
SetLimit(1)
}
func OrgNameUniqueQuery(name string) *es_models.SearchQuery {
return es_models.NewSearchQuery().
AggregateTypeFilter(org_model.OrgNameAggregate).
AggregateIDFilter(name).
OrderDesc().
SetLimit(1)
}
func OrgQuery(latestSequence uint64) *es_models.SearchQuery {
return es_models.NewSearchQuery().
AggregateTypeFilter(org_model.OrgAggregate).
LatestSequenceFilter(latestSequence)
}
func OrgAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, id string, sequence uint64) (*es_models.Aggregate, error) {
return aggCreator.NewAggregate(ctx, id, org_model.OrgAggregate, orgVersion, sequence)
}
func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, org *Org) (_ []*es_models.Aggregate, err error) {
if org == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie7", "org should not be nil")
}
domainAgrregate, err := uniqueDomainAggregate(ctx, aggCreator, org.Domain)
if err != nil {
return nil, err
}
nameAggregate, err := uniqueNameAggregate(ctx, aggCreator, org.Name)
if err != nil {
return nil, err
}
agg, err := aggCreator.NewAggregate(ctx, org.AggregateID, org_model.OrgAggregate, orgVersion, org.Sequence, es_models.OverwriteResourceOwner(org.AggregateID))
if err != nil {
return nil, err
}
agg, err = agg.AppendEvent(org_model.OrgAdded, org)
if err != nil {
return nil, err
}
return []*es_models.Aggregate{
agg,
domainAgrregate,
nameAggregate,
}, nil
}
func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *Org, updated *Org) ([]*es_models.Aggregate, error) {
if existing == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dk83d", "existing org must not be nil")
}
if updated == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dhr74", "updated org must not be nil")
}
changes := existing.Changes(updated)
if len(changes) == 0 {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-E0hc5", "no changes")
}
aggregates := make([]*es_models.Aggregate, 0, 3)
if name, ok := changes["name"]; ok {
nameAggregate, err := uniqueNameAggregate(ctx, aggCreator, name.(string))
if err != nil {
return nil, err
}
aggregates = append(aggregates, nameAggregate)
}
if name, ok := changes["domain"]; ok {
domainAggregate, err := uniqueDomainAggregate(ctx, aggCreator, name.(string))
if err != nil {
return nil, err
}
aggregates = append(aggregates, domainAggregate)
}
orgAggregate, err := OrgAggregate(ctx, aggCreator, existing.AggregateID, existing.Sequence)
if err != nil {
return nil, err
}
orgAggregate, err = orgAggregate.AppendEvent(org_model.OrgChanged, changes)
if err != nil {
return nil, err
}
aggregates = append(aggregates, orgAggregate)
return aggregates, nil
}
func orgDeactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if org == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-R03z8", "existing org must not be nil")
}
if org.State == int32(org_model.ORGSTATE_INACTIVE) {
return nil, errors.ThrowInvalidArgument(nil, "EVENT-mcPH0", "org already inactive")
}
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
return agg.AppendEvent(org_model.OrgDeactivated, nil)
}
}
func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if org == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-cTHLd", "existing org must not be nil")
}
if org.State == int32(org_model.ORGSTATE_ACTIVE) {
return nil, errors.ThrowInvalidArgument(nil, "EVENT-pUSMs", "org already active")
}
agg, err := OrgAggregate(ctx, aggCreator, org.AggregateID, org.Sequence)
if err != nil {
return nil, err
}
return agg.AppendEvent(org_model.OrgReactivated, nil)
}
}
func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, domain string) (*es_models.Aggregate, error) {
aggregate, err := aggCreator.NewAggregate(ctx, domain, org_model.OrgDomainAggregate, orgVersion, 0)
if err != nil {
return nil, err
}
aggregate, err = aggregate.AppendEvent(org_model.OrgDomainReserved, nil)
if err != nil {
return nil, err
}
return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isReservedValidation(aggregate, org_model.OrgDomainReserved)), nil
}
func uniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, name string) (*es_models.Aggregate, error) {
aggregate, err := aggCreator.NewAggregate(ctx, name, org_model.OrgNameAggregate, orgVersion, 0)
if err != nil {
return nil, err
}
aggregate, err = aggregate.AppendEvent(org_model.OrgNameReserved, nil)
if err != nil {
return nil, err
}
return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isReservedValidation(aggregate, org_model.OrgNameReserved)), nil
}
func isReservedValidation(aggregate *es_models.Aggregate, resevedEventType es_models.EventType) func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
if len(events) == 0 {
aggregate.PreviousSequence = 0
return nil
}
if events[0].Type == resevedEventType {
return errors.ThrowPreconditionFailed(nil, "EVENT-eJQqe", "org already reseved")
}
aggregate.PreviousSequence = events[0].Sequence
return nil
}
}

View File

@ -0,0 +1,93 @@
package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
func orgMemberAddedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, member *OrgMember) (*es_models.Aggregate, error) {
if member == nil {
return nil, errors.ThrowInvalidArgument(nil, "EVENT-c63Ap", "member must not be nil")
}
aggregate, err := aggCreator.NewAggregate(ctx, member.AggregateID, org_model.OrgAggregate, orgVersion, member.Sequence)
if err != nil {
return nil, err
}
validationQuery := es_models.NewSearchQuery().
AggregateTypeFilter("org", "user").
AggregateIDsFilter(member.AggregateID, member.UserID)
validation := addMemberValidation(aggregate, member)
return aggregate.SetPrecondition(validationQuery, validation).AppendEvent(org_model.OrgMemberAdded, member)
}
func orgMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existingMember *OrgMember, member *OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if member == nil || existingMember == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d34fs", "member must not be nil")
}
changes := existingMember.Changes(member)
if len(changes) == 0 {
return nil, errors.ThrowInvalidArgument(nil, "EVENT-VLMGn", "nothing changed")
}
agg, err := OrgAggregate(ctx, aggCreator, existingMember.AggregateID, existingMember.Sequence)
if err != nil {
return nil, err
}
return agg.AppendEvent(org_model.OrgMemberChanged, changes)
}
}
func orgMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, member *OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if member == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dieu7", "member must not be nil")
}
agg, err := OrgAggregate(ctx, aggCreator, member.AggregateID, member.Sequence)
if err != nil {
return nil, err
}
return agg.AppendEvent(org_model.OrgMemberRemoved, member)
}
}
func addMemberValidation(aggregate *es_models.Aggregate, member *OrgMember) func(...*es_models.Event) error {
return func(events ...*es_models.Event) error {
existsOrg := false
existsUser := false
isMember := false
for _, event := range events {
switch event.AggregateType {
case usr_model.UserAggregate:
existsUser = true
case org_model.OrgAggregate:
aggregate.PreviousSequence = event.Sequence
existsOrg = true
switch event.Type {
case org_model.OrgMemberAdded, org_model.OrgMemberRemoved:
manipulatedMember, err := OrgMemberFromEvent(new(OrgMember), event)
if err != nil {
return errors.ThrowInternal(err, "EVENT-Eg8St", "unable to validate object")
}
if manipulatedMember.UserID == member.UserID {
isMember = event.Type == org_model.OrgMemberAdded
}
}
}
}
if existsOrg && existsUser && !isMember {
return nil
}
return errors.ThrowPreconditionFailed(nil, "EVENT-3OfIm", "conditions not met")
}
}

View File

@ -0,0 +1,397 @@
package eventsourcing
import (
"context"
"testing"
"github.com/caos/zitadel/internal/api/auth"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
func TestOrgMemberAddedAggregate(t *testing.T) {
type res struct {
isErr func(error) bool
eventCount int
}
type args struct {
aggCreator *es_models.AggregateCreator
member *OrgMember
ctx context.Context
}
tests := []struct {
name string
args args
res res
}{
{
name: "no member",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
member: nil,
},
res: res{
isErr: errors.IsErrorInvalidArgument,
},
},
{
name: "member added sucessfully",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
member: &OrgMember{
ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234},
},
},
res: res{
isErr: nil,
eventCount: 1,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
aggregate, err := orgMemberAddedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.member)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && aggregate == nil {
t.Error("aggregate must not be nil")
}
if tt.res.isErr == nil && len(aggregate.Events) != tt.res.eventCount {
t.Error("wrong amount of events")
}
})
}
}
func TestOrgMemberChangedAggregate(t *testing.T) {
type res struct {
isErr func(error) bool
eventCount int
}
type args struct {
aggCreator *es_models.AggregateCreator
existingMember *OrgMember
member *OrgMember
ctx context.Context
}
tests := []struct {
name string
args args
res res
}{
{
name: "no member",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
member: nil,
existingMember: &OrgMember{},
},
res: res{
isErr: errors.IsPreconditionFailed,
},
},
{
name: "no existing member",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
existingMember: nil,
member: &OrgMember{},
},
res: res{
isErr: errors.IsPreconditionFailed,
},
},
{
name: "no changes",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
member: &OrgMember{
ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234},
},
existingMember: &OrgMember{
ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234},
},
},
res: res{
isErr: errors.IsErrorInvalidArgument,
},
},
{
name: "with changes success",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
member: &OrgMember{
ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234},
Roles: []string{"asdf"},
},
existingMember: &OrgMember{
ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234},
Roles: []string{"asdf", "woeri"},
},
},
res: res{
isErr: nil,
eventCount: 1,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
aggregateCreator := orgMemberChangedAggregate(tt.args.aggCreator, tt.args.existingMember, tt.args.member)
aggregate, err := aggregateCreator(tt.args.ctx)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && aggregate == nil {
t.Error("aggregate must not be nil")
}
if tt.res.isErr == nil && len(aggregate.Events) != tt.res.eventCount {
t.Error("wrong amount of events")
}
})
}
}
func TestOrgMemberRemovedAggregate(t *testing.T) {
type res struct {
isErr func(error) bool
eventCount int
}
type args struct {
aggCreator *es_models.AggregateCreator
member *OrgMember
ctx context.Context
}
tests := []struct {
name string
args args
res res
}{
{
name: "no member",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
member: nil,
},
res: res{
isErr: errors.IsPreconditionFailed,
},
},
{
name: "member added sucessfully",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
member: &OrgMember{
ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234},
},
},
res: res{
isErr: nil,
eventCount: 1,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
aggregateCreator := orgMemberRemovedAggregate(tt.args.aggCreator, tt.args.member)
aggregate, err := aggregateCreator(tt.args.ctx)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && aggregate == nil {
t.Error("aggregate must not be nil")
}
if tt.res.isErr == nil && len(aggregate.Events) != tt.res.eventCount {
t.Error("wrong amount of events")
}
})
}
}
func Test_addMemberValidation(t *testing.T) {
type res struct {
isErr func(error) bool
preivousSequence uint64
}
type args struct {
aggregate *es_models.Aggregate
events []*es_models.Event
member *OrgMember
}
tests := []struct {
name string
args args
res res
}{
{
name: "no events",
args: args{
aggregate: &es_models.Aggregate{},
},
res: res{
isErr: errors.IsPreconditionFailed,
},
},
{
name: "only org events",
args: args{
aggregate: &es_models.Aggregate{},
events: []*es_models.Event{
{
AggregateType: org_model.OrgAggregate,
Sequence: 13,
},
{
AggregateType: org_model.OrgAggregate,
Sequence: 142,
},
{
AggregateType: org_model.OrgAggregate,
Sequence: 1234,
Type: org_model.OrgMemberAdded,
Data: []byte(`{"userId":"hodor"}`),
},
},
member: &OrgMember{UserID: "hodor"},
},
res: res{
isErr: errors.IsPreconditionFailed,
},
},
{
name: "only user events",
args: args{
aggregate: &es_models.Aggregate{},
events: []*es_models.Event{
{
AggregateType: usr_model.UserAggregate,
Sequence: 13,
},
{
AggregateType: usr_model.UserAggregate,
Sequence: 142,
},
},
member: &OrgMember{UserID: "hodor"},
},
res: res{
isErr: errors.IsPreconditionFailed,
},
},
{
name: "user, org events success",
args: args{
aggregate: &es_models.Aggregate{},
events: []*es_models.Event{
{
AggregateType: usr_model.UserAggregate,
Sequence: 13,
},
{
AggregateType: org_model.OrgAggregate,
Sequence: 142,
},
},
member: &OrgMember{UserID: "hodor"},
},
res: res{
isErr: nil,
preivousSequence: 142,
},
},
{
name: "user, org and member events success",
args: args{
aggregate: &es_models.Aggregate{},
events: []*es_models.Event{
{
AggregateType: usr_model.UserAggregate,
Sequence: 13,
},
{
AggregateType: org_model.OrgAggregate,
Sequence: 142,
},
{
AggregateType: org_model.OrgAggregate,
Sequence: 1234,
Type: org_model.OrgMemberAdded,
Data: []byte(`{"userId":"hodor"}`),
},
{
AggregateType: org_model.OrgAggregate,
Sequence: 1236,
Type: org_model.OrgMemberRemoved,
Data: []byte(`{"userId":"hodor"}`),
},
},
member: &OrgMember{UserID: "hodor"},
},
res: res{
isErr: nil,
preivousSequence: 1236,
},
},
{
name: "user, org and member added events fail",
args: args{
aggregate: &es_models.Aggregate{},
events: []*es_models.Event{
{
AggregateType: usr_model.UserAggregate,
Sequence: 13,
},
{
AggregateType: org_model.OrgAggregate,
Sequence: 142,
},
{
AggregateType: org_model.OrgAggregate,
Sequence: 1234,
Type: org_model.OrgMemberAdded,
Data: []byte(`{"userId":"hodor"}`),
},
},
member: &OrgMember{UserID: "hodor"},
},
res: res{
isErr: errors.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
validaiton := addMemberValidation(tt.args.aggregate, tt.args.member)
err := validaiton(tt.args.events...)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && tt.args.aggregate.PreviousSequence != tt.res.preivousSequence {
t.Errorf("wrong previous sequence got: %d want %d", tt.args.aggregate.PreviousSequence, tt.res.preivousSequence)
}
})
}
}

View File

@ -0,0 +1,160 @@
package eventsourcing
import (
"encoding/json"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
)
const (
orgVersion = "v1"
)
type Org struct {
es_models.ObjectRoot `json:"-"`
Name string `json:"name,omitempty"`
Domain string `json:"domain,omitempty"`
State int32 `json:"-"`
Members []*OrgMember `json:"-"`
}
func OrgFromModel(org *org_model.Org) *Org {
members := OrgMembersFromModel(org.Members)
return &Org{
ObjectRoot: org.ObjectRoot,
Domain: org.Domain,
Name: org.Name,
State: int32(org.State),
Members: members,
}
}
func OrgToModel(org *Org) *org_model.Org {
return &org_model.Org{
ObjectRoot: org.ObjectRoot,
Domain: org.Domain,
Name: org.Name,
State: org_model.OrgState(org.State),
Members: OrgMembersToModel(org.Members),
}
}
func OrgFromEvents(org *Org, events ...*es_models.Event) (*Org, error) {
if org == nil {
org = new(Org)
}
return org, org.AppendEvents(events...)
}
func (o *Org) AppendEvents(events ...*es_models.Event) error {
for _, event := range events {
err := o.AppendEvent(event)
if err != nil {
return err
}
}
return nil
}
func (o *Org) AppendEvent(event *es_models.Event) error {
switch event.Type {
case org_model.OrgAdded:
*o = Org{}
err := o.setData(event)
if err != nil {
return err
}
case org_model.OrgChanged:
err := o.setData(event)
if err != nil {
return err
}
case org_model.OrgDeactivated:
o.State = int32(org_model.ORGSTATE_INACTIVE)
case org_model.OrgReactivated:
o.State = int32(org_model.ORGSTATE_ACTIVE)
case org_model.OrgMemberAdded:
member, err := OrgMemberFromEvent(nil, event)
if err != nil {
return err
}
member.CreationDate = event.CreationDate
o.setMember(member)
case org_model.OrgMemberChanged:
member, err := OrgMemberFromEvent(nil, event)
if err != nil {
return err
}
existingMember := o.getMember(member.UserID)
member.CreationDate = existingMember.CreationDate
o.setMember(member)
case org_model.OrgMemberRemoved:
member, err := OrgMemberFromEvent(nil, event)
if err != nil {
return err
}
o.removeMember(member.UserID)
}
o.ObjectRoot.AppendEvent(event)
return nil
}
func (o *Org) setData(event *es_models.Event) error {
err := json.Unmarshal(event.Data, o)
if err != nil {
return errors.ThrowInternal(err, "EVENT-BpbQZ", "unable to unmarshal event")
}
return nil
}
func (o *Org) getMember(userID string) *OrgMember {
for _, member := range o.Members {
if member.UserID == userID {
return member
}
}
return nil
}
func (o *Org) setMember(member *OrgMember) {
for i, existingMember := range o.Members {
if existingMember.UserID == member.UserID {
o.Members[i] = member
return
}
}
o.Members = append(o.Members, member)
}
func (o *Org) removeMember(userID string) {
for i := len(o.Members) - 1; i >= 0; i-- {
if o.Members[i].UserID == userID {
copy(o.Members[i:], o.Members[i+1:])
o.Members[len(o.Members)-1] = nil
o.Members = o.Members[:len(o.Members)-1]
}
}
}
func (o *Org) Changes(changed *Org) map[string]interface{} {
changes := make(map[string]interface{}, 2)
if changed.Name != "" && changed.Name != o.Name {
changes["name"] = changed.Name
}
if changed.Domain != "" && changed.Domain != o.Domain {
changes["domain"] = changed.Domain
}
return changes
}

View File

@ -0,0 +1,170 @@
package eventsourcing
import (
"encoding/json"
"testing"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/org/model"
)
func TestOrgFromEvents(t *testing.T) {
type args struct {
event []*es_models.Event
org *Org
}
tests := []struct {
name string
args args
result *Org
}{
{
name: "org from events, ok",
args: args{
event: []*es_models.Event{
{AggregateID: "ID", Sequence: 1, Type: model.OrgAdded},
},
org: &Org{Name: "OrgName"},
},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName"},
},
{
name: "org from events, nil org",
args: args{
event: []*es_models.Event{
{AggregateID: "ID", Sequence: 1, Type: model.OrgAdded},
},
org: nil,
},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.org != nil {
data, _ := json.Marshal(tt.args.org)
tt.args.event[0].Data = data
}
result, _ := OrgFromEvents(tt.args.org, tt.args.event...)
if result.Name != tt.result.Name {
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, result.Name)
}
})
}
}
func TestAppendEvent(t *testing.T) {
type args struct {
event *es_models.Event
org *Org
}
tests := []struct {
name string
args args
result *Org
}{
{
name: "append added event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgAdded},
org: &Org{Name: "OrgName"},
},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName"},
},
{
name: "append change event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgChanged, Data: []byte(`{"domain": "OrgDomain"}`)},
org: &Org{Name: "OrgName", Domain: "asdf"},
},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName", Domain: "OrgDomain"},
},
{
name: "append deactivate event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgDeactivated},
},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_INACTIVE)},
},
{
name: "append reactivate event",
args: args{
event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgReactivated},
},
result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.org != nil {
data, _ := json.Marshal(tt.args.org)
tt.args.event.Data = data
}
result := &Org{}
result.AppendEvent(tt.args.event)
if result.State != tt.result.State {
t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.State, result.State)
}
if result.Name != tt.result.Name {
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.result.Name, result.Name)
}
if result.ObjectRoot.AggregateID != tt.result.ObjectRoot.AggregateID {
t.Errorf("got wrong result id: expected: %v, actual: %v ", tt.result.ObjectRoot.AggregateID, result.ObjectRoot.AggregateID)
}
})
}
}
func TestChanges(t *testing.T) {
type args struct {
existing *Org
new *Org
}
type res struct {
changesLen int
}
tests := []struct {
name string
args args
res res
}{
{
name: "org name changes",
args: args{
existing: &Org{Name: "Name"},
new: &Org{Name: "NameChanged"},
},
res: res{
changesLen: 1,
},
},
{
name: "org domain changes",
args: args{
existing: &Org{Name: "Name", Domain: "old domain"},
new: &Org{Name: "Name", Domain: "new domain"},
},
res: res{
changesLen: 1,
},
},
{
name: "no changes",
args: args{
existing: &Org{Name: "Name"},
new: &Org{Name: "Name"},
},
res: res{
changesLen: 0,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
changes := tt.args.existing.Changes(tt.args.new)
if len(changes) != tt.res.changesLen {
t.Errorf("got wrong changes len: expected: %v, actual: %v ", tt.res.changesLen, len(changes))
}
})
}
}

View File

@ -0,0 +1,585 @@
package eventsourcing
import (
"context"
"testing"
"github.com/caos/zitadel/internal/api/auth"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
org_model "github.com/caos/zitadel/internal/org/model"
)
func Test_isReservedValidation(t *testing.T) {
type res struct {
isErr func(error) bool
agggregateSequence uint64
}
type args struct {
aggregate *es_models.Aggregate
eventType es_models.EventType
Events []*es_models.Event
}
tests := []struct {
name string
args args
res res
}{
{
name: "no events success",
args: args{
aggregate: &es_models.Aggregate{},
eventType: "object.reserved",
Events: []*es_models.Event{},
},
res: res{
isErr: nil,
agggregateSequence: 0,
},
},
{
name: "not reseved success",
args: args{
aggregate: &es_models.Aggregate{},
eventType: "object.reserved",
Events: []*es_models.Event{
{
AggregateID: "asdf",
AggregateType: "org",
Sequence: 45,
Type: "object.released",
},
},
},
res: res{
isErr: nil,
agggregateSequence: 45,
},
},
{
name: "reseved error",
args: args{
aggregate: &es_models.Aggregate{},
eventType: "object.reserved",
Events: []*es_models.Event{
{
AggregateID: "asdf",
AggregateType: "org",
Sequence: 45,
Type: "object.reserved",
},
},
},
res: res{
isErr: errors.IsPreconditionFailed,
agggregateSequence: 0,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
validate := isReservedValidation(tt.args.aggregate, tt.args.eventType)
err := validate(tt.args.Events...)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got: %v", err)
}
if err == nil && tt.args.aggregate.PreviousSequence != tt.res.agggregateSequence {
t.Errorf("expected sequence %d got %d", tt.res.agggregateSequence, tt.args.aggregate.PreviousSequence)
}
})
}
}
func aggregateWithPrecondition() *es_models.Aggregate {
return nil
}
func Test_uniqueNameAggregate(t *testing.T) {
type res struct {
expected *es_models.Aggregate
isErr func(error) bool
}
type args struct {
ctx context.Context
aggCreator *es_models.AggregateCreator
orgName string
}
tests := []struct {
name string
args args
res res
}{
{
name: "no org name error",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
aggCreator: es_models.NewAggregateCreator("test"),
orgName: "",
},
res: res{
expected: nil,
isErr: errors.IsPreconditionFailed,
},
},
{
name: "aggregate created",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
aggCreator: es_models.NewAggregateCreator("test"),
orgName: "asdf",
},
res: res{
expected: aggregateWithPrecondition(),
isErr: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := uniqueNameAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.orgName)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && (got.Precondition == nil || got.Precondition.Query == nil || got.Precondition.Validation == nil) {
t.Errorf("precondition is not set correctly")
}
})
}
}
func Test_uniqueDomainAggregate(t *testing.T) {
type res struct {
expected *es_models.Aggregate
isErr func(error) bool
}
type args struct {
ctx context.Context
aggCreator *es_models.AggregateCreator
orgDomain string
}
tests := []struct {
name string
args args
res res
}{
{
name: "no org domain error",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
aggCreator: es_models.NewAggregateCreator("test"),
orgDomain: "",
},
res: res{
expected: nil,
isErr: errors.IsPreconditionFailed,
},
},
{
name: "aggregate created",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
aggCreator: es_models.NewAggregateCreator("test"),
orgDomain: "asdf",
},
res: res{
expected: aggregateWithPrecondition(),
isErr: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := uniqueDomainAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.orgDomain)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && (got.Precondition == nil || got.Precondition.Query == nil || got.Precondition.Validation == nil) {
t.Errorf("precondition is not set correctly")
}
})
}
}
func TestOrgReactivateAggregate(t *testing.T) {
type res struct {
isErr func(error) bool
}
type args struct {
aggCreator *es_models.AggregateCreator
org *Org
ctx context.Context
}
tests := []struct {
name string
args args
res res
}{
{
name: "correct",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
org: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "orgID",
Sequence: 2,
},
State: int32(org_model.ORGSTATE_INACTIVE),
},
},
},
{
name: "already active error",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
org: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "orgID",
Sequence: 2,
},
State: int32(org_model.ORGSTATE_ACTIVE),
},
},
res: res{
isErr: errors.IsErrorInvalidArgument,
},
},
{
name: "org nil error",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
org: nil,
},
res: res{
isErr: errors.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
aggregateCreator := orgReactivateAggregate(tt.args.aggCreator, tt.args.org)
aggregate, err := aggregateCreator(tt.args.ctx)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && aggregate == nil {
t.Error("aggregate must not be nil")
}
})
}
}
func TestOrgDeactivateAggregate(t *testing.T) {
type res struct {
isErr func(error) bool
}
type args struct {
aggCreator *es_models.AggregateCreator
org *Org
ctx context.Context
}
tests := []struct {
name string
args args
res res
}{
{
name: "correct",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
org: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "orgID",
Sequence: 2,
},
State: int32(org_model.ORGSTATE_ACTIVE),
},
},
},
{
name: "already inactive error",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
org: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "orgID",
Sequence: 2,
},
State: int32(org_model.ORGSTATE_INACTIVE),
},
},
res: res{
isErr: errors.IsErrorInvalidArgument,
},
},
{
name: "org nil error",
args: args{
aggCreator: es_models.NewAggregateCreator("test"),
ctx: auth.NewMockContext("org", "user"),
org: nil,
},
res: res{
isErr: errors.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
aggregateCreator := orgDeactivateAggregate(tt.args.aggCreator, tt.args.org)
aggregate, err := aggregateCreator(tt.args.ctx)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && aggregate == nil {
t.Error("aggregate must not be nil")
}
})
}
}
func TestOrgUpdateAggregates(t *testing.T) {
type res struct {
aggregateCount int
isErr func(error) bool
}
type args struct {
ctx context.Context
aggCreator *es_models.AggregateCreator
existing *Org
updated *Org
}
tests := []struct {
name string
args args
res res
}{
{
name: "no existing org error",
args: args{
ctx: auth.NewMockContext("org", "user"),
aggCreator: es_models.NewAggregateCreator("test"),
existing: nil,
updated: &Org{},
},
res: res{
aggregateCount: 0,
isErr: errors.IsPreconditionFailed,
},
},
{
name: "no updated org error",
args: args{
ctx: auth.NewMockContext("org", "user"),
aggCreator: es_models.NewAggregateCreator("test"),
existing: &Org{},
updated: nil,
},
res: res{
aggregateCount: 0,
isErr: errors.IsPreconditionFailed,
},
},
{
name: "no changes",
args: args{
ctx: auth.NewMockContext("org", "user"),
aggCreator: es_models.NewAggregateCreator("test"),
existing: &Org{},
updated: &Org{},
},
res: res{
aggregateCount: 0,
isErr: errors.IsPreconditionFailed,
},
},
{
name: "name changed",
args: args{
ctx: auth.NewMockContext("org", "user"),
aggCreator: es_models.NewAggregateCreator("test"),
existing: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "sdaf",
Sequence: 5,
},
Domain: "caos.ch",
Name: "coas",
},
updated: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "sdaf",
Sequence: 5,
},
Domain: "caos.ch",
Name: "caos",
},
},
res: res{
aggregateCount: 2,
isErr: nil,
},
},
{
name: "domain changed",
args: args{
ctx: auth.NewMockContext("org", "user"),
aggCreator: es_models.NewAggregateCreator("test"),
existing: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "sdaf",
Sequence: 5,
},
Domain: "caos.swiss",
Name: "caos",
},
updated: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "sdaf",
Sequence: 5,
},
Domain: "caos.ch",
Name: "caos",
},
},
res: res{
aggregateCount: 2,
isErr: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := OrgUpdateAggregates(tt.args.ctx, tt.args.aggCreator, tt.args.existing, tt.args.updated)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got: %v", err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && len(got) != tt.res.aggregateCount {
t.Errorf("OrgUpdateAggregates() aggregate count = %d, wanted count %d", len(got), tt.res.aggregateCount)
}
})
}
}
func TestOrgCreatedAggregates(t *testing.T) {
type res struct {
aggregateCount int
isErr func(error) bool
}
type args struct {
ctx context.Context
aggCreator *es_models.AggregateCreator
org *Org
}
tests := []struct {
name string
args args
res res
}{
{
name: "no org error",
args: args{
ctx: auth.NewMockContext("org", "user"),
aggCreator: es_models.NewAggregateCreator("test"),
org: nil,
},
res: res{
aggregateCount: 0,
isErr: errors.IsPreconditionFailed,
},
},
{
name: "org successful",
args: args{
ctx: auth.NewMockContext("org", "user"),
aggCreator: es_models.NewAggregateCreator("test"),
org: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "sdaf",
Sequence: 5,
},
Domain: "caos.ch",
Name: "caos",
},
},
res: res{
aggregateCount: 3,
isErr: nil,
},
},
{
name: "no domain error",
args: args{
ctx: auth.NewMockContext("org", "user"),
aggCreator: es_models.NewAggregateCreator("test"),
org: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "sdaf",
Sequence: 5,
},
Name: "caos",
},
},
res: res{
aggregateCount: 2,
isErr: errors.IsPreconditionFailed,
},
},
{
name: "no name error",
args: args{
ctx: auth.NewMockContext("org", "user"),
aggCreator: es_models.NewAggregateCreator("test"),
org: &Org{
ObjectRoot: es_models.ObjectRoot{
AggregateID: "sdaf",
Sequence: 5,
},
Domain: "caos.ch",
},
},
res: res{
aggregateCount: 2,
isErr: errors.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := orgCreatedAggregates(tt.args.ctx, tt.args.aggCreator, tt.args.org)
if tt.res.isErr == nil && err != nil {
t.Errorf("no error expected got %T: %v", err, err)
}
if tt.res.isErr != nil && !tt.res.isErr(err) {
t.Errorf("wrong error got %T: %v", err, err)
}
if tt.res.isErr == nil && len(got) != tt.res.aggregateCount {
t.Errorf("OrgUpdateAggregates() aggregate count = %d, wanted count %d", len(got), tt.res.aggregateCount)
}
})
}
}

View File

@ -0,0 +1,10 @@
package repository
import es_models "github.com/caos/zitadel/internal/eventstore/models"
type Org struct {
es_models.ObjectRoot
Name string
Domain string
}

View File

@ -1,9 +1,10 @@
package model
import (
"time"
"github.com/caos/zitadel/internal/crypto"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"time"
)
type User struct {
@ -92,26 +93,26 @@ func (u *User) HashPasswordIfExisting(passwordAlg crypto.HashAlgorithm, onetime
}
func (u *User) GenerateInitCodeIfNeeded(initGenerator crypto.Generator) error {
u.InitCode = new(InitUserCode)
if !u.IsInitialState() {
return nil
}
u.InitCode = new(InitUserCode)
return u.InitCode.GenerateInitUserCode(initGenerator)
}
func (u *User) GeneratePhoneCodeIfNeeded(phoneGenerator crypto.Generator) error {
u.PhoneCode = new(PhoneCode)
if u.Phone == nil || u.IsPhoneVerified {
return nil
}
u.PhoneCode = new(PhoneCode)
return u.PhoneCode.GeneratePhoneCode(phoneGenerator)
}
func (u *User) GenerateEmailCodeIfNeeded(emailGenerator crypto.Generator) error {
u.EmailCode = new(EmailCode)
if u.Email == nil || u.IsEmailVerified {
return nil
}
u.EmailCode = new(EmailCode)
return u.EmailCode.GenerateEmailCode(emailGenerator)
}

View File

@ -2,18 +2,20 @@ package eventsourcing
import (
"context"
"strconv"
"github.com/caos/zitadel/internal/cache/config"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/crypto"
caos_errs "github.com/caos/zitadel/internal/errors"
es_int "github.com/caos/zitadel/internal/eventstore"
es_models "github.com/caos/zitadel/internal/eventstore/models"
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
global_model "github.com/caos/zitadel/internal/model"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
"github.com/pquerna/otp/totp"
"github.com/sony/sonyflake"
"strconv"
)
type UserEventstore struct {
@ -49,6 +51,7 @@ func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventsto
phoneVerificationCode := crypto.NewEncryptionGenerator(systemDefaults.SecretGenerators.PhoneVerificationCode, aesCrypto)
passwordVerificationCode := crypto.NewEncryptionGenerator(systemDefaults.SecretGenerators.PasswordVerificationCode, aesCrypto)
aesOtpCrypto, err := crypto.NewAESCrypto(systemDefaults.Multifactors.OTP.VerificationKey)
passwordAlg := crypto.NewBCrypt(systemDefaults.SecretGenerators.PasswordSaltCost)
if err != nil {
return nil, err
}
@ -67,6 +70,7 @@ func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventsto
PhoneVerificationCode: phoneVerificationCode,
PasswordVerificationCode: passwordVerificationCode,
Multifactors: mfa,
PasswordAlg: passwordAlg,
}, nil
}
@ -85,37 +89,47 @@ func (es *UserEventstore) UserByID(ctx context.Context, id string) (*usr_model.U
return model.UserToModel(user), nil
}
func (es *UserEventstore) CreateUser(ctx context.Context, user *usr_model.User) (*usr_model.User, error) {
func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model.User, resourceOwner string) (*model.User, *es_models.Aggregate, error) {
user.SetEmailAsUsername()
if !user.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Name is required")
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Name is required")
}
//TODO: Check Uniqueness
id, err := es.idGenerator.NextID()
if err != nil {
return nil, err
return nil, nil, err
}
user.AggregateID = strconv.FormatUint(id, 10)
err = user.HashPasswordIfExisting(es.PasswordAlg, true)
if err != nil {
return nil, err
return nil, nil, err
}
err = user.GenerateInitCodeIfNeeded(es.InitializeUserCode)
if err != nil {
return nil, err
return nil, nil, err
}
err = user.GeneratePhoneCodeIfNeeded(es.PhoneVerificationCode)
if err != nil {
return nil, err
return nil, nil, err
}
repoUser := model.UserFromModel(user)
repoInitCode := model.InitCodeFromModel(user.InitCode)
repoPhoneCode := model.PhoneCodeFromModel(user.PhoneCode)
createAggregate := UserCreateAggregate(es.AggregateCreator(), repoUser, repoInitCode, repoPhoneCode)
err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, createAggregate)
createAggregate, err := UserCreateAggregate(ctx, es.AggregateCreator(), repoUser, repoInitCode, repoPhoneCode, resourceOwner)
return repoUser, createAggregate, err
}
func (es *UserEventstore) CreateUser(ctx context.Context, user *usr_model.User) (*usr_model.User, error) {
repoUser, aggregate, err := es.PrepareCreateUser(ctx, user, "")
if err != nil {
return nil, err
}
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoUser.AppendEvents, aggregate)
if err != nil {
return nil, err
}
@ -124,32 +138,41 @@ func (es *UserEventstore) CreateUser(ctx context.Context, user *usr_model.User)
return model.UserToModel(repoUser), nil
}
func (es *UserEventstore) RegisterUser(ctx context.Context, user *usr_model.User, resourceOwner string) (*usr_model.User, error) {
func (es *UserEventstore) PrepareRegisterUser(ctx context.Context, user *usr_model.User, resourceOwner string) (*model.User, *es_models.Aggregate, error) {
user.SetEmailAsUsername()
if !user.IsValid() || user.Password == nil || user.SecretString == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "user is invalid")
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "user is invalid")
}
//TODO: Check Uniqueness
id, err := es.idGenerator.NextID()
if err != nil {
return nil, err
return nil, nil, err
}
user.AggregateID = strconv.FormatUint(id, 10)
err = user.HashPasswordIfExisting(es.PasswordAlg, false)
if err != nil {
return nil, err
return nil, nil, err
}
err = user.GenerateEmailCodeIfNeeded(es.EmailVerificationCode)
if err != nil {
return nil, err
return nil, nil, err
}
repoUser := model.UserFromModel(user)
repoEmailCode := model.EmailCodeFromModel(user.EmailCode)
createAggregate := UserRegisterAggregate(es.AggregateCreator(), repoUser, resourceOwner, repoEmailCode)
err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, createAggregate)
aggregate, err := UserRegisterAggregate(ctx, es.AggregateCreator(), repoUser, resourceOwner, repoEmailCode)
return repoUser, aggregate, err
}
func (es *UserEventstore) RegisterUser(ctx context.Context, user *usr_model.User, resourceOwner string) (*usr_model.User, error) {
repoUser, createAggregate, err := es.PrepareRegisterUser(ctx, user, resourceOwner)
if err != nil {
return nil, err
}
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoUser.AppendEvents, createAggregate)
if err != nil {
return nil, err
}

View File

@ -2,12 +2,13 @@ package model
import (
"encoding/json"
"time"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/crypto"
caos_errs "github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/user/model"
"time"
)
const (
@ -22,11 +23,11 @@ type User struct {
*Email
*Phone
*Address
InitCode *InitUserCode
EmailCode *EmailCode
PhoneCode *PhoneCode
PasswordCode *PasswordCode
OTP *OTP
InitCode *InitUserCode `json:"-"`
EmailCode *EmailCode `json:"-"`
PhoneCode *PhoneCode `json:"-"`
PasswordCode *PasswordCode `json:"-"`
OTP *OTP `json:"-"`
}
type InitUserCode struct {

View File

@ -2,6 +2,7 @@ package eventsourcing
import (
"context"
"github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
@ -36,72 +37,72 @@ func UserAggregateOverwriteContext(ctx context.Context, aggCreator *es_models.Ag
return aggCreator.NewAggregate(ctx, user.AggregateID, model.UserAggregate, model.UserVersion, user.Sequence, es_models.OverwriteResourceOwner(resourceOwnerID), es_models.OverwriteEditorUser(userID))
}
func UserCreateAggregate(aggCreator *es_models.AggregateCreator, user *model.User, initCode *model.InitUserCode, phoneCode *model.PhoneCode) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if user == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "user should not be nil")
}
agg, err := UserAggregate(ctx, aggCreator, user)
if err != nil {
return nil, err
}
agg, err = agg.AppendEvent(model.UserAdded, user)
if err != nil {
return nil, err
}
if user.Email != nil && user.EmailAddress != "" && user.IsEmailVerified {
agg, err = agg.AppendEvent(model.UserEmailVerified, nil)
if err != nil {
return nil, err
}
}
if user.Phone != nil && user.PhoneNumber != "" && user.IsPhoneVerified {
agg, err = agg.AppendEvent(model.UserPhoneVerified, nil)
if err != nil {
return nil, err
}
}
if user.Password != nil {
agg, err = agg.AppendEvent(model.UserPasswordCodeAdded, user.Password)
if err != nil {
return nil, err
}
}
if initCode != nil {
agg, err = agg.AppendEvent(model.InitializedUserCodeAdded, initCode)
if err != nil {
return nil, err
}
}
if phoneCode != nil {
agg, err = agg.AppendEvent(model.UserPhoneCodeAdded, phoneCode)
if err != nil {
return nil, err
}
}
return agg, err
func UserCreateAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, initCode *model.InitUserCode, phoneCode *model.PhoneCode, resourceOwner string) (agg *es_models.Aggregate, err error) {
if user == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "user should not be nil")
}
if resourceOwner != "" {
agg, err = UserAggregateOverwriteContext(ctx, aggCreator, user, user.AggregateID, resourceOwner)
} else {
agg, err = UserAggregate(ctx, aggCreator, user)
}
if err != nil {
return nil, err
}
agg, err = agg.AppendEvent(model.UserAdded, user)
if err != nil {
return nil, err
}
if user.Email != nil && user.EmailAddress != "" && user.IsEmailVerified {
agg, err = agg.AppendEvent(model.UserEmailVerified, nil)
if err != nil {
return nil, err
}
}
if user.Phone != nil && user.PhoneNumber != "" && user.IsPhoneVerified {
agg, err = agg.AppendEvent(model.UserPhoneVerified, nil)
if err != nil {
return nil, err
}
}
if user.Password != nil {
agg, err = agg.AppendEvent(model.UserPasswordCodeAdded, user.Password)
if err != nil {
return nil, err
}
}
if initCode != nil {
agg, err = agg.AppendEvent(model.InitializedUserCodeAdded, initCode)
if err != nil {
return nil, err
}
}
if phoneCode != nil {
agg, err = agg.AppendEvent(model.UserPhoneCodeAdded, phoneCode)
if err != nil {
return nil, err
}
}
return agg, err
}
func UserRegisterAggregate(aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, emailCode *model.EmailCode) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if user == nil || resourceOwner == "" || emailCode == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "user, resourceowner, emailcode should not be nothing")
}
agg, err := UserAggregateOverwriteContext(ctx, aggCreator, user, resourceOwner, user.AggregateID)
if err != nil {
return nil, err
}
agg, err = agg.AppendEvent(model.UserRegistered, user)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.UserEmailCodeAdded, emailCode)
func UserRegisterAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, user *model.User, resourceOwner string, emailCode *model.EmailCode) (*es_models.Aggregate, error) {
if user == nil || resourceOwner == "" || emailCode == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-duxk2", "user, resourceowner, emailcode should not be nothing")
}
agg, err := UserAggregateOverwriteContext(ctx, aggCreator, user, resourceOwner, user.AggregateID)
if err != nil {
return nil, err
}
agg, err = agg.AppendEvent(model.UserRegistered, user)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.UserEmailCodeAdded, emailCode)
}
func UserDeactivateAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {

View File

@ -2,12 +2,13 @@ package eventsourcing
import (
"context"
"testing"
"time"
"github.com/caos/zitadel/internal/api/auth"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
"testing"
"time"
)
func TestUserByIDQuery(t *testing.T) {
@ -212,7 +213,7 @@ func TestUserCreateAggregate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := UserCreateAggregate(tt.args.aggCreator, tt.args.new, tt.args.initCode, tt.args.phoneCode)(tt.args.ctx)
agg, err := UserCreateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.initCode, tt.args.phoneCode, "")
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
@ -329,7 +330,7 @@ func TestUserRegisterAggregate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := UserRegisterAggregate(tt.args.aggCreator, tt.args.new, tt.args.resourceOwner, tt.args.emailCode)(tt.args.ctx)
agg, err := UserRegisterAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.resourceOwner, tt.args.emailCode)
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))

View File

@ -0,0 +1,8 @@
BEGIN;
CREATE USER admin_api;
GRANT SELECT, INSERT, UPDATE ON DATABASE eventstore TO admin_api;
GRANT SELECT, INSERT, UPDATE ON TABLE eventstore.* TO admin_api;
COMMIT;

View File

@ -2,16 +2,22 @@ package admin
import (
"context"
app "github.com/caos/zitadel/internal/admin"
sd "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/admin/repository/eventsourcing"
"github.com/caos/zitadel/internal/api/auth"
"github.com/caos/zitadel/pkg/admin/api"
)
type Config struct {
App app.Config
API api.Config
Repository eventsourcing.Config
API api.Config
}
func Start(ctx context.Context, config Config, authZ auth.Config) {
api.Start(ctx, config.API)
func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) {
repo, err := eventsourcing.Start(config.Repository, systemDefaults)
logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app")
api.Start(ctx, config.API, authZ, repo)
}

View File

@ -2,6 +2,9 @@ package api
import (
"context"
"github.com/caos/zitadel/internal/admin/repository"
"github.com/caos/zitadel/internal/api/auth"
grpc_util "github.com/caos/zitadel/internal/api/grpc"
"github.com/caos/zitadel/internal/api/grpc/server"
"github.com/caos/zitadel/pkg/admin/api/grpc"
@ -11,8 +14,8 @@ type Config struct {
GRPC grpc_util.Config
}
func Start(ctx context.Context, conf Config) {
grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig())
func Start(ctx context.Context, conf Config, authZ auth.Config, repo repository.Repository) {
grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo)
grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig())
server.StartServer(ctx, grpcServer)

View File

@ -583,11 +583,11 @@ func (m *OrgSearchResponse) GetResult() []*Org {
}
type OrgSetUpRequest struct {
Org *CreateOrgRequest `protobuf:"bytes,1,opt,name=org,proto3" json:"org,omitempty"`
User *RegisterUserRequest `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Org *CreateOrgRequest `protobuf:"bytes,1,opt,name=org,proto3" json:"org,omitempty"`
User *CreateUserRequest `protobuf:"bytes,2,opt,name=user,proto3" json:"user,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *OrgSetUpRequest) Reset() { *m = OrgSetUpRequest{} }
@ -622,7 +622,7 @@ func (m *OrgSetUpRequest) GetOrg() *CreateOrgRequest {
return nil
}
func (m *OrgSetUpRequest) GetUser() *RegisterUserRequest {
func (m *OrgSetUpRequest) GetUser() *CreateUserRequest {
if m != nil {
return m.User
}
@ -676,105 +676,169 @@ func (m *OrgSetUpResponse) GetUser() *User {
return nil
}
type RegisterUserRequest struct {
Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"`
type CreateUserRequest struct {
UserName string `protobuf:"bytes,1,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"`
FirstName string `protobuf:"bytes,2,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"`
LastName string `protobuf:"bytes,3,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"`
NickName string `protobuf:"bytes,4,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"`
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
PreferredLanguage string `protobuf:"bytes,6,opt,name=preferred_language,json=preferredLanguage,proto3" json:"preferred_language,omitempty"`
Gender Gender `protobuf:"varint,7,opt,name=gender,proto3,enum=zitadel.admin.api.v1.Gender" json:"gender,omitempty"`
Password string `protobuf:"bytes,8,opt,name=password,proto3" json:"password,omitempty"`
OrgId string `protobuf:"bytes,9,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"`
Email string `protobuf:"bytes,8,opt,name=email,proto3" json:"email,omitempty"`
IsEmailVerified bool `protobuf:"varint,9,opt,name=is_email_verified,json=isEmailVerified,proto3" json:"is_email_verified,omitempty"`
Phone string `protobuf:"bytes,11,opt,name=phone,proto3" json:"phone,omitempty"`
IsPhoneVerified bool `protobuf:"varint,12,opt,name=is_phone_verified,json=isPhoneVerified,proto3" json:"is_phone_verified,omitempty"`
Country string `protobuf:"bytes,13,opt,name=country,proto3" json:"country,omitempty"`
Locality string `protobuf:"bytes,14,opt,name=locality,proto3" json:"locality,omitempty"`
PostalCode string `protobuf:"bytes,15,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"`
Region string `protobuf:"bytes,16,opt,name=region,proto3" json:"region,omitempty"`
StreetAddress string `protobuf:"bytes,17,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"`
Password string `protobuf:"bytes,18,opt,name=password,proto3" json:"password,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RegisterUserRequest) Reset() { *m = RegisterUserRequest{} }
func (m *RegisterUserRequest) String() string { return proto.CompactTextString(m) }
func (*RegisterUserRequest) ProtoMessage() {}
func (*RegisterUserRequest) Descriptor() ([]byte, []int) {
func (m *CreateUserRequest) Reset() { *m = CreateUserRequest{} }
func (m *CreateUserRequest) String() string { return proto.CompactTextString(m) }
func (*CreateUserRequest) ProtoMessage() {}
func (*CreateUserRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_73a7fc70dcc2027c, []int{9}
}
func (m *RegisterUserRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RegisterUserRequest.Unmarshal(m, b)
func (m *CreateUserRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CreateUserRequest.Unmarshal(m, b)
}
func (m *RegisterUserRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RegisterUserRequest.Marshal(b, m, deterministic)
func (m *CreateUserRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CreateUserRequest.Marshal(b, m, deterministic)
}
func (m *RegisterUserRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_RegisterUserRequest.Merge(m, src)
func (m *CreateUserRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_CreateUserRequest.Merge(m, src)
}
func (m *RegisterUserRequest) XXX_Size() int {
return xxx_messageInfo_RegisterUserRequest.Size(m)
func (m *CreateUserRequest) XXX_Size() int {
return xxx_messageInfo_CreateUserRequest.Size(m)
}
func (m *RegisterUserRequest) XXX_DiscardUnknown() {
xxx_messageInfo_RegisterUserRequest.DiscardUnknown(m)
func (m *CreateUserRequest) XXX_DiscardUnknown() {
xxx_messageInfo_CreateUserRequest.DiscardUnknown(m)
}
var xxx_messageInfo_RegisterUserRequest proto.InternalMessageInfo
var xxx_messageInfo_CreateUserRequest proto.InternalMessageInfo
func (m *RegisterUserRequest) GetEmail() string {
func (m *CreateUserRequest) GetUserName() string {
if m != nil {
return m.Email
return m.UserName
}
return ""
}
func (m *RegisterUserRequest) GetFirstName() string {
func (m *CreateUserRequest) GetFirstName() string {
if m != nil {
return m.FirstName
}
return ""
}
func (m *RegisterUserRequest) GetLastName() string {
func (m *CreateUserRequest) GetLastName() string {
if m != nil {
return m.LastName
}
return ""
}
func (m *RegisterUserRequest) GetNickName() string {
func (m *CreateUserRequest) GetNickName() string {
if m != nil {
return m.NickName
}
return ""
}
func (m *RegisterUserRequest) GetDisplayName() string {
func (m *CreateUserRequest) GetDisplayName() string {
if m != nil {
return m.DisplayName
}
return ""
}
func (m *RegisterUserRequest) GetPreferredLanguage() string {
func (m *CreateUserRequest) GetPreferredLanguage() string {
if m != nil {
return m.PreferredLanguage
}
return ""
}
func (m *RegisterUserRequest) GetGender() Gender {
func (m *CreateUserRequest) GetGender() Gender {
if m != nil {
return m.Gender
}
return Gender_GENDER_UNSPECIFIED
}
func (m *RegisterUserRequest) GetPassword() string {
func (m *CreateUserRequest) GetEmail() string {
if m != nil {
return m.Password
return m.Email
}
return ""
}
func (m *RegisterUserRequest) GetOrgId() string {
func (m *CreateUserRequest) GetIsEmailVerified() bool {
if m != nil {
return m.OrgId
return m.IsEmailVerified
}
return false
}
func (m *CreateUserRequest) GetPhone() string {
if m != nil {
return m.Phone
}
return ""
}
func (m *CreateUserRequest) GetIsPhoneVerified() bool {
if m != nil {
return m.IsPhoneVerified
}
return false
}
func (m *CreateUserRequest) GetCountry() string {
if m != nil {
return m.Country
}
return ""
}
func (m *CreateUserRequest) GetLocality() string {
if m != nil {
return m.Locality
}
return ""
}
func (m *CreateUserRequest) GetPostalCode() string {
if m != nil {
return m.PostalCode
}
return ""
}
func (m *CreateUserRequest) GetRegion() string {
if m != nil {
return m.Region
}
return ""
}
func (m *CreateUserRequest) GetStreetAddress() string {
if m != nil {
return m.StreetAddress
}
return ""
}
func (m *CreateUserRequest) GetPassword() string {
if m != nil {
return m.Password
}
return ""
}
@ -800,6 +864,7 @@ type User struct {
PostalCode string `protobuf:"bytes,18,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"`
Region string `protobuf:"bytes,19,opt,name=region,proto3" json:"region,omitempty"`
StreetAddress string `protobuf:"bytes,20,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"`
Sequence uint64 `protobuf:"varint,21,opt,name=sequence,proto3" json:"sequence,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -970,6 +1035,13 @@ func (m *User) GetStreetAddress() string {
return ""
}
func (m *User) GetSequence() uint64 {
if m != nil {
return m.Sequence
}
return 0
}
type CreateOrgRequest struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
@ -1032,7 +1104,7 @@ func init() {
proto.RegisterType((*OrgSearchResponse)(nil), "zitadel.admin.api.v1.OrgSearchResponse")
proto.RegisterType((*OrgSetUpRequest)(nil), "zitadel.admin.api.v1.OrgSetUpRequest")
proto.RegisterType((*OrgSetUpResponse)(nil), "zitadel.admin.api.v1.OrgSetUpResponse")
proto.RegisterType((*RegisterUserRequest)(nil), "zitadel.admin.api.v1.RegisterUserRequest")
proto.RegisterType((*CreateUserRequest)(nil), "zitadel.admin.api.v1.CreateUserRequest")
proto.RegisterType((*User)(nil), "zitadel.admin.api.v1.User")
proto.RegisterType((*CreateOrgRequest)(nil), "zitadel.admin.api.v1.CreateOrgRequest")
}
@ -1040,112 +1112,119 @@ func init() {
func init() { proto.RegisterFile("admin.proto", fileDescriptor_73a7fc70dcc2027c) }
var fileDescriptor_73a7fc70dcc2027c = []byte{
// 1667 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4f, 0x73, 0x1b, 0x49,
0x15, 0xcf, 0xe8, 0x9f, 0x47, 0x4f, 0xfe, 0x33, 0xee, 0x78, 0x9d, 0x59, 0x39, 0xbb, 0xf6, 0x0e,
0x9b, 0x90, 0xd5, 0x12, 0x69, 0x23, 0x96, 0x2a, 0xca, 0xd4, 0x2e, 0x25, 0x5b, 0xb3, 0x8e, 0x2a,
0xb6, 0xe4, 0x1d, 0xc9, 0xe1, 0xcf, 0x45, 0x4c, 0x34, 0xed, 0x51, 0x93, 0xd1, 0xcc, 0xa4, 0xbb,
0x95, 0xa0, 0xa5, 0x38, 0x90, 0x2a, 0x2e, 0x1c, 0x38, 0xc0, 0x81, 0x4f, 0xc0, 0x99, 0x13, 0x57,
0xbe, 0x04, 0x1f, 0x80, 0x0b, 0x55, 0x5c, 0x38, 0x70, 0xe1, 0xb2, 0x27, 0xaa, 0xbb, 0x47, 0xb2,
0x46, 0x96, 0x62, 0x52, 0x5c, 0xf6, 0x64, 0xf5, 0xef, 0xf7, 0x7b, 0xaf, 0x5f, 0xbf, 0x7e, 0xfd,
0xa6, 0xdb, 0x50, 0x72, 0xbd, 0x11, 0x09, 0xab, 0x31, 0x8d, 0x78, 0x84, 0x76, 0xbe, 0x22, 0xdc,
0xf5, 0x70, 0x50, 0x55, 0xa0, 0x1b, 0x93, 0xea, 0xcb, 0x47, 0xe5, 0xbb, 0x7e, 0x14, 0xf9, 0x01,
0xae, 0xb9, 0x31, 0xa9, 0xb9, 0x61, 0x18, 0x71, 0x97, 0x93, 0x28, 0x64, 0xca, 0xa6, 0xbc, 0x97,
0xb0, 0x72, 0xf4, 0x6c, 0x7c, 0x59, 0xc3, 0xa3, 0x98, 0x4f, 0x12, 0x72, 0x7f, 0x91, 0xe4, 0x64,
0x84, 0x19, 0x77, 0x47, 0x71, 0x22, 0xb8, 0xbb, 0x28, 0x60, 0x9c, 0x8e, 0x07, 0x3c, 0x61, 0xef,
0xbc, 0x74, 0x03, 0xe2, 0xb9, 0x1c, 0xd7, 0xa6, 0x3f, 0x12, 0xe2, 0x3b, 0xf2, 0xcf, 0xe0, 0xa1,
0x8f, 0xc3, 0x87, 0xec, 0x95, 0xeb, 0xfb, 0x98, 0xd6, 0xa2, 0x58, 0x86, 0xb5, 0x24, 0x44, 0xd3,
0x1d, 0xf3, 0xa1, 0xa2, 0xa7, 0x2a, 0xc5, 0x58, 0x77, 0x20, 0xdf, 0xa1, 0x7e, 0xab, 0x89, 0x36,
0x21, 0x43, 0x3c, 0x53, 0x3b, 0xd0, 0x1e, 0x14, 0x9d, 0x0c, 0xf1, 0xac, 0x73, 0x30, 0x2e, 0x42,
0xf2, 0x62, 0x8c, 0x3b, 0xd4, 0x77, 0xf0, 0x8b, 0x31, 0x66, 0x1c, 0xed, 0x41, 0x2e, 0x74, 0x47,
0x58, 0xa9, 0x8e, 0xd6, 0xbe, 0x3e, 0xca, 0xd1, 0x8c, 0xa1, 0x39, 0x12, 0x44, 0xfb, 0x50, 0xf0,
0xa2, 0x91, 0x4b, 0x42, 0x33, 0x93, 0xa6, 0x13, 0xd8, 0xfa, 0x04, 0xb6, 0xe7, 0x3c, 0xb2, 0x38,
0x0a, 0x19, 0x46, 0x7b, 0x50, 0x24, 0xac, 0x3f, 0x96, 0xb8, 0xf4, 0xab, 0x3b, 0x3a, 0x61, 0x4a,
0x67, 0xfd, 0x47, 0x83, 0x6c, 0x87, 0xfa, 0x8b, 0xb1, 0xa1, 0x4f, 0x21, 0xcf, 0xb8, 0xcb, 0xb1,
0x9c, 0x69, 0xb3, 0xfe, 0x7e, 0x75, 0xd9, 0xae, 0x55, 0x3b, 0xd4, 0xef, 0x0a, 0x95, 0xa3, 0xc4,
0xe8, 0x87, 0xb0, 0x31, 0xa0, 0x58, 0xe6, 0xa5, 0x2f, 0x32, 0x69, 0x66, 0x0f, 0xb4, 0x07, 0xa5,
0x7a, 0xb9, 0xaa, 0x76, 0xa0, 0x3a, 0xdd, 0x81, 0x6a, 0x6f, 0xba, 0x45, 0xce, 0xfa, 0xd4, 0xa0,
0x29, 0x1c, 0xfc, 0x00, 0x4a, 0x83, 0xa1, 0x1b, 0xfa, 0x58, 0x99, 0xe7, 0x6e, 0x34, 0x07, 0x25,
0x97, 0xc6, 0x28, 0xc9, 0x5d, 0x5e, 0xae, 0x42, 0xa5, 0x6c, 0x77, 0x96, 0xb2, 0x82, 0x44, 0xa7,
0x99, 0xfa, 0xa7, 0x06, 0x86, 0x88, 0x1e, 0xbb, 0x74, 0x30, 0x9c, 0x26, 0x7f, 0x17, 0x0a, 0xd1,
0xe5, 0x25, 0xc3, 0x5c, 0x26, 0x22, 0xe7, 0x24, 0x23, 0xb4, 0x03, 0xf9, 0x80, 0x8c, 0x08, 0x97,
0xc9, 0xc8, 0x39, 0x6a, 0x80, 0xba, 0xb0, 0xc9, 0x22, 0xca, 0x49, 0xe8, 0xf7, 0x07, 0x51, 0x30,
0x1e, 0x85, 0x72, 0xb5, 0x9b, 0x75, 0x6b, 0x75, 0xae, 0xe4, 0x6c, 0x4f, 0xf0, 0xe4, 0x48, 0xff,
0xfa, 0x28, 0xff, 0x5a, 0xcb, 0x1c, 0xdc, 0x72, 0x36, 0x12, 0x1f, 0xc7, 0xd2, 0x05, 0x32, 0x20,
0xeb, 0xb2, 0x81, 0x5c, 0xb8, 0xee, 0x88, 0x9f, 0xe8, 0x73, 0x58, 0x7b, 0x31, 0xc6, 0x94, 0x60,
0x66, 0xe6, 0x0f, 0xb2, 0x0f, 0x4a, 0xf5, 0x0f, 0x6f, 0xf0, 0xff, 0xe5, 0x18, 0xd3, 0x89, 0x33,
0x35, 0xb2, 0xfe, 0xa4, 0xc1, 0x66, 0x9a, 0x43, 0x9f, 0x43, 0xf6, 0x39, 0x9e, 0xc8, 0x45, 0xbe,
0x6d, 0xb8, 0xc2, 0x10, 0x7d, 0x06, 0x85, 0x11, 0xe6, 0xc3, 0xc8, 0x4b, 0xaa, 0xe3, 0xde, 0x0d,
0x2e, 0xce, 0xa4, 0xd8, 0x49, 0x8c, 0x44, 0x3a, 0x5f, 0xba, 0xc1, 0x58, 0x55, 0x47, 0xd1, 0x51,
0x03, 0xeb, 0x8f, 0x1a, 0x6c, 0xcf, 0xed, 0x48, 0x52, 0xbc, 0x6f, 0xb7, 0x25, 0x1f, 0xc0, 0x3a,
0x8f, 0xb8, 0x1b, 0xf4, 0x29, 0x66, 0xe3, 0x80, 0xcb, 0x09, 0x72, 0x4e, 0x49, 0x62, 0x8e, 0x84,
0xd0, 0x23, 0x28, 0x24, 0x64, 0x4e, 0x66, 0xf3, 0xdd, 0x95, 0xb1, 0x3b, 0x89, 0xd0, 0xfa, 0xad,
0x06, 0x5b, 0x32, 0x32, 0x7e, 0x11, 0x4f, 0x4b, 0xe5, 0xfb, 0x90, 0x8d, 0xa8, 0x2f, 0x83, 0x2a,
0xd5, 0xef, 0x2f, 0xf7, 0x71, 0x2c, 0x2a, 0x7b, 0xee, 0x70, 0x3b, 0xc2, 0x04, 0x7d, 0x06, 0xb9,
0x31, 0xc3, 0x54, 0x06, 0x5e, 0xaa, 0x7f, 0xb4, 0xdc, 0xd4, 0xc1, 0x3e, 0x61, 0x1c, 0xd3, 0x0b,
0x86, 0xe9, 0xd4, 0x5a, 0x9a, 0x59, 0x51, 0x52, 0xb7, 0x32, 0x96, 0x24, 0x49, 0x1f, 0xcf, 0x07,
0xf3, 0x86, 0x05, 0xc9, 0xf9, 0xab, 0xa9, 0xf9, 0xcb, 0xcb, 0xd5, 0x72, 0x5e, 0x35, 0xe1, 0xbf,
0x32, 0x70, 0x7b, 0x49, 0x38, 0xe8, 0x3d, 0xc8, 0xe3, 0x91, 0x4b, 0x82, 0x54, 0xab, 0xfa, 0x99,
0xe6, 0x28, 0x14, 0xdd, 0x07, 0xb8, 0x24, 0x94, 0xf1, 0xbe, 0x3c, 0x92, 0x0b, 0xfd, 0xaa, 0x28,
0xa9, 0xb6, 0x38, 0xa0, 0x1f, 0x42, 0x31, 0x70, 0xa7, 0xb2, 0x6c, 0x5a, 0xa6, 0x0b, 0x46, 0xaa,
0xf6, 0xa0, 0x18, 0x92, 0xc1, 0x73, 0xa5, 0xca, 0xc9, 0xb2, 0xd1, 0x05, 0x20, 0xc9, 0x0f, 0x60,
0xdd, 0x23, 0x2c, 0x0e, 0xdc, 0x49, 0x7f, 0xee, 0xfc, 0x97, 0x12, 0x4c, 0x4a, 0x1e, 0x02, 0x8a,
0x29, 0xbe, 0xc4, 0x94, 0x62, 0xaf, 0x1f, 0xb8, 0xa1, 0x3f, 0x76, 0x7d, 0x9c, 0xb4, 0x84, 0xed,
0x19, 0x73, 0x9a, 0x10, 0xe8, 0x53, 0x28, 0xf8, 0x38, 0xf4, 0x30, 0x35, 0xd7, 0x64, 0x81, 0xdf,
0x5d, 0x9e, 0xa5, 0x13, 0xa9, 0x71, 0x12, 0x2d, 0xfa, 0x16, 0xe8, 0xb1, 0xcb, 0xd8, 0xab, 0x88,
0x7a, 0xa6, 0xbe, 0xb0, 0x92, 0x29, 0x81, 0xde, 0x87, 0x42, 0x44, 0xfd, 0x3e, 0xf1, 0xcc, 0x62,
0x5a, 0x92, 0x8f, 0xa8, 0xdf, 0xf2, 0xac, 0xbf, 0xe7, 0x21, 0x27, 0xd2, 0x7c, 0xad, 0x23, 0x7f,
0x2f, 0xdd, 0x91, 0xf7, 0x57, 0x6f, 0xdc, 0x37, 0xa8, 0x25, 0xef, 0x41, 0x51, 0x14, 0xd1, 0xfc,
0xbe, 0xe8, 0x02, 0x90, 0x9b, 0xf2, 0x5e, 0xaa, 0x44, 0xd4, 0x66, 0xcc, 0x55, 0xc6, 0xde, 0x7c,
0x65, 0xac, 0x29, 0xdb, 0xe5, 0x05, 0xa1, 0xdf, 0x50, 0x10, 0xc5, 0xff, 0xb5, 0x20, 0xe0, 0xe6,
0x82, 0x28, 0xbd, 0x45, 0x41, 0xec, 0x4c, 0x8f, 0xc8, 0xba, 0x6a, 0x74, 0xea, 0x64, 0x3c, 0x80,
0x2d, 0xc2, 0x6c, 0xf1, 0xf3, 0x29, 0xa6, 0xe4, 0x92, 0x60, 0xcf, 0xdc, 0x90, 0xed, 0x7e, 0x11,
0x16, 0xf6, 0xf1, 0x30, 0x0a, 0xb1, 0xb9, 0xa9, 0xec, 0xe5, 0x40, 0xd9, 0x9f, 0x8b, 0x9f, 0x33,
0xfb, 0xad, 0xa9, 0x7d, 0x0a, 0x46, 0x26, 0xac, 0x0d, 0xa2, 0x71, 0xc8, 0xe9, 0xc4, 0x34, 0xa4,
0x87, 0xe9, 0x10, 0x95, 0x41, 0x0f, 0xa2, 0x81, 0x1b, 0x10, 0x3e, 0x31, 0xb7, 0x93, 0xd4, 0x26,
0x63, 0xb4, 0x0f, 0xa5, 0x38, 0x62, 0xa2, 0x8b, 0x0e, 0x22, 0x0f, 0x9b, 0x48, 0xd2, 0xa0, 0xa0,
0xe3, 0xc8, 0x93, 0x3d, 0x99, 0x62, 0x9f, 0x44, 0xa1, 0x79, 0x5b, 0x7d, 0x53, 0xd5, 0x08, 0xdd,
0x83, 0x4d, 0xc6, 0x29, 0xc6, 0xbc, 0xef, 0x7a, 0x1e, 0xc5, 0x8c, 0x99, 0x3b, 0x92, 0xdf, 0x50,
0x68, 0x43, 0x81, 0xe2, 0xda, 0xb3, 0xd8, 0x19, 0xff, 0xbf, 0x6b, 0x4f, 0xe5, 0x1c, 0xf4, 0xe9,
0x4d, 0x04, 0x99, 0xb0, 0xd3, 0x71, 0x4e, 0xba, 0xbd, 0x46, 0xcf, 0xee, 0x5f, 0xb4, 0xbb, 0xe7,
0xf6, 0x71, 0xeb, 0x8b, 0x96, 0xdd, 0x34, 0x6e, 0xa1, 0xdb, 0xb0, 0x35, 0x63, 0x1a, 0xc7, 0xbd,
0xd6, 0x53, 0xdb, 0xd0, 0xd0, 0x3b, 0xb0, 0x3d, 0x03, 0x5b, 0xed, 0x04, 0xce, 0x54, 0x7e, 0x01,
0xeb, 0xf3, 0x1f, 0x40, 0x74, 0x17, 0x4c, 0x21, 0xb3, 0x1b, 0xce, 0xf1, 0xe3, 0x27, 0xf6, 0x4f,
0x16, 0x3c, 0xbf, 0x0b, 0xef, 0xa4, 0xd8, 0x8e, 0x73, 0xd2, 0x6f, 0x37, 0xce, 0x84, 0xff, 0x3b,
0x70, 0x3b, 0x45, 0x35, 0x3b, 0x67, 0x8d, 0x56, 0xdb, 0xc8, 0xa0, 0x5d, 0x40, 0x29, 0x42, 0x86,
0x60, 0x64, 0x2b, 0x41, 0xf2, 0xad, 0xb9, 0xfa, 0x6e, 0xa2, 0x32, 0xec, 0xce, 0xa4, 0x67, 0x76,
0xef, 0x71, 0xa7, 0xd9, 0xb7, 0xbf, 0xbc, 0x68, 0x9c, 0x76, 0x8d, 0x5b, 0x68, 0x1f, 0xf6, 0x16,
0xb9, 0x6e, 0xaf, 0xe1, 0xf4, 0xba, 0xfd, 0x1f, 0xb5, 0x7a, 0x8f, 0x0d, 0x2d, 0x15, 0x79, 0x22,
0x38, 0xee, 0xb4, 0x7b, 0x8d, 0x56, 0xbb, 0x6b, 0x64, 0x2a, 0x7f, 0xd6, 0xa0, 0x38, 0x6b, 0x19,
0x62, 0x1d, 0x17, 0x5d, 0xdb, 0x59, 0x96, 0xbc, 0x1d, 0x30, 0xae, 0xa8, 0x59, 0xf6, 0x76, 0x01,
0x5d, 0xa1, 0x57, 0xe9, 0x13, 0x59, 0xbd, 0xc2, 0x9b, 0xf6, 0xa9, 0xdd, 0xb3, 0x9b, 0x46, 0x36,
0xed, 0xe4, 0xb4, 0x73, 0xfc, 0xc4, 0x6e, 0x1a, 0xb9, 0xb4, 0xb8, 0x7b, 0xd1, 0x3d, 0xb7, 0xdb,
0x4d, 0x23, 0x9f, 0x86, 0x5b, 0xed, 0x56, 0xaf, 0xd5, 0x38, 0x35, 0x0a, 0x95, 0x1f, 0x43, 0x41,
0x9d, 0x32, 0x31, 0xf9, 0x89, 0xdd, 0x6e, 0xda, 0xce, 0x42, 0xa8, 0xdb, 0xb0, 0x91, 0xe0, 0x5f,
0xd8, 0x67, 0x8d, 0x53, 0x11, 0xe7, 0x16, 0x94, 0x12, 0x48, 0x02, 0x19, 0x84, 0x60, 0x33, 0x01,
0x9a, 0xad, 0xa7, 0xb6, 0xd3, 0xb5, 0x8d, 0x6c, 0xfd, 0xdf, 0x79, 0x58, 0x6f, 0x88, 0xd3, 0xdc,
0xc5, 0xf4, 0x25, 0x19, 0x60, 0xf4, 0x04, 0xd6, 0x1e, 0x63, 0x37, 0xe0, 0xc3, 0xaf, 0xd0, 0xee,
0xb5, 0x7e, 0x67, 0x8b, 0x17, 0x48, 0x79, 0x05, 0x6e, 0x19, 0xaf, 0xff, 0xf6, 0x8f, 0x3f, 0x64,
0x00, 0xe9, 0xb5, 0x61, 0xe2, 0xe1, 0x04, 0xf2, 0x0e, 0x76, 0xbd, 0xc9, 0x5b, 0xbb, 0xda, 0x94,
0xae, 0x74, 0x54, 0xa8, 0x51, 0x69, 0xdf, 0x06, 0xfd, 0x69, 0xf2, 0x50, 0x59, 0xe9, 0xeb, 0xce,
0x35, 0xbc, 0x2b, 0x9f, 0x3c, 0xd6, 0xb6, 0x74, 0x56, 0x42, 0xc5, 0xd9, 0x63, 0x07, 0xfd, 0x46,
0x83, 0x52, 0x8b, 0x75, 0xa8, 0xaf, 0x5e, 0x04, 0x68, 0xc5, 0x65, 0x66, 0xf1, 0xa5, 0x52, 0xfe,
0xf6, 0x8d, 0x3a, 0x75, 0x3b, 0xb1, 0xee, 0xbd, 0xfe, 0x8b, 0x09, 0xa0, 0x13, 0x77, 0x54, 0x15,
0x2b, 0x90, 0x11, 0x6c, 0xa3, 0xad, 0x5a, 0x44, 0x7d, 0x56, 0xeb, 0x13, 0xa6, 0x5e, 0x26, 0xe8,
0x12, 0xe0, 0x04, 0xf3, 0x0e, 0xf5, 0x8f, 0x26, 0xad, 0x26, 0xda, 0x5b, 0x79, 0x8b, 0x69, 0x35,
0xcb, 0xab, 0xaf, 0x38, 0xd6, 0xc1, 0x92, 0xc9, 0xd6, 0x11, 0xa8, 0xc9, 0x7e, 0x49, 0xbc, 0x5f,
0x89, 0xf5, 0x82, 0x3a, 0x5e, 0x1d, 0xea, 0xb3, 0x55, 0xcb, 0x5d, 0x7c, 0x1b, 0xac, 0x5a, 0xee,
0xb5, 0x1b, 0xab, 0x75, 0x7f, 0x49, 0x04, 0xc8, 0xda, 0x48, 0x96, 0xcb, 0xa4, 0xf8, 0x50, 0xab,
0xa0, 0x5f, 0x6b, 0xa0, 0xcb, 0x6b, 0x9c, 0x78, 0x7e, 0xbd, 0xe9, 0x06, 0x7d, 0x75, 0xeb, 0x2c,
0xdf, 0xbf, 0x49, 0x36, 0x17, 0x43, 0x09, 0x8a, 0x22, 0x86, 0x57, 0x94, 0x70, 0xac, 0x72, 0x6e,
0xad, 0xcf, 0x82, 0xe0, 0xe3, 0xf8, 0x50, 0xab, 0x1c, 0xfd, 0x55, 0xfb, 0x7d, 0xe3, 0x77, 0x1a,
0x6a, 0xc0, 0x86, 0xf4, 0x77, 0xc0, 0x54, 0xe5, 0x5b, 0x1f, 0xa3, 0x8f, 0x86, 0x9c, 0xc7, 0xec,
0xb0, 0x56, 0xf3, 0x09, 0x1f, 0x8e, 0x9f, 0x55, 0x07, 0xd1, 0xa8, 0x36, 0x70, 0x23, 0x56, 0x4b,
0x02, 0xa8, 0xc5, 0xcf, 0xfd, 0x9a, 0x34, 0xaa, 0x67, 0x3f, 0xa9, 0x3e, 0xaa, 0x68, 0x99, 0xba,
0xe1, 0xc6, 0x71, 0x40, 0x06, 0xf2, 0xe6, 0x50, 0xfb, 0x39, 0x8b, 0xc2, 0x34, 0xe2, 0xd3, 0x78,
0x70, 0x78, 0x4d, 0x73, 0x78, 0x4d, 0xf3, 0xd3, 0xca, 0x8d, 0x53, 0xca, 0xff, 0x12, 0x08, 0xed,
0xb3, 0x82, 0x2c, 0xf0, 0xef, 0xfe, 0x37, 0x00, 0x00, 0xff, 0xff, 0x70, 0xfd, 0x92, 0x95, 0x62,
0x10, 0x00, 0x00,
// 1785 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4b, 0x73, 0x1b, 0x59,
0x15, 0x4e, 0xeb, 0x65, 0xe9, 0x48, 0x96, 0x5b, 0x37, 0x8e, 0xd3, 0x23, 0x67, 0xb0, 0xa7, 0x99,
0xbc, 0x14, 0x22, 0x4d, 0xc4, 0x50, 0x50, 0x9e, 0x62, 0x28, 0xd9, 0xea, 0xb1, 0x55, 0xb1, 0x25,
0x4f, 0x4b, 0x0e, 0x8f, 0x8d, 0xe8, 0xa8, 0xaf, 0x5b, 0x4d, 0xa4, 0xee, 0xce, 0xbd, 0x2d, 0x07,
0x85, 0x62, 0x41, 0xaa, 0xa8, 0x62, 0xc5, 0x02, 0x16, 0xfc, 0x02, 0xd6, 0xac, 0xd8, 0xb2, 0x66,
0xcf, 0x92, 0x2d, 0x55, 0x6c, 0xd9, 0xb0, 0x09, 0x1b, 0xea, 0x3e, 0x5a, 0x6f, 0xc5, 0xe5, 0x62,
0xc3, 0xca, 0xea, 0xf3, 0x7d, 0xe7, 0xdc, 0x73, 0xcf, 0x3d, 0xdf, 0x7d, 0x18, 0xb2, 0x96, 0x3d,
0x74, 0xbd, 0x72, 0x40, 0xfc, 0xd0, 0x47, 0xdb, 0x6f, 0xdd, 0xd0, 0xb2, 0xf1, 0xa0, 0x2c, 0x8c,
0x56, 0xe0, 0x96, 0xaf, 0x9e, 0x15, 0xef, 0x39, 0xbe, 0xef, 0x0c, 0x70, 0xc5, 0x0a, 0xdc, 0x8a,
0xe5, 0x79, 0x7e, 0x68, 0x85, 0xae, 0xef, 0x51, 0xe1, 0x53, 0xdc, 0x95, 0x28, 0xff, 0x7a, 0x39,
0xba, 0xac, 0xe0, 0x61, 0x10, 0x8e, 0x25, 0xb8, 0xb7, 0x08, 0x86, 0xee, 0x10, 0xd3, 0xd0, 0x1a,
0x06, 0x92, 0x70, 0x6f, 0x91, 0x40, 0x43, 0x32, 0xea, 0x85, 0x12, 0xbd, 0x7b, 0x65, 0x0d, 0x5c,
0xdb, 0x0a, 0x71, 0x25, 0xfa, 0x21, 0x81, 0x6f, 0xf1, 0x3f, 0xbd, 0xa7, 0x0e, 0xf6, 0x9e, 0xd2,
0x37, 0x96, 0xe3, 0x60, 0x52, 0xf1, 0x03, 0x9e, 0xd6, 0x8a, 0x14, 0x35, 0x6b, 0x14, 0xf6, 0x05,
0x1c, 0xb1, 0x04, 0xa2, 0xdf, 0x85, 0x64, 0x8b, 0x38, 0x8d, 0x3a, 0xca, 0x43, 0xcc, 0xb5, 0x35,
0x65, 0x5f, 0x79, 0x94, 0x31, 0x63, 0xae, 0xad, 0x9f, 0x83, 0x7a, 0xe1, 0xb9, 0xaf, 0x47, 0xb8,
0x45, 0x1c, 0x13, 0xbf, 0x1e, 0x61, 0x1a, 0xa2, 0x5d, 0x48, 0x78, 0xd6, 0x10, 0x0b, 0xd6, 0xe1,
0xc6, 0xfb, 0xc3, 0x04, 0x89, 0xa9, 0x8a, 0xc9, 0x8d, 0x68, 0x0f, 0x52, 0xb6, 0x3f, 0xb4, 0x5c,
0x4f, 0x8b, 0xcd, 0xc3, 0xd2, 0xac, 0x7f, 0x06, 0x85, 0x99, 0x88, 0x34, 0xf0, 0x3d, 0x8a, 0xd1,
0x2e, 0x64, 0x5c, 0xda, 0x1d, 0x71, 0x3b, 0x8f, 0x9b, 0x36, 0xd3, 0x2e, 0x15, 0x3c, 0xfd, 0xdf,
0x0a, 0xc4, 0x5b, 0xc4, 0x59, 0xcc, 0x0d, 0x7d, 0x0e, 0x49, 0x1a, 0x5a, 0x21, 0xe6, 0x23, 0xe5,
0xab, 0xdf, 0x28, 0xaf, 0x5a, 0xb5, 0x72, 0x8b, 0x38, 0x6d, 0xc6, 0x32, 0x05, 0x19, 0xfd, 0x00,
0x36, 0x7b, 0x04, 0xf3, 0xba, 0x74, 0x59, 0x25, 0xb5, 0xf8, 0xbe, 0xf2, 0x28, 0x5b, 0x2d, 0x96,
0xc5, 0x0a, 0x94, 0xa3, 0x15, 0x28, 0x77, 0xa2, 0x25, 0x32, 0x73, 0x91, 0x43, 0x9d, 0x05, 0xf8,
0x02, 0xb2, 0xbd, 0xbe, 0xe5, 0x39, 0x58, 0xb8, 0x27, 0xae, 0x75, 0x07, 0x41, 0xe7, 0xce, 0x48,
0xd6, 0x2e, 0xc9, 0x67, 0x21, 0x4a, 0xb6, 0x33, 0x29, 0x59, 0x8a, 0x5b, 0xa3, 0x4a, 0xfd, 0x53,
0x01, 0x95, 0x65, 0x8f, 0x2d, 0xd2, 0xeb, 0x47, 0xc5, 0xdf, 0x81, 0x94, 0x7f, 0x79, 0x49, 0x71,
0xc8, 0x0b, 0x91, 0x30, 0xe5, 0x17, 0xda, 0x86, 0xe4, 0xc0, 0x1d, 0xba, 0x21, 0x2f, 0x46, 0xc2,
0x14, 0x1f, 0xa8, 0x0d, 0x79, 0xea, 0x93, 0xd0, 0xf5, 0x9c, 0x6e, 0xcf, 0x1f, 0x8c, 0x86, 0x1e,
0x9f, 0x6d, 0xbe, 0xaa, 0xaf, 0xaf, 0x15, 0x1f, 0xed, 0x39, 0x1e, 0x1f, 0xa6, 0xdf, 0x1f, 0x26,
0xdf, 0x29, 0xb1, 0xfd, 0x5b, 0xe6, 0xa6, 0x8c, 0x71, 0xc4, 0x43, 0x20, 0x15, 0xe2, 0x16, 0xed,
0xf1, 0x89, 0xa7, 0x4d, 0xf6, 0x13, 0x7d, 0x09, 0x1b, 0xaf, 0x47, 0x98, 0xb8, 0x98, 0x6a, 0xc9,
0xfd, 0xf8, 0xa3, 0x6c, 0xf5, 0xd3, 0x6b, 0xe2, 0x7f, 0x3d, 0xc2, 0x64, 0x6c, 0x46, 0x4e, 0xfa,
0x1f, 0x15, 0xc8, 0xcf, 0x63, 0xe8, 0x4b, 0x88, 0xbf, 0xc2, 0x63, 0x3e, 0xc9, 0x9b, 0xa6, 0xcb,
0x1c, 0xd1, 0xf7, 0x21, 0x35, 0xc4, 0x61, 0xdf, 0xb7, 0x65, 0x77, 0xdc, 0xbf, 0x26, 0xc4, 0x19,
0x27, 0x9b, 0xd2, 0x89, 0x95, 0xf3, 0xca, 0x1a, 0x8c, 0x44, 0x77, 0x64, 0x4c, 0xf1, 0xa1, 0xff,
0x41, 0x81, 0xc2, 0xcc, 0x8a, 0xc8, 0xe6, 0xbd, 0xd9, 0x92, 0x7c, 0x02, 0xb9, 0xd0, 0x0f, 0xad,
0x41, 0x97, 0x60, 0x3a, 0x1a, 0x84, 0x7c, 0x80, 0x84, 0x99, 0xe5, 0x36, 0x93, 0x9b, 0xd0, 0x33,
0x48, 0x49, 0x30, 0xc1, 0xab, 0xf9, 0xd1, 0xda, 0xdc, 0x4d, 0x49, 0xd4, 0x7f, 0xa3, 0xc0, 0x16,
0xcf, 0x2c, 0xbc, 0x08, 0xa2, 0x56, 0xf9, 0x1e, 0xc4, 0x7d, 0xe2, 0xf0, 0xa4, 0xb2, 0xd5, 0x07,
0xab, 0x63, 0x1c, 0xb1, 0xce, 0x9e, 0x11, 0xb7, 0xc9, 0x5c, 0xd0, 0x17, 0x90, 0x18, 0x51, 0x4c,
0x78, 0xe2, 0xd9, 0xea, 0xc3, 0x0f, 0xb9, 0x5e, 0x50, 0x4c, 0x22, 0x5f, 0xee, 0xa4, 0xfb, 0xb2,
0x6b, 0x79, 0x26, 0xb2, 0x44, 0x4f, 0x66, 0x53, 0xf9, 0xc0, 0x74, 0xf8, 0xe8, 0xe5, 0xb9, 0xd1,
0x8b, 0xab, 0xd9, 0x7c, 0x5c, 0x31, 0xe0, 0xdf, 0x93, 0x50, 0x58, 0x4a, 0x06, 0x3d, 0x84, 0x0c,
0x43, 0xbb, 0x33, 0x5b, 0x15, 0xbc, 0x3f, 0xdc, 0x20, 0x49, 0x55, 0xd1, 0xfe, 0xaa, 0x98, 0x69,
0x06, 0x36, 0x99, 0xfc, 0x1e, 0x03, 0x5c, 0xba, 0x84, 0x86, 0x82, 0x19, 0x5b, 0x62, 0x66, 0x38,
0xca, 0xa9, 0x0f, 0x21, 0x33, 0xb0, 0x22, 0x66, 0x7c, 0x39, 0x26, 0x03, 0x39, 0xf1, 0x3e, 0x64,
0x3c, 0xb7, 0xf7, 0x4a, 0x10, 0x13, 0x9c, 0xc8, 0xfa, 0x93, 0xc4, 0x39, 0x8d, 0x41, 0x9c, 0xf6,
0x04, 0x72, 0xb6, 0x4b, 0x83, 0x81, 0x35, 0xee, 0x4e, 0x77, 0x85, 0x19, 0x66, 0x56, 0xa2, 0x9c,
0xfc, 0x5d, 0x40, 0x01, 0xc1, 0x97, 0x98, 0x10, 0x6c, 0x77, 0x07, 0x96, 0xe7, 0x8c, 0x2c, 0x07,
0x8b, 0x2d, 0x63, 0xc6, 0xa5, 0x30, 0xe1, 0x9c, 0x4a, 0x0a, 0xfa, 0x1c, 0x52, 0x0e, 0xf6, 0x6c,
0x4c, 0xb4, 0x0d, 0x2e, 0x85, 0x7b, 0xab, 0x2b, 0x7a, 0xcc, 0x39, 0xa6, 0xe4, 0x22, 0x1d, 0x92,
0x78, 0x68, 0xb9, 0x03, 0x2d, 0xcd, 0x47, 0xc8, 0xbd, 0x3f, 0xcc, 0x90, 0x0d, 0x3e, 0xcf, 0x9f,
0x2a, 0xa6, 0x80, 0x50, 0x09, 0x0a, 0x2e, 0xed, 0xf2, 0xdf, 0xdd, 0x2b, 0x4c, 0xdc, 0x4b, 0x17,
0xdb, 0x5a, 0x86, 0xef, 0x0b, 0x5b, 0x2e, 0x35, 0x98, 0xfd, 0x85, 0x34, 0xa3, 0x8f, 0x21, 0x19,
0xf4, 0x7d, 0x0f, 0x6b, 0xd9, 0x99, 0x73, 0x41, 0xdb, 0x36, 0x85, 0x55, 0x86, 0xe2, 0xbf, 0xa7,
0xa1, 0x72, 0x51, 0xa8, 0x73, 0x66, 0x9f, 0x84, 0xd2, 0x61, 0xa3, 0xe7, 0x8f, 0xbc, 0x90, 0x8c,
0xb5, 0xcd, 0x85, 0xe9, 0x47, 0x00, 0xfa, 0x14, 0xd2, 0x03, 0xbf, 0x67, 0x0d, 0xdc, 0x70, 0xac,
0xe5, 0x17, 0x17, 0x20, 0x42, 0xd0, 0x63, 0xc8, 0x06, 0x3e, 0x65, 0x6a, 0xec, 0xf9, 0x36, 0xd6,
0xb6, 0x16, 0x88, 0x20, 0xc0, 0x23, 0xdf, 0xc6, 0x68, 0x9f, 0x89, 0xd2, 0x71, 0x7d, 0x4f, 0x53,
0x17, 0x58, 0xd2, 0x8e, 0x2a, 0x90, 0xa7, 0x21, 0xc1, 0x38, 0xec, 0x5a, 0xb6, 0x4d, 0x30, 0xa5,
0x5a, 0x61, 0x81, 0xb9, 0x29, 0xf0, 0x9a, 0x80, 0xd1, 0x37, 0x21, 0x1d, 0x58, 0x94, 0xbe, 0xf1,
0x89, 0xad, 0xa1, 0xd9, 0xaa, 0x9c, 0x98, 0x13, 0x40, 0xff, 0x4f, 0x12, 0x12, 0xac, 0xaf, 0x97,
0x8e, 0xbf, 0xef, 0xcc, 0x1f, 0x7f, 0x7b, 0xeb, 0x75, 0xf2, 0x7f, 0x74, 0xfe, 0xed, 0xce, 0xaa,
0x52, 0x1c, 0x82, 0x53, 0x25, 0x7e, 0x3c, 0xa7, 0x44, 0x71, 0x18, 0xce, 0xa8, 0x6f, 0x77, 0x56,
0x7d, 0x1b, 0xc2, 0x77, 0xa2, 0xb8, 0xdd, 0x59, 0xc5, 0xa5, 0x05, 0x38, 0xd1, 0xd9, 0x27, 0x0b,
0x3a, 0xcb, 0x70, 0x7c, 0x4e, 0x5d, 0x4f, 0x57, 0xaa, 0x0b, 0x38, 0xf1, 0x83, 0x9a, 0xca, 0xde,
0x40, 0x53, 0xdb, 0x91, 0xa6, 0x72, 0xe2, 0x54, 0x11, 0x2a, 0x7a, 0x04, 0x8b, 0x62, 0xe1, 0x6d,
0xbd, 0x42, 0x43, 0xdb, 0x91, 0x86, 0xf2, 0xc2, 0x5f, 0x48, 0x87, 0xfb, 0xcf, 0x29, 0x84, 0x37,
0xf2, 0x0a, 0xe1, 0x68, 0x53, 0xe1, 0xf0, 0x26, 0x9e, 0xca, 0xa5, 0x38, 0x23, 0x97, 0x82, 0x2c,
0x6d, 0x24, 0x92, 0xbd, 0x79, 0x91, 0xf0, 0x4e, 0x9d, 0x93, 0xc6, 0xce, 0x44, 0x1a, 0xb7, 0xc5,
0x05, 0x46, 0x0a, 0xe2, 0xfe, 0x92, 0x20, 0xb6, 0x39, 0xbe, 0x20, 0x83, 0x22, 0xa4, 0x29, 0xdb,
0xb4, 0xbd, 0x1e, 0xd6, 0xee, 0xf0, 0xd3, 0x70, 0xf2, 0xcd, 0xee, 0x9f, 0x8b, 0x47, 0xd4, 0xff,
0x76, 0xff, 0x2c, 0x9d, 0x43, 0x3a, 0xba, 0x12, 0x22, 0x0d, 0xb6, 0x5b, 0xe6, 0x71, 0xbb, 0x53,
0xeb, 0x18, 0xdd, 0x8b, 0x66, 0xfb, 0xdc, 0x38, 0x6a, 0x7c, 0xd5, 0x30, 0xea, 0xea, 0x2d, 0x74,
0x1b, 0xb6, 0x26, 0x48, 0xed, 0xa8, 0xd3, 0x78, 0x61, 0xa8, 0x0a, 0xba, 0x03, 0x85, 0x89, 0xb1,
0xd1, 0x94, 0xe6, 0x58, 0xe9, 0xe7, 0x90, 0x9b, 0xbd, 0x89, 0xa0, 0x7b, 0xa0, 0x31, 0x9a, 0x51,
0x33, 0x8f, 0x4e, 0x9e, 0x1b, 0x3f, 0x5e, 0x88, 0xfc, 0x11, 0xdc, 0x99, 0x43, 0x5b, 0xe6, 0x71,
0xb7, 0x59, 0x3b, 0x63, 0xf1, 0xef, 0xc2, 0xed, 0x39, 0xa8, 0xde, 0x3a, 0xab, 0x35, 0x9a, 0x6a,
0x0c, 0xed, 0x00, 0x9a, 0x03, 0x78, 0x0a, 0x6a, 0xbc, 0x34, 0x90, 0x87, 0xfe, 0xf4, 0x02, 0x83,
0x8a, 0xb0, 0x33, 0xa1, 0x9e, 0x19, 0x9d, 0x93, 0x56, 0xbd, 0x6b, 0x7c, 0x7d, 0x51, 0x3b, 0x6d,
0xab, 0xb7, 0xd0, 0x1e, 0xec, 0x2e, 0x62, 0xed, 0x4e, 0xcd, 0xec, 0xb4, 0xbb, 0x3f, 0x6c, 0x74,
0x4e, 0x54, 0x65, 0x2e, 0x73, 0x49, 0x38, 0x6a, 0x35, 0x3b, 0xb5, 0x46, 0xb3, 0xad, 0xc6, 0x4a,
0x7f, 0x52, 0x20, 0x33, 0xd9, 0x4e, 0xd8, 0x3c, 0x2e, 0xda, 0x86, 0xb9, 0xaa, 0x78, 0xdb, 0xa0,
0x4e, 0xa1, 0x49, 0xf5, 0x76, 0x00, 0x4d, 0xad, 0xd3, 0xf2, 0xb1, 0xaa, 0x4e, 0xed, 0x75, 0xe3,
0xd4, 0xe8, 0x18, 0x75, 0x35, 0x3e, 0x1f, 0xe4, 0xb4, 0x75, 0xf4, 0xdc, 0xa8, 0xab, 0x89, 0x79,
0x72, 0xfb, 0xa2, 0x7d, 0x6e, 0x34, 0xeb, 0x6a, 0x72, 0xde, 0xdc, 0x68, 0x36, 0x3a, 0x8d, 0xda,
0xa9, 0x9a, 0x2a, 0xfd, 0x08, 0x52, 0x42, 0x81, 0x6c, 0xf0, 0x63, 0xa3, 0x59, 0x37, 0xcc, 0x85,
0x54, 0x0b, 0xb0, 0x29, 0xed, 0x5f, 0x19, 0x67, 0xb5, 0x53, 0x96, 0xe7, 0x16, 0x64, 0xa5, 0x89,
0x1b, 0x62, 0x08, 0x41, 0x5e, 0x1a, 0xea, 0x8d, 0x17, 0x86, 0xd9, 0x36, 0xd4, 0x78, 0xf5, 0x5f,
0x49, 0xc8, 0xd5, 0x98, 0xd2, 0xdb, 0x98, 0x5c, 0xb9, 0x3d, 0x8c, 0x9e, 0xc3, 0xc6, 0x09, 0xb6,
0x06, 0x61, 0xff, 0x2d, 0xda, 0x59, 0xda, 0x0b, 0x0d, 0xf6, 0x14, 0x2c, 0xae, 0xb1, 0xeb, 0xea,
0xbb, 0xbf, 0xfd, 0xe3, 0xf7, 0x31, 0x40, 0xe9, 0x4a, 0x5f, 0x46, 0x38, 0x86, 0xa4, 0x89, 0x2d,
0x7b, 0x7c, 0xe3, 0x50, 0x79, 0x1e, 0x2a, 0x8d, 0x52, 0x15, 0xc2, 0xfd, 0x9b, 0x90, 0x7e, 0x21,
0x5f, 0x8c, 0x6b, 0x63, 0xdd, 0x5d, 0xb2, 0xb7, 0xf9, 0xdb, 0x53, 0x2f, 0xf0, 0x60, 0x59, 0x94,
0x99, 0xbc, 0x3a, 0xd1, 0xaf, 0x15, 0xc8, 0x36, 0x68, 0x8b, 0x38, 0xe2, 0x69, 0x86, 0xd6, 0xdc,
0x2a, 0x17, 0x9f, 0x8c, 0xc5, 0x87, 0xd7, 0xf2, 0xc4, 0x45, 0x51, 0xbf, 0xff, 0xee, 0xcf, 0x1a,
0x40, 0xda, 0xb5, 0x86, 0x65, 0x36, 0x03, 0x9e, 0x41, 0x01, 0x6d, 0x55, 0x7c, 0xe2, 0xd0, 0x4a,
0xd7, 0xa5, 0xe2, 0x89, 0x88, 0x2e, 0x01, 0x8e, 0x71, 0xd8, 0x22, 0xce, 0xe1, 0xb8, 0x51, 0x47,
0xbb, 0x6b, 0x2f, 0x94, 0x8d, 0x7a, 0x71, 0xfd, 0x6d, 0x53, 0xdf, 0x5f, 0x31, 0x58, 0x0e, 0x81,
0x18, 0xec, 0x17, 0xae, 0xfd, 0x4b, 0x36, 0x5f, 0x10, 0xf2, 0x6a, 0x11, 0x87, 0xae, 0x9b, 0xee,
0xe2, 0x23, 0x6d, 0xdd, 0x74, 0x97, 0x9e, 0x0e, 0xfa, 0x83, 0x15, 0x19, 0x20, 0x7d, 0x53, 0x4e,
0x97, 0x72, 0xf2, 0x81, 0x52, 0x42, 0xbf, 0x52, 0x20, 0xcd, 0x6f, 0xd4, 0xec, 0x1d, 0xfc, 0xa1,
0xa7, 0xcc, 0xf4, 0xfa, 0x5f, 0x7c, 0x70, 0x1d, 0x6d, 0x26, 0x87, 0x2c, 0x64, 0x58, 0x0e, 0x6f,
0x88, 0x1b, 0x62, 0x51, 0x73, 0x3d, 0x37, 0x49, 0x22, 0x1c, 0x05, 0x07, 0x4a, 0xe9, 0xf0, 0x2f,
0xca, 0xef, 0x6a, 0xbf, 0x55, 0x50, 0x0d, 0x36, 0x79, 0xbc, 0x7d, 0x2a, 0x3a, 0x5f, 0x7f, 0x82,
0x1e, 0xf7, 0xc3, 0x30, 0xa0, 0x07, 0x95, 0x8a, 0xe3, 0x86, 0xfd, 0xd1, 0xcb, 0x72, 0xcf, 0x1f,
0x56, 0x7a, 0x96, 0x4f, 0x2b, 0x32, 0x81, 0x4a, 0xf0, 0xca, 0xa9, 0x70, 0xa7, 0x6a, 0xfc, 0xb3,
0xf2, 0xb3, 0x92, 0x12, 0xab, 0xaa, 0x56, 0x10, 0x0c, 0xdc, 0x1e, 0xbf, 0x55, 0x54, 0x7e, 0x46,
0x7d, 0x6f, 0xde, 0xe2, 0x90, 0xa0, 0x77, 0xb0, 0xc4, 0x39, 0x58, 0xe2, 0xfc, 0xa4, 0x74, 0xed,
0x90, 0xfc, 0xdf, 0x35, 0x8c, 0xfb, 0x32, 0xc5, 0x1b, 0xfc, 0xdb, 0xff, 0x0d, 0x00, 0x00, 0xff,
0xff, 0xd2, 0xa3, 0xeb, 0x34, 0xeb, 0x11, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -197,6 +197,64 @@
}
}
},
"v1CreateUserRequest": {
"type": "object",
"properties": {
"user_name": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
},
"nick_name": {
"type": "string"
},
"display_name": {
"type": "string"
},
"preferred_language": {
"type": "string"
},
"gender": {
"$ref": "#/definitions/v1Gender"
},
"email": {
"type": "string"
},
"is_email_verified": {
"type": "boolean",
"format": "boolean"
},
"phone": {
"type": "string"
},
"is_phone_verified": {
"type": "boolean",
"format": "boolean"
},
"country": {
"type": "string"
},
"locality": {
"type": "string"
},
"postal_code": {
"type": "string"
},
"region": {
"type": "string"
},
"street_address": {
"type": "string"
},
"password": {
"type": "string"
}
}
},
"v1Gender": {
"type": "string",
"enum": [
@ -321,7 +379,7 @@
"$ref": "#/definitions/v1CreateOrgRequest"
},
"user": {
"$ref": "#/definitions/v1RegisterUserRequest"
"$ref": "#/definitions/v1CreateUserRequest"
}
}
},
@ -345,38 +403,6 @@
],
"default": "ORGSTATE_UNSPECIFIED"
},
"v1RegisterUserRequest": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
},
"nick_name": {
"type": "string"
},
"display_name": {
"type": "string"
},
"preferred_language": {
"type": "string"
},
"gender": {
"$ref": "#/definitions/v1Gender"
},
"password": {
"type": "string"
},
"org_id": {
"type": "string"
}
}
},
"v1UniqueOrgResponse": {
"type": "object",
"properties": {
@ -452,6 +478,10 @@
},
"street_address": {
"type": "string"
},
"sequence": {
"type": "string",
"format": "uint64"
}
}
},

View File

@ -2,21 +2,38 @@ package grpc
import (
"context"
"github.com/caos/zitadel/internal/errors"
)
func (s *Server) GetOrgByID(ctx context.Context, orgID *OrgID) (_ *Org, err error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-mvn3R", "Not implemented")
org, err := s.org.OrgByID(ctx, orgID.Id)
if err != nil {
return nil, err
}
return orgFromModel(org), nil
}
func (s *Server) SearchOrgs(ctx context.Context, request *OrgSearchRequest) (_ *OrgSearchResponse, err error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-Po9Hd", "Not implemented")
orgs, err := s.org.SearchOrgs(ctx)
if err != nil {
return nil, err
}
return &OrgSearchResponse{Result: orgsFromModel(orgs),
Limit: request.Limit,
Offset: request.Offset,
// TotalResult: , TODO: total result from search
}, nil
}
func (s *Server) IsOrgUnique(ctx context.Context, request *UniqueOrgRequest) (org *UniqueOrgResponse, err error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-0p6Fw", "Not implemented")
isUnique, err := s.org.IsOrgUnique(ctx, request.Name, request.Domain)
return &UniqueOrgResponse{IsUnique: isUnique}, err
}
func (s *Server) SetUpOrg(ctx context.Context, orgSetUp *OrgSetUpRequest) (_ *OrgSetUpResponse, err error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-hdj5D", "Not implemented")
setUp, err := s.org.SetUpOrg(ctx, setUpRequestToModel(orgSetUp))
if err != nil {
return nil, err
}
return setUpOrgResponseFromModel(setUp), err
}

View File

@ -0,0 +1,181 @@
package grpc
import (
"github.com/caos/logging"
admin_model "github.com/caos/zitadel/internal/admin/model"
org_model "github.com/caos/zitadel/internal/org/model"
usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/golang/protobuf/ptypes"
"golang.org/x/text/language"
)
func setUpRequestToModel(setUp *OrgSetUpRequest) *admin_model.SetupOrg {
return &admin_model.SetupOrg{
Org: orgCreateRequestToModel(setUp.Org),
User: userCreateRequestToModel(setUp.User),
}
}
func orgCreateRequestToModel(org *CreateOrgRequest) *org_model.Org {
return &org_model.Org{
Domain: org.Domain,
Name: org.Name,
}
}
func userCreateRequestToModel(user *CreateUserRequest) *usr_model.User {
preferredLanguage, err := language.Parse(user.PreferredLanguage)
logging.Log("GRPC-30hwz").OnError(err).Debug("unable to parse language")
return &usr_model.User{
Profile: &usr_model.Profile{
UserName: user.UserName,
DisplayName: user.DisplayName,
FirstName: user.FirstName,
LastName: user.LastName,
NickName: user.NickName,
PreferredLanguage: preferredLanguage,
Gender: genderToModel(user.Gender),
},
Password: &usr_model.Password{
SecretString: user.Password,
},
Email: &usr_model.Email{
EmailAddress: user.Email,
IsEmailVerified: user.IsEmailVerified,
},
Phone: &usr_model.Phone{
IsPhoneVerified: user.IsPhoneVerified,
PhoneNumber: user.Phone,
},
Address: &usr_model.Address{
Country: user.Country,
Locality: user.Locality,
PostalCode: user.PostalCode,
Region: user.Region,
StreetAddress: user.StreetAddress,
},
}
}
func setUpOrgResponseFromModel(setUp *admin_model.SetupOrg) *OrgSetUpResponse {
return &OrgSetUpResponse{
Org: orgFromModel(setUp.Org),
User: userFromModel(setUp.User),
}
}
func orgsFromModel(orgs []*org_model.Org) []*Org {
result := make([]*Org, len(orgs))
for i, org := range orgs {
result[i] = orgFromModel(org)
}
return result
}
func orgFromModel(org *org_model.Org) *Org {
creationDate, err := ptypes.TimestampProto(org.CreationDate)
logging.Log("GRPC-GTHsZ").OnError(err).Debug("unable to get timestamp from time")
changeDate, err := ptypes.TimestampProto(org.ChangeDate)
logging.Log("GRPC-dVnoj").OnError(err).Debug("unable to get timestamp from time")
return &Org{
Domain: org.Domain,
ChangeDate: changeDate,
CreationDate: creationDate,
Id: org.AggregateID,
Name: org.Name,
State: orgStateFromModel(org.State),
}
}
func userFromModel(user *usr_model.User) *User {
creationDate, err := ptypes.TimestampProto(user.CreationDate)
logging.Log("GRPC-8duwe").OnError(err).Debug("unable to parse timestamp")
changeDate, err := ptypes.TimestampProto(user.ChangeDate)
logging.Log("GRPC-ckoe3d").OnError(err).Debug("unable to parse timestamp")
converted := &User{
Id: user.AggregateID,
State: userStateFromModel(user.State),
CreationDate: creationDate,
ChangeDate: changeDate,
Sequence: user.Sequence,
UserName: user.UserName,
FirstName: user.FirstName,
LastName: user.LastName,
DisplayName: user.DisplayName,
NickName: user.NickName,
PreferredLanguage: user.PreferredLanguage.String(),
Gender: genderFromModel(user.Gender),
}
if user.Email != nil {
converted.Email = user.EmailAddress
converted.IsEmailVerified = user.IsEmailVerified
}
if user.Phone != nil {
converted.Phone = user.PhoneNumber
converted.IsPhoneVerified = user.IsPhoneVerified
}
if user.Address != nil {
converted.Country = user.Country
converted.Locality = user.Locality
converted.PostalCode = user.PostalCode
converted.Region = user.Region
converted.StreetAddress = user.StreetAddress
}
return converted
}
func orgStateFromModel(state org_model.OrgState) OrgState {
switch state {
case org_model.ORGSTATE_ACTIVE:
return OrgState_ORGSTATE_ACTIVE
case org_model.ORGSTATE_INACTIVE:
return OrgState_ORGSTATE_INACTIVE
default:
return OrgState_ORGSTATE_UNSPECIFIED
}
}
func genderFromModel(gender usr_model.Gender) Gender {
switch gender {
case usr_model.GENDER_FEMALE:
return Gender_GENDER_FEMALE
case usr_model.GENDER_MALE:
return Gender_GENDER_MALE
case usr_model.GENDER_DIVERSE:
return Gender_GENDER_DIVERSE
default:
return Gender_GENDER_UNSPECIFIED
}
}
func genderToModel(gender Gender) usr_model.Gender {
switch gender {
case Gender_GENDER_FEMALE:
return usr_model.GENDER_FEMALE
case Gender_GENDER_MALE:
return usr_model.GENDER_MALE
case Gender_GENDER_DIVERSE:
return usr_model.GENDER_DIVERSE
default:
return usr_model.GENDER_UNDEFINED
}
}
func userStateFromModel(state usr_model.UserState) UserState {
switch state {
case usr_model.USERSTATE_ACTIVE:
return UserState_USERSTATE_ACTIVE
case usr_model.USERSTATE_INACTIVE:
return UserState_USERSTATE_INACTIVE
case usr_model.USERSTATE_LOCKED:
return UserState_USERSTATE_LOCKED
default:
return UserState_USERSTATE_UNSPECIFIED
}
}

View File

@ -2,17 +2,18 @@ package grpc
import (
"context"
"github.com/caos/zitadel/internal/errors"
"github.com/golang/protobuf/ptypes/empty"
pb_struct "github.com/golang/protobuf/ptypes/struct"
)
func (s *Server) Healthz(_ context.Context, e *empty.Empty) (*empty.Empty, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-ruc8e", "Not implemented")
return &empty.Empty{}, nil
}
func (s *Server) Ready(ctx context.Context, e *empty.Empty) (*empty.Empty, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-bw3vR", "Not implemented")
return &empty.Empty{}, s.repo.Health(ctx)
}
func (s *Server) Validate(ctx context.Context, _ *empty.Empty) (*pb_struct.Struct, error) {

View File

@ -1,28 +1,32 @@
package grpc
import (
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"google.golang.org/grpc"
admin_auth "github.com/caos/zitadel/internal/admin/auth"
"github.com/caos/zitadel/internal/admin/repository"
"github.com/caos/zitadel/internal/api/auth"
grpc_util "github.com/caos/zitadel/internal/api/grpc"
"github.com/caos/zitadel/internal/api/grpc/server/middleware"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
"google.golang.org/grpc"
)
var _ AdminServiceServer = (*Server)(nil)
type Config struct {
Port string
SearchLimit int
}
type Server struct {
port string
searchLimit int
port string
org repository.OrgRepository
verifier auth.TokenVerifier
authZ auth.Config
repo repository.Repository
}
func StartServer(conf grpc_util.ServerConfig) *Server {
func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository.Repository) *Server {
return &Server{
port: conf.Port,
port: conf.Port,
org: repo,
repo: repo,
authZ: authZ,
verifier: admin_auth.Start(),
}
}
@ -36,6 +40,7 @@ func (s *Server) GRPCServer() (*grpc.Server, error) {
grpc.UnaryInterceptor(
grpc_middleware.ChainUnaryServer(
middleware.ErrorHandler(),
AdminService_Authorization_Interceptor(s.verifier, &s.authZ),
),
),
)

View File

@ -164,7 +164,7 @@ enum OrgSearchMethod {
message OrgSetUpRequest {
CreateOrgRequest org = 1;
RegisterUserRequest user = 2;
CreateUserRequest user = 2;
}
message OrgSetUpResponse {
@ -172,16 +172,24 @@ message OrgSetUpResponse {
User user = 2;
}
message RegisterUserRequest {
string email = 1 [(validate.rules).string.email = true];
string first_name = 2 [(validate.rules).string.min_len = 1];
string last_name = 3 [(validate.rules).string.min_len = 1];
string nick_name = 4;
string display_name = 5;
string preferred_language = 6;
message CreateUserRequest {
string user_name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
string first_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
string last_name = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
string nick_name = 4 [(validate.rules).string = {max_len: 200}];
string display_name = 5 [(validate.rules).string = {max_len: 200}];
string preferred_language = 6 [(validate.rules).string = {max_len: 200}];
Gender gender = 7;
string password = 8 [(validate.rules).string.min_len = 1];
string org_id = 9 [(validate.rules).string.min_len = 1];
string email = 8 [(validate.rules).string = {min_len: 1, max_len: 200, email: true}];
bool is_email_verified = 9;
string phone = 11 [(validate.rules).string = {max_len: 20}];
bool is_phone_verified = 12;
string country = 13 [(validate.rules).string = {max_len: 200}];
string locality = 14 [(validate.rules).string = {max_len: 200}];
string postal_code = 15 [(validate.rules).string = {max_len: 200}];
string region = 16 [(validate.rules).string = {max_len: 200}];
string street_address = 17 [(validate.rules).string = {max_len: 200}];
string password = 18 [(validate.rules).string = {max_len: 72}];
}
message User {
@ -205,6 +213,7 @@ message User {
string postal_code = 18;
string region = 19;
string street_address = 20;
uint64 sequence = 21;
}
enum UserState {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -358,7 +358,7 @@
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
"$ref": "#/definitions/v1OrgMember"
}
}
},
@ -450,7 +450,7 @@
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
"$ref": "#/definitions/v1OrgMember"
}
}
},
@ -3339,7 +3339,7 @@
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/protobufStruct"
"type": "object"
}
}
},
@ -3350,19 +3350,6 @@
}
},
"definitions": {
"protobufListValue": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufValue"
},
"description": "Repeated field of dynamically typed values."
}
},
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
},
"protobufNullValue": {
"type": "string",
"enum": [
@ -3371,51 +3358,6 @@
"default": "NULL_VALUE",
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
},
"protobufStruct": {
"type": "object",
"properties": {
"fields": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/protobufValue"
},
"description": "Unordered map of dynamically typed values."
}
},
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
},
"protobufValue": {
"type": "object",
"properties": {
"null_value": {
"$ref": "#/definitions/protobufNullValue",
"description": "Represents a null value."
},
"number_value": {
"type": "number",
"format": "double",
"description": "Represents a double value."
},
"string_value": {
"type": "string",
"description": "Represents a string value."
},
"bool_value": {
"type": "boolean",
"format": "boolean",
"description": "Represents a boolean value."
},
"struct_value": {
"$ref": "#/definitions/protobufStruct",
"description": "Represents a structured value."
},
"list_value": {
"$ref": "#/definitions/protobufListValue",
"description": "Represents a repeated `Value`."
}
},
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
},
"v1AddOrgMemberRequest": {
"type": "object",
"properties": {
@ -3703,7 +3645,7 @@
"type": "string"
},
"data": {
"$ref": "#/definitions/protobufStruct"
"type": "object"
}
}
},
@ -4178,18 +4120,6 @@
"user_id": {
"type": "string"
},
"user_name": {
"type": "string"
},
"email": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
},
"roles": {
"type": "array",
"items": {

View File

@ -38,14 +38,14 @@ func (m *MockManagementServiceClient) EXPECT() *MockManagementServiceClientMockR
}
// AddOrgMember mocks base method
func (m *MockManagementServiceClient) AddOrgMember(arg0 context.Context, arg1 *grpc.AddOrgMemberRequest, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
func (m *MockManagementServiceClient) AddOrgMember(arg0 context.Context, arg1 *grpc.AddOrgMemberRequest, arg2 ...grpc0.CallOption) (*grpc.OrgMember, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddOrgMember", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret0, _ := ret[0].(*grpc.OrgMember)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@ -158,14 +158,14 @@ func (mr *MockManagementServiceClientMockRecorder) ApplicationChanges(arg0, arg1
}
// ChangeOrgMember mocks base method
func (m *MockManagementServiceClient) ChangeOrgMember(arg0 context.Context, arg1 *grpc.ChangeOrgMemberRequest, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
func (m *MockManagementServiceClient) ChangeOrgMember(arg0 context.Context, arg1 *grpc.ChangeOrgMemberRequest, arg2 ...grpc0.CallOption) (*grpc.OrgMember, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "ChangeOrgMember", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret0, _ := ret[0].(*grpc.OrgMember)
ret1, _ := ret[1].(error)
return ret0, ret1
}

View File

@ -2,25 +2,42 @@ package grpc
import (
"context"
"github.com/caos/zitadel/internal/errors"
)
func (s *Server) GetOrgByID(ctx context.Context, in *OrgID) (*Org, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-sdo5g", "Not implemented")
func (s *Server) GetOrgByID(ctx context.Context, orgID *OrgID) (*Org, error) {
org, err := s.org.OrgByID(ctx, orgID.Id)
if err != nil {
return nil, err
}
return orgFromModel(org), nil
}
func (s *Server) GetOrgByDomainGlobal(ctx context.Context, in *OrgDomain) (*Org, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-mop4s", "Not implemented")
org, err := s.org.OrgByDomainGlobal(ctx, in.Domain)
if err != nil {
return nil, err
}
return orgFromModel(org), nil
}
func (s *Server) DeactivateOrg(ctx context.Context, in *OrgID) (*Org, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-vel3X", "Not implemented")
org, err := s.org.DeactivateOrg(ctx, in.Id)
if err != nil {
return nil, err
}
return orgFromModel(org), nil
}
func (s *Server) ReactivateOrg(ctx context.Context, in *OrgID) (*Org, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-Scmk3", "Not implemented")
org, err := s.org.ReactivateOrg(ctx, in.Id)
if err != nil {
return nil, err
}
return orgFromModel(org), nil
}
func (s *Server) OrgChanges(ctx context.Context, changesRequest *ChangeRequest) (*Changes, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-mfiF4", "Not implemented")
return nil, errors.ThrowUnimplemented(nil, "GRPC-DNiIq", "unimplemented")
}

View File

@ -0,0 +1,43 @@
package grpc
import (
"github.com/caos/logging"
org_model "github.com/caos/zitadel/internal/org/model"
"github.com/golang/protobuf/ptypes"
)
func orgsFromModel(orgs []*org_model.Org) []*Org {
orgList := make([]*Org, len(orgs))
for i, org := range orgs {
orgList[i] = orgFromModel(org)
}
return orgList
}
func orgFromModel(org *org_model.Org) *Org {
creationDate, err := ptypes.TimestampProto(org.CreationDate)
logging.Log("GRPC-GTHsZ").OnError(err).Debug("unable to get timestamp from time")
changeDate, err := ptypes.TimestampProto(org.ChangeDate)
logging.Log("GRPC-dVnoj").OnError(err).Debug("unable to get timestamp from time")
return &Org{
Domain: org.Domain,
ChangeDate: changeDate,
CreationDate: creationDate,
Id: org.AggregateID,
Name: org.Name,
State: orgStateFromModel(org.State),
}
}
func orgStateFromModel(state org_model.OrgState) OrgState {
switch state {
case org_model.ORGSTATE_ACTIVE:
return OrgState_ORGSTATE_ACTIVE
case org_model.ORGSTATE_INACTIVE:
return OrgState_ORGSTATE_INACTIVE
default:
return OrgState_ORGSTATE_UNSPECIFIED
}
}

View File

@ -2,6 +2,7 @@ package grpc
import (
"context"
"github.com/caos/zitadel/internal/errors"
"github.com/golang/protobuf/ptypes/empty"
)
@ -14,14 +15,27 @@ func (s *Server) SearchOrgMembers(ctx context.Context, in *OrgMemberSearchReques
return nil, errors.ThrowUnimplemented(nil, "GRPC-wkdl3", "Not implemented")
}
func (s *Server) AddOrgMember(ctx context.Context, member *AddOrgMemberRequest) (*empty.Empty, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-Moe56", "Not implemented")
func (s *Server) AddOrgMember(ctx context.Context, member *AddOrgMemberRequest) (*OrgMember, error) {
repositoryMember := addOrgMemberToModel(member)
addedMember, err := s.orgMember.AddOrgMember(ctx, repositoryMember)
if err != nil {
return nil, err
}
return orgMemberFromModel(addedMember), nil
}
func (s *Server) ChangeOrgMember(ctx context.Context, member *ChangeOrgMemberRequest) (*empty.Empty, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-eod34", "Not implemented")
func (s *Server) ChangeOrgMember(ctx context.Context, member *ChangeOrgMemberRequest) (*OrgMember, error) {
repositoryMember := changeOrgMemberToModel(member)
changedMember, err := s.orgMember.ChangeOrgMember(ctx, repositoryMember)
if err != nil {
return nil, err
}
return orgMemberFromModel(changedMember), nil
}
func (s *Server) RemoveOrgMember(ctx context.Context, member *RemoveOrgMemberRequest) (*empty.Empty, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-poeSw", "Not implemented")
err := s.orgMember.RemoveOrgMember(ctx, member.OrgId, member.UserId)
return &empty.Empty{}, err
}

View File

@ -0,0 +1,37 @@
package grpc
import (
"github.com/caos/logging"
org_model "github.com/caos/zitadel/internal/org/model"
"github.com/golang/protobuf/ptypes"
)
func addOrgMemberToModel(member *AddOrgMemberRequest) *org_model.OrgMember {
memberModel := org_model.NewOrgMember(member.OrgId, member.UserId)
memberModel.Roles = member.Roles
return memberModel
}
func changeOrgMemberToModel(member *ChangeOrgMemberRequest) *org_model.OrgMember {
memberModel := org_model.NewOrgMember(member.OrgId, member.UserId)
memberModel.Roles = member.Roles
return memberModel
}
func orgMemberFromModel(member *org_model.OrgMember) *OrgMember {
creationDate, err := ptypes.TimestampProto(member.CreationDate)
logging.Log("GRPC-jC5wY").OnError(err).Debug("date parse failed")
changeDate, err := ptypes.TimestampProto(member.ChangeDate)
logging.Log("GRPC-Nc2jJ").OnError(err).Debug("date parse failed")
return &OrgMember{
UserId: member.UserID,
CreationDate: creationDate,
ChangeDate: changeDate,
Roles: member.Roles,
Sequence: member.Sequence,
}
}

View File

@ -15,6 +15,8 @@ var _ ManagementServiceServer = (*Server)(nil)
type Server struct {
port string
project repository.ProjectRepository
org repository.OrgRepository
orgMember repository.OrgMemberRepository
user repository.UserRepository
usergrant repository.UserGrantRepository
verifier *mgmt_auth.TokenVerifier
@ -25,6 +27,8 @@ func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository
return &Server{
port: conf.Port,
project: repo,
org: repo,
orgMember: repo,
user: repo,
usergrant: repo,
authZ: authZ,

View File

@ -527,7 +527,7 @@ service ManagementService {
};
}
rpc AddOrgMember(AddOrgMemberRequest) returns (google.protobuf.Empty) {
rpc AddOrgMember(AddOrgMemberRequest) returns (OrgMember) {
option (google.api.http) = {
post: "/orgs/{org_id}/members"
body: "*"
@ -538,7 +538,7 @@ service ManagementService {
};
}
rpc ChangeOrgMember(ChangeOrgMemberRequest) returns (google.protobuf.Empty) {
rpc ChangeOrgMember(ChangeOrgMemberRequest) returns (OrgMember) {
option (google.api.http) = {
put: "/orgs/{org_id}/members/{user_id}"
body: "*"
@ -1646,14 +1646,10 @@ message OrgMemberRoles {
message OrgMember {
string user_id = 1;
string user_name = 2;
string email = 3;
string first_name = 4;
string last_name = 5;
repeated string roles = 6;
google.protobuf.Timestamp change_date = 7;
google.protobuf.Timestamp creation_date = 8;
uint64 sequence = 9;
repeated string roles = 2;
google.protobuf.Timestamp change_date = 3;
google.protobuf.Timestamp creation_date = 4;
uint64 sequence = 5;
}
message AddOrgMemberRequest {