mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-07 23:12:02 +00:00
feat: Add ListInstances endpoint (#9452)
This commit is contained in:
@@ -2,11 +2,22 @@ package instance
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/zitadel/zitadel/cmd/build"
|
"github.com/zitadel/zitadel/cmd/build"
|
||||||
|
filter "github.com/zitadel/zitadel/internal/api/grpc/filter/v2beta"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||||
|
"github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
"github.com/zitadel/zitadel/pkg/grpc/instance/v2"
|
"github.com/zitadel/zitadel/pkg/grpc/instance/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func InstancesToPb(instances []*query.Instance) []*instance.Instance {
|
||||||
|
list := []*instance.Instance{}
|
||||||
|
for i, instance := range instances {
|
||||||
|
list[i] = ToProtoObject(instance)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
func ToProtoObject(inst *query.Instance) *instance.Instance {
|
func ToProtoObject(inst *query.Instance) *instance.Instance {
|
||||||
return &instance.Instance{
|
return &instance.Instance{
|
||||||
Id: inst.ID,
|
Id: inst.ID,
|
||||||
@@ -39,3 +50,61 @@ func DomainToPb(d *query.InstanceDomain) *instance.Domain {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ListInstancesRequestToModel(req *instance.ListInstancesRequest, sysDefaults systemdefaults.SystemDefaults) (*query.InstanceSearchQueries, error) {
|
||||||
|
offset, limit, asc, err := filter.PaginationPbToQuery(sysDefaults, req.GetPagination())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
queries, err := 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.FieldName) query.Column {
|
||||||
|
switch fieldName {
|
||||||
|
case instance.FieldName_FIELD_NAME_ID:
|
||||||
|
return query.InstanceColumnID
|
||||||
|
case instance.FieldName_FIELD_NAME_NAME:
|
||||||
|
return query.InstanceColumnName
|
||||||
|
case instance.FieldName_FIELD_NAME_CREATION_DATE:
|
||||||
|
return query.InstanceColumnCreationDate
|
||||||
|
default:
|
||||||
|
return query.Column{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func instanceQueriesToModel(queries []*instance.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.Query) (query.SearchQuery, error) {
|
||||||
|
switch q := searchQuery.Query.(type) {
|
||||||
|
case *instance.Query_IdQuery:
|
||||||
|
return query.NewInstanceIDsListSearchQuery(q.IdQuery.Ids...)
|
||||||
|
case *instance.Query_DomainQuery:
|
||||||
|
return query.NewInstanceDomainsListSearchQuery(q.DomainQuery.Domains...)
|
||||||
|
default:
|
||||||
|
return nil, zerrors.ThrowInvalidArgument(nil, "INST-3m0se", "List.Query.Invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package instance
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
filter "github.com/zitadel/zitadel/pkg/grpc/filter/v2beta"
|
||||||
"github.com/zitadel/zitadel/pkg/grpc/instance/v2"
|
"github.com/zitadel/zitadel/pkg/grpc/instance/v2"
|
||||||
"google.golang.org/protobuf/types/known/emptypb"
|
"google.golang.org/protobuf/types/known/emptypb"
|
||||||
)
|
)
|
||||||
@@ -17,3 +18,23 @@ func (s *Server) GetInstance(ctx context.Context, _ *emptypb.Empty) (*instance.G
|
|||||||
Instance: ToProtoObject(inst),
|
Instance: ToProtoObject(inst),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListInstances(ctx context.Context, req *instance.ListInstancesRequest) (*instance.ListInstancesResponse, error) {
|
||||||
|
queries, err := ListInstancesRequestToModel(req, s.systemDefaults)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
instances, err := s.query.SearchInstances(ctx, queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &instance.ListInstancesResponse{
|
||||||
|
Instances: InstancesToPb(instances.Instances),
|
||||||
|
Pagination: &filter.PaginationResponse{
|
||||||
|
TotalResult: instances.Count,
|
||||||
|
AppliedLimit: uint64(req.GetPagination().GetLimit()),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||||
"github.com/zitadel/zitadel/internal/command"
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
|
"github.com/zitadel/zitadel/internal/config/systemdefaults"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/pkg/grpc/instance/v2"
|
"github.com/zitadel/zitadel/pkg/grpc/instance/v2"
|
||||||
@@ -18,6 +19,7 @@ type Server struct {
|
|||||||
command *command.Commands
|
command *command.Commands
|
||||||
query *query.Queries
|
query *query.Queries
|
||||||
checkPermission domain.PermissionCheck
|
checkPermission domain.PermissionCheck
|
||||||
|
systemDefaults systemdefaults.SystemDefaults
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct{}
|
type Config struct{}
|
||||||
@@ -26,11 +28,13 @@ func CreateServer(
|
|||||||
command *command.Commands,
|
command *command.Commands,
|
||||||
query *query.Queries,
|
query *query.Queries,
|
||||||
checkPermission domain.PermissionCheck,
|
checkPermission domain.PermissionCheck,
|
||||||
|
systemDefaults systemdefaults.SystemDefaults,
|
||||||
) *Server {
|
) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
command: command,
|
command: command,
|
||||||
query: query,
|
query: query,
|
||||||
checkPermission: checkPermission,
|
checkPermission: checkPermission,
|
||||||
|
systemDefaults: systemDefaults,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ syntax = "proto3";
|
|||||||
|
|
||||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
import "zitadel/object/v2/object.proto";
|
import "zitadel/object/v2/object.proto";
|
||||||
|
import "validate/validate.proto";
|
||||||
|
|
||||||
package zitadel.instance.v2;
|
package zitadel.instance.v2;
|
||||||
|
|
||||||
@@ -50,3 +51,38 @@ message Domain {
|
|||||||
bool primary = 3;
|
bool primary = 3;
|
||||||
bool generated = 4;
|
bool generated = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FieldName {
|
||||||
|
FIELD_NAME_UNSPECIFIED = 0;
|
||||||
|
FIELD_NAME_ID = 1;
|
||||||
|
FIELD_NAME_NAME = 2;
|
||||||
|
FIELD_NAME_CREATION_DATE = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Query {
|
||||||
|
oneof query {
|
||||||
|
option (validate.required) = true;
|
||||||
|
|
||||||
|
IdsQuery id_query = 1;
|
||||||
|
DomainsQuery domain_query = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message IdsQuery {
|
||||||
|
repeated string ids = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "4820840938402429";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
message DomainsQuery {
|
||||||
|
repeated string domains = 1 [
|
||||||
|
(validate.rules).repeated = {max_items: 20, items: {string: {min_len: 1, max_len: 100}}},
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
max_items: 20,
|
||||||
|
example: "[\"my-instace.zitadel.cloud\", \"auth.custom.com\"]";
|
||||||
|
description: "Return the instances that have the requested domains";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ package zitadel.instance.v2;
|
|||||||
import "validate/validate.proto";
|
import "validate/validate.proto";
|
||||||
import "zitadel/object/v2/object.proto";
|
import "zitadel/object/v2/object.proto";
|
||||||
import "zitadel/instance/v2/instance.proto";
|
import "zitadel/instance/v2/instance.proto";
|
||||||
|
import "zitadel/filter/v2beta/filter.proto";
|
||||||
import "google/protobuf/empty.proto";
|
import "google/protobuf/empty.proto";
|
||||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
import "google/api/annotations.proto";
|
import "google/api/annotations.proto";
|
||||||
@@ -137,6 +138,30 @@ message UpdateInstanceResponse {
|
|||||||
zitadel.object.v2.Details details = 1;
|
zitadel.object.v2.Details details = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ListInstancesRequest {
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
|
||||||
|
json_schema: {
|
||||||
|
description: "Search query for lists";
|
||||||
|
required: ["query"]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// pagination and sorting
|
||||||
|
zitadel.filter.v2beta.PaginationRequest pagination = 1;
|
||||||
|
// the field the result is sorted
|
||||||
|
FieldName sorting_column = 2;
|
||||||
|
// criterias the client is looking for
|
||||||
|
repeated Query queries = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListInstancesResponse {
|
||||||
|
// the list of instances
|
||||||
|
repeated Instance instances = 1;
|
||||||
|
|
||||||
|
// contains the total number of instances matching the query and the applied limit
|
||||||
|
zitadel.filter.v2beta.PaginationResponse pagination = 2;
|
||||||
|
}
|
||||||
|
|
||||||
service InstanceService {
|
service InstanceService {
|
||||||
|
|
||||||
// DeleteInstance deletes an instance with the given ID.
|
// DeleteInstance deletes an instance with the given ID.
|
||||||
@@ -229,10 +254,39 @@ service InstanceService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateInstance
|
// ListInstances lists instances matching the given query.
|
||||||
// ListInstances
|
//
|
||||||
|
// The query can be used to filter either by instance ID or domain.
|
||||||
|
// The request is paginated and returns 100 results by default.
|
||||||
|
rpc ListInstances(ListInstancesRequest) returns (ListInstancesResponse) {
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
description: "Lists instances matching the given query.";
|
||||||
|
tags: "Instance";
|
||||||
|
responses: {
|
||||||
|
key: "200";
|
||||||
|
value: {
|
||||||
|
description: "The list of instances.";
|
||||||
|
schema: {
|
||||||
|
json_schema: {
|
||||||
|
ref: "#/definitions/ListInstancesResponse";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v2/instances"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "system.instance.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add Custom Domain
|
// Add Custom Domain
|
||||||
// Remove Custom Domain
|
// Remove Custom Domain
|
||||||
|
|||||||
Reference in New Issue
Block a user