mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 04:57:33 +00:00
feat: System api (#3461)
* feat: start system api * feat: remove auth * feat: change gitignore * feat: run system api * feat: remove clear view form admin api * feat: search instances * feat: add instance * fix: set primary domain * Update .gitignore * fix: add instance * fix: add instance * fix: handle errors * fix: handle instance name * fix: test Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
package admin_test
|
||||
package admin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
admin_grpc "github.com/caos/zitadel/internal/api/grpc/admin"
|
||||
"github.com/caos/zitadel/internal/test"
|
||||
"github.com/caos/zitadel/internal/view/model"
|
||||
admin_pb "github.com/caos/zitadel/pkg/grpc/admin"
|
||||
@@ -34,7 +33,7 @@ func TestFailedEventsToPbFields(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := admin_grpc.FailedEventsViewToPb(tt.args.failedEvents)
|
||||
got := FailedEventsViewToPb(tt.args.failedEvents)
|
||||
for _, g := range got {
|
||||
test.AssertFieldsMapped(t, g)
|
||||
}
|
||||
@@ -64,7 +63,7 @@ func TestFailedEventToPbFields(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
converted := admin_grpc.FailedEventViewToPb(tt.args.failedEvent)
|
||||
converted := FailedEventViewToPb(tt.args.failedEvent)
|
||||
test.AssertFieldsMapped(t, converted)
|
||||
}
|
||||
}
|
||||
@@ -89,7 +88,7 @@ func TestRemoveFailedEventRequestToModelFields(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
converted := admin_grpc.RemoveFailedEventRequestToModel(tt.args.req)
|
||||
converted := RemoveFailedEventRequestToModel(tt.args.req)
|
||||
test.AssertFieldsMapped(t, converted, "FailureCount", "ErrMsg")
|
||||
}
|
||||
}
|
||||
|
@@ -22,16 +22,3 @@ func (s *Server) ListViews(ctx context.Context, _ *admin_pb.ListViewsRequest) (*
|
||||
convertedCurrentSequences = append(convertedCurrentSequences, convertedViews...)
|
||||
return &admin_pb.ListViewsResponse{Result: convertedCurrentSequences}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ClearView(ctx context.Context, req *admin_pb.ClearViewRequest) (*admin_pb.ClearViewResponse, error) {
|
||||
var err error
|
||||
if req.Database != "zitadel" {
|
||||
err = s.administrator.ClearView(ctx, req.Database, req.ViewName)
|
||||
} else {
|
||||
err = s.query.ClearCurrentSequence(ctx, req.ViewName)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &admin_pb.ClearViewResponse{}, nil
|
||||
}
|
||||
|
@@ -7,6 +7,46 @@ import (
|
||||
instance_pb "github.com/caos/zitadel/pkg/grpc/instance"
|
||||
)
|
||||
|
||||
func InstancesToPb(instances []*query.Instance) []*instance_pb.Instance {
|
||||
list := make([]*instance_pb.Instance, len(instances))
|
||||
for i, instance := range instances {
|
||||
list[i] = InstanceToPb(instance)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func InstanceToPb(instance *query.Instance) *instance_pb.Instance {
|
||||
return &instance_pb.Instance{
|
||||
Details: object.ToViewDetailsPb(
|
||||
instance.Sequence,
|
||||
instance.CreationDate,
|
||||
instance.ChangeDate,
|
||||
instance.InstanceID(),
|
||||
),
|
||||
Id: instance.InstanceID(),
|
||||
}
|
||||
}
|
||||
|
||||
func InstanceQueriesToModel(queries []*instance_pb.Query) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
q[i], err = InstanceQueryToModel(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return q, nil
|
||||
}
|
||||
|
||||
func InstanceQueryToModel(searchQuery *instance_pb.Query) (query.SearchQuery, error) {
|
||||
switch q := searchQuery.Query.(type) {
|
||||
case *instance_pb.Query_IdQuery:
|
||||
return query.NewInstanceIDsListSearchQuery(q.IdQuery.Ids...)
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgument(nil, "INST-3m0se", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func DomainQueriesToModel(queries []*instance_pb.DomainSearchQuery) (_ []query.SearchQuery, err error) {
|
||||
q := make([]query.SearchQuery, len(queries))
|
||||
for i, query := range queries {
|
||||
@@ -27,7 +67,7 @@ func DomainQueryToModel(searchQuery *instance_pb.DomainSearchQuery) (query.Searc
|
||||
case *instance_pb.DomainSearchQuery_PrimaryQuery:
|
||||
return query.NewInstanceDomainPrimarySearchQuery(q.PrimaryQuery.Primary)
|
||||
default:
|
||||
return nil, errors.ThrowInvalidArgument(nil, "ORG-Ags42", "List.Query.Invalid")
|
||||
return nil, errors.ThrowInvalidArgument(nil, "INST-Ags42", "List.Query.Invalid")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,10 @@ import (
|
||||
|
||||
func AuthorizationInterceptor(verifier *authz.TokenVerifier, authConfig authz.Config) grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
//TODO: Change as soon as we know how to authenticate system api
|
||||
if verifier == nil {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
return authorize(ctx, req, info, handler, verifier, authConfig)
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package middleware
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -16,13 +17,19 @@ type InstanceVerifier interface {
|
||||
GetInstance(ctx context.Context)
|
||||
}
|
||||
|
||||
func InstanceInterceptor(verifier authz.InstanceVerifier, headerName string) grpc.UnaryServerInterceptor {
|
||||
func InstanceInterceptor(verifier authz.InstanceVerifier, headerName string, ignoredServices ...string) grpc.UnaryServerInterceptor {
|
||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||
return setInstance(ctx, req, info, handler, verifier, headerName)
|
||||
return setInstance(ctx, req, info, handler, verifier, headerName, ignoredServices...)
|
||||
}
|
||||
}
|
||||
|
||||
func setInstance(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, verifier authz.InstanceVerifier, headerName string) (_ interface{}, err error) {
|
||||
func setInstance(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, verifier authz.InstanceVerifier, headerName string, ignoredServices ...string) (_ interface{}, err error) {
|
||||
for _, service := range ignoredServices {
|
||||
if strings.HasPrefix(info.FullMethod, service) {
|
||||
return handler(ctx, req)
|
||||
}
|
||||
}
|
||||
|
||||
host, err := hostNameFromContext(ctx, headerName)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.PermissionDenied, err.Error())
|
||||
|
@@ -30,7 +30,8 @@ func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, querie
|
||||
middleware.SentryHandler(),
|
||||
middleware.NoCacheInterceptor(),
|
||||
middleware.ErrorHandler(),
|
||||
middleware.InstanceInterceptor(queries, hostHeaderName),
|
||||
//TODO: Handle Ignored Services
|
||||
middleware.InstanceInterceptor(queries, hostHeaderName, "/zitadel.system.v1.SystemService"),
|
||||
middleware.AuthorizationInterceptor(verifier, authConfig),
|
||||
middleware.TranslationHandler(queries),
|
||||
middleware.ValidationHandler(),
|
||||
|
37
internal/api/grpc/system/failed_event.go
Normal file
37
internal/api/grpc/system/failed_event.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||
)
|
||||
|
||||
func (s *Server) ListFailedEvents(ctx context.Context, req *system_pb.ListFailedEventsRequest) (*system_pb.ListFailedEventsResponse, error) {
|
||||
failedEventsOld, err := s.administrator.GetFailedEvents(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
convertedOld := FailedEventsViewToPb(failedEventsOld)
|
||||
|
||||
failedEvents, err := s.query.SearchFailedEvents(ctx, new(query.FailedEventSearchQueries))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
convertedNew := FailedEventsToPb(failedEvents)
|
||||
convertedOld = append(convertedOld, convertedNew...)
|
||||
return &system_pb.ListFailedEventsResponse{Result: convertedOld}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveFailedEvent(ctx context.Context, req *system_pb.RemoveFailedEventRequest) (*system_pb.RemoveFailedEventResponse, error) {
|
||||
var err error
|
||||
if req.Database != "zitadel" {
|
||||
err = s.administrator.RemoveFailedEvent(ctx, RemoveFailedEventRequestToModel(req))
|
||||
} else {
|
||||
err = s.query.RemoveFailedEvent(ctx, req.ViewName, req.FailedSequence)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &system_pb.RemoveFailedEventResponse{}, nil
|
||||
}
|
51
internal/api/grpc/system/failed_event_converter.go
Normal file
51
internal/api/grpc/system/failed_event_converter.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
"github.com/caos/zitadel/internal/view/model"
|
||||
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||
)
|
||||
|
||||
func FailedEventsViewToPb(failedEvents []*model.FailedEvent) []*system_pb.FailedEvent {
|
||||
events := make([]*system_pb.FailedEvent, len(failedEvents))
|
||||
for i, failedEvent := range failedEvents {
|
||||
events[i] = FailedEventViewToPb(failedEvent)
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
func FailedEventViewToPb(failedEvent *model.FailedEvent) *system_pb.FailedEvent {
|
||||
return &system_pb.FailedEvent{
|
||||
Database: failedEvent.Database,
|
||||
ViewName: failedEvent.ViewName,
|
||||
FailedSequence: failedEvent.FailedSequence,
|
||||
FailureCount: failedEvent.FailureCount,
|
||||
ErrorMessage: failedEvent.ErrMsg,
|
||||
}
|
||||
}
|
||||
|
||||
func FailedEventsToPb(failedEvents *query.FailedEvents) []*system_pb.FailedEvent {
|
||||
events := make([]*system_pb.FailedEvent, len(failedEvents.FailedEvents))
|
||||
for i, failedEvent := range failedEvents.FailedEvents {
|
||||
events[i] = FailedEventToPb(failedEvent)
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
func FailedEventToPb(failedEvent *query.FailedEvent) *system_pb.FailedEvent {
|
||||
return &system_pb.FailedEvent{
|
||||
Database: "zitadel",
|
||||
ViewName: failedEvent.ProjectionName,
|
||||
FailedSequence: failedEvent.FailedSequence,
|
||||
FailureCount: failedEvent.FailureCount,
|
||||
ErrorMessage: failedEvent.Error,
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveFailedEventRequestToModel(req *system_pb.RemoveFailedEventRequest) *model.FailedEvent {
|
||||
return &model.FailedEvent{
|
||||
Database: req.Database,
|
||||
ViewName: req.ViewName,
|
||||
FailedSequence: req.FailedSequence,
|
||||
}
|
||||
}
|
95
internal/api/grpc/system/failed_event_converter_test.go
Normal file
95
internal/api/grpc/system/failed_event_converter_test.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package system_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
system_grpc "github.com/caos/zitadel/internal/api/grpc/system"
|
||||
"github.com/caos/zitadel/internal/test"
|
||||
"github.com/caos/zitadel/internal/view/model"
|
||||
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||
)
|
||||
|
||||
func TestFailedEventsToPbFields(t *testing.T) {
|
||||
type args struct {
|
||||
failedEvents []*model.FailedEvent
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
{
|
||||
name: "all fields",
|
||||
args: args{
|
||||
failedEvents: []*model.FailedEvent{
|
||||
{
|
||||
Database: "admin",
|
||||
ViewName: "users",
|
||||
FailedSequence: 456,
|
||||
FailureCount: 5,
|
||||
ErrMsg: "some error",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := system_grpc.FailedEventsViewToPb(tt.args.failedEvents)
|
||||
for _, g := range got {
|
||||
test.AssertFieldsMapped(t, g)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFailedEventToPbFields(t *testing.T) {
|
||||
type args struct {
|
||||
failedEvent *model.FailedEvent
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
{
|
||||
"all fields",
|
||||
args{
|
||||
failedEvent: &model.FailedEvent{
|
||||
Database: "admin",
|
||||
ViewName: "users",
|
||||
FailedSequence: 456,
|
||||
FailureCount: 5,
|
||||
ErrMsg: "some error",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
converted := system_grpc.FailedEventViewToPb(tt.args.failedEvent)
|
||||
test.AssertFieldsMapped(t, converted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveFailedEventRequestToModelFields(t *testing.T) {
|
||||
type args struct {
|
||||
req *system_pb.RemoveFailedEventRequest
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
{
|
||||
"all fields",
|
||||
args{
|
||||
req: &system_pb.RemoveFailedEventRequest{
|
||||
Database: "admin",
|
||||
ViewName: "users",
|
||||
FailedSequence: 456,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
converted := system_grpc.RemoveFailedEventRequestToModel(tt.args.req)
|
||||
test.AssertFieldsMapped(t, converted, "FailureCount", "ErrMsg")
|
||||
}
|
||||
}
|
127
internal/api/grpc/system/instance.go
Normal file
127
internal/api/grpc/system/instance.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
instance_grpc "github.com/caos/zitadel/internal/api/grpc/instance"
|
||||
"github.com/caos/zitadel/internal/api/grpc/object"
|
||||
object_pb "github.com/caos/zitadel/pkg/grpc/object"
|
||||
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||
)
|
||||
|
||||
func (s *Server) ListInstances(ctx context.Context, req *system_pb.ListInstancesRequest) (*system_pb.ListInstancesResponse, error) {
|
||||
queries, err := ListInstancesRequestToModel(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result, err := s.query.SearchInstances(ctx, queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &system_pb.ListInstancesResponse{
|
||||
Result: instance_grpc.InstancesToPb(result.Instances),
|
||||
Details: &object_pb.ListDetails{
|
||||
TotalResult: result.Count,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetInstance(ctx context.Context, req *system_pb.GetInstanceRequest) (*system_pb.GetInstanceResponse, error) {
|
||||
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||
instance, err := s.query.Instance(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &system_pb.GetInstanceResponse{
|
||||
Instance: instance_grpc.InstanceToPb(instance),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddInstance(ctx context.Context, req *system_pb.AddInstanceRequest) (*system_pb.AddInstanceResponse, error) {
|
||||
id, details, err := s.command.SetUpInstance(ctx, AddInstancePbToSetupInstance(req, s.DefaultInstance), s.ExternalSecure, s.BaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &system_pb.AddInstanceResponse{
|
||||
Id: id,
|
||||
Details: object.AddToDetailsPb(
|
||||
details.Sequence,
|
||||
details.EventDate,
|
||||
details.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *Server) ListDomains(ctx context.Context, req *system_pb.ListDomainsRequest) (*system_pb.ListDomainsResponse, error) {
|
||||
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||
queries, err := ListInstanceDomainsRequestToModel(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domains, err := s.query.SearchInstanceDomains(ctx, queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &system_pb.ListDomainsResponse{
|
||||
Result: instance_grpc.DomainsToPb(domains.Domains),
|
||||
Details: object.ToListDetails(
|
||||
domains.Count,
|
||||
domains.Sequence,
|
||||
domains.Timestamp,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) AddDomain(ctx context.Context, req *system_pb.AddDomainRequest) (*system_pb.AddDomainResponse, error) {
|
||||
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||
instance, err := s.query.Instance(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx = authz.WithInstance(ctx, instance)
|
||||
details, err := s.command.AddInstanceDomain(ctx, req.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &system_pb.AddDomainResponse{
|
||||
Details: object.AddToDetailsPb(
|
||||
details.Sequence,
|
||||
details.EventDate,
|
||||
details.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) RemoveDomain(ctx context.Context, req *system_pb.RemoveDomainRequest) (*system_pb.RemoveDomainResponse, error) {
|
||||
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||
details, err := s.command.RemoveInstanceDomain(ctx, req.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &system_pb.RemoveDomainResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
details.Sequence,
|
||||
details.EventDate,
|
||||
details.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) SetPrimaryDomain(ctx context.Context, req *system_pb.SetPrimaryDomainRequest) (*system_pb.SetPrimaryDomainResponse, error) {
|
||||
ctx = authz.WithInstanceID(ctx, req.Id)
|
||||
details, err := s.command.SetPrimaryInstanceDomain(ctx, req.Domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &system_pb.SetPrimaryDomainResponse{
|
||||
Details: object.ChangeToDetailsPb(
|
||||
details.Sequence,
|
||||
details.EventDate,
|
||||
details.ResourceOwner,
|
||||
),
|
||||
}, nil
|
||||
}
|
97
internal/api/grpc/system/instance_converter.go
Normal file
97
internal/api/grpc/system/instance_converter.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
instance_grpc "github.com/caos/zitadel/internal/api/grpc/instance"
|
||||
"github.com/caos/zitadel/internal/api/grpc/object"
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
instance_pb "github.com/caos/zitadel/pkg/grpc/instance"
|
||||
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||
)
|
||||
|
||||
func AddInstancePbToSetupInstance(req *system_pb.AddInstanceRequest, defaultInstance command.InstanceSetup) *command.InstanceSetup {
|
||||
if req.InstanceName != "" {
|
||||
defaultInstance.InstanceName = req.InstanceName
|
||||
defaultInstance.Org.Name = req.InstanceName
|
||||
}
|
||||
if req.CustomDomain != "" {
|
||||
defaultInstance.CustomDomain = req.CustomDomain
|
||||
}
|
||||
if req.FirstOrgName != "" {
|
||||
defaultInstance.Org.Name = req.FirstOrgName
|
||||
}
|
||||
if req.OwnerEmail != "" {
|
||||
defaultInstance.Org.Human.Email.Address = req.OwnerEmail
|
||||
}
|
||||
if req.OwnerUsername != "" {
|
||||
defaultInstance.Org.Human.Username = req.OwnerUsername
|
||||
}
|
||||
if req.OwnerFirstName != "" {
|
||||
defaultInstance.Org.Human.FirstName = req.OwnerFirstName
|
||||
}
|
||||
if req.OwnerLastName != "" {
|
||||
defaultInstance.Org.Human.LastName = req.OwnerLastName
|
||||
}
|
||||
return &defaultInstance
|
||||
}
|
||||
func ListInstancesRequestToModel(req *system_pb.ListInstancesRequest) (*query.InstanceSearchQueries, error) {
|
||||
offset, limit, asc := object.ListQueryToModel(req.Query)
|
||||
queries, err := instance_grpc.InstanceQueriesToModel(req.Queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.InstanceSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: fieldNameToInstanceColumn(req.SortingColumn),
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func fieldNameToInstanceColumn(fieldName instance_pb.FieldName) query.Column {
|
||||
switch fieldName {
|
||||
case instance_pb.FieldName_FIELD_NAME_ID:
|
||||
return query.InstanceColumnID
|
||||
case instance_pb.FieldName_FIELD_NAME_NAME:
|
||||
return query.InstanceColumnName
|
||||
case instance_pb.FieldName_FIELD_NAME_CREATION_DATE:
|
||||
return query.InstanceColumnCreationDate
|
||||
default:
|
||||
return query.Column{}
|
||||
}
|
||||
}
|
||||
|
||||
func ListInstanceDomainsRequestToModel(req *system_pb.ListDomainsRequest) (*query.InstanceDomainSearchQueries, error) {
|
||||
offset, limit, asc := object.ListQueryToModel(req.Query)
|
||||
queries, err := instance_grpc.DomainQueriesToModel(req.Queries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &query.InstanceDomainSearchQueries{
|
||||
SearchRequest: query.SearchRequest{
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
Asc: asc,
|
||||
SortingColumn: fieldNameToInstanceDomainColumn(req.SortingColumn),
|
||||
},
|
||||
Queries: queries,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func fieldNameToInstanceDomainColumn(fieldName instance_pb.DomainFieldName) query.Column {
|
||||
switch fieldName {
|
||||
case instance_pb.DomainFieldName_DOMAIN_FIELD_NAME_DOMAIN:
|
||||
return query.InstanceDomainDomainCol
|
||||
case instance_pb.DomainFieldName_DOMAIN_FIELD_NAME_GENERATED:
|
||||
return query.InstanceDomainIsGeneratedCol
|
||||
case instance_pb.DomainFieldName_DOMAIN_FIELD_NAME_PRIMARY:
|
||||
return query.InstanceDomainIsPrimaryCol
|
||||
case instance_pb.DomainFieldName_DOMAIN_FIELD_NAME_CREATION_DATE:
|
||||
return query.InstanceDomainCreationDateCol
|
||||
default:
|
||||
return query.Column{}
|
||||
}
|
||||
}
|
75
internal/api/grpc/system/server.go
Normal file
75
internal/api/grpc/system/server.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/admin/repository"
|
||||
http_util "github.com/caos/zitadel/internal/api/http"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/caos/zitadel/internal/admin/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
"github.com/caos/zitadel/internal/api/grpc/server"
|
||||
"github.com/caos/zitadel/internal/command"
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
"github.com/caos/zitadel/pkg/grpc/system"
|
||||
)
|
||||
|
||||
const (
|
||||
systemAPI = "System-API"
|
||||
)
|
||||
|
||||
var _ system.SystemServiceServer = (*Server)(nil)
|
||||
|
||||
type Server struct {
|
||||
system.UnimplementedSystemServiceServer
|
||||
command *command.Commands
|
||||
query *query.Queries
|
||||
administrator repository.AdministratorRepository
|
||||
DefaultInstance command.InstanceSetup
|
||||
ExternalSecure bool
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Repository eventsourcing.Config
|
||||
}
|
||||
|
||||
func CreateServer(command *command.Commands,
|
||||
query *query.Queries,
|
||||
repo repository.Repository,
|
||||
defaultInstance command.InstanceSetup,
|
||||
externalPort uint16,
|
||||
externalDomain string,
|
||||
externalSecure bool) *Server {
|
||||
return &Server{
|
||||
command: command,
|
||||
query: query,
|
||||
administrator: repo,
|
||||
DefaultInstance: defaultInstance,
|
||||
ExternalSecure: externalSecure,
|
||||
BaseURL: http_util.BuildHTTP(externalDomain, externalPort, externalSecure),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
|
||||
system.RegisterSystemServiceServer(grpcServer, s)
|
||||
}
|
||||
|
||||
func (s *Server) AppName() string {
|
||||
return systemAPI
|
||||
}
|
||||
|
||||
func (s *Server) MethodPrefix() string {
|
||||
return system.SystemService_MethodPrefix
|
||||
}
|
||||
|
||||
func (s *Server) AuthMethods() authz.MethodMapping {
|
||||
return system.SystemService_AuthMethods
|
||||
}
|
||||
|
||||
func (s *Server) RegisterGateway() server.GatewayFunc {
|
||||
return system.RegisterSystemServiceHandlerFromEndpoint
|
||||
}
|
||||
|
||||
func (s *Server) GatewayPathPrefix() string {
|
||||
return "/system/v1"
|
||||
}
|
37
internal/api/grpc/system/view.go
Normal file
37
internal/api/grpc/system/view.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||
)
|
||||
|
||||
func (s *Server) ListViews(ctx context.Context, _ *system_pb.ListViewsRequest) (*system_pb.ListViewsResponse, error) {
|
||||
currentSequences, err := s.query.SearchCurrentSequences(ctx, new(query.CurrentSequencesSearchQueries))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
convertedCurrentSequences := CurrentSequencesToPb(currentSequences)
|
||||
views, err := s.administrator.GetViews()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
convertedViews := ViewsToPb(views)
|
||||
|
||||
convertedCurrentSequences = append(convertedCurrentSequences, convertedViews...)
|
||||
return &system_pb.ListViewsResponse{Result: convertedCurrentSequences}, nil
|
||||
}
|
||||
|
||||
func (s *Server) ClearView(ctx context.Context, req *system_pb.ClearViewRequest) (*system_pb.ClearViewResponse, error) {
|
||||
var err error
|
||||
if req.Database != "zitadel" {
|
||||
err = s.administrator.ClearView(ctx, req.Database, req.ViewName)
|
||||
} else {
|
||||
err = s.query.ClearCurrentSequence(ctx, req.ViewName)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &system_pb.ClearViewResponse{}, nil
|
||||
}
|
43
internal/api/grpc/system/view_converter.go
Normal file
43
internal/api/grpc/system/view_converter.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/query"
|
||||
"github.com/caos/zitadel/internal/view/model"
|
||||
system_pb "github.com/caos/zitadel/pkg/grpc/system"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func ViewsToPb(views []*model.View) []*system_pb.View {
|
||||
v := make([]*system_pb.View, len(views))
|
||||
for i, view := range views {
|
||||
v[i] = ViewToPb(view)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func ViewToPb(view *model.View) *system_pb.View {
|
||||
return &system_pb.View{
|
||||
Database: view.Database,
|
||||
ViewName: view.ViewName,
|
||||
LastSuccessfulSpoolerRun: timestamppb.New(view.LastSuccessfulSpoolerRun),
|
||||
ProcessedSequence: view.CurrentSequence,
|
||||
EventTimestamp: timestamppb.New(view.EventTimestamp),
|
||||
}
|
||||
}
|
||||
|
||||
func CurrentSequencesToPb(currentSequences *query.CurrentSequences) []*system_pb.View {
|
||||
v := make([]*system_pb.View, len(currentSequences.CurrentSequences))
|
||||
for i, currentSequence := range currentSequences.CurrentSequences {
|
||||
v[i] = CurrentSequenceToPb(currentSequence)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func CurrentSequenceToPb(currentSequence *query.CurrentSequence) *system_pb.View {
|
||||
return &system_pb.View{
|
||||
Database: "zitadel",
|
||||
ViewName: currentSequence.ProjectionName,
|
||||
ProcessedSequence: currentSequence.CurrentSequence,
|
||||
EventTimestamp: timestamppb.New(currentSequence.Timestamp),
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user