From 4d5cbc94e269783ec0c6f8e37a19a3d76e7abcab Mon Sep 17 00:00:00 2001 From: Iraq Jaber Date: Fri, 2 May 2025 12:10:30 +0200 Subject: [PATCH] fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! refactor(api): moving organization API resourced based added AddOrganizationDomain & ListOrganizationDomain() --- internal/api/grpc/instance/converter.go | 4 +- internal/api/grpc/management/org_converter.go | 4 +- internal/api/grpc/object/v2beta/converter.go | 58 ++- internal/api/grpc/org/v2beta/helper.go | 54 ++- internal/api/grpc/org/v2beta/org.go | 72 +++ proto/zitadel/org/v2beta/org.proto | 81 +++- proto/zitadel/org/v2beta/org_service.proto | 417 +++++++++++++++--- 7 files changed, 613 insertions(+), 77 deletions(-) diff --git a/internal/api/grpc/instance/converter.go b/internal/api/grpc/instance/converter.go index 4094da4a77..0a6aff4348 100644 --- a/internal/api/grpc/instance/converter.go +++ b/internal/api/grpc/instance/converter.go @@ -28,7 +28,7 @@ func InstanceToPb(instance *query.Instance) *instance_pb.Instance { Name: instance.Name, Domains: DomainsToPb(instance.Domains), Version: build.Version(), - State: instance_pb.State_STATE_RUNNING, //TODO: change when delete is implemented + State: instance_pb.State_STATE_RUNNING, // TODO: change when delete is implemented } } @@ -44,7 +44,7 @@ func InstanceDetailToPb(instance *query.Instance) *instance_pb.InstanceDetail { Name: instance.Name, Domains: DomainsToPb(instance.Domains), Version: build.Version(), - State: instance_pb.State_STATE_RUNNING, //TODO: change when delete is implemented + State: instance_pb.State_STATE_RUNNING, // TODO: change when delete is implemented } } diff --git a/internal/api/grpc/management/org_converter.go b/internal/api/grpc/management/org_converter.go index 879b5e0763..e80641dab0 100644 --- a/internal/api/grpc/management/org_converter.go +++ b/internal/api/grpc/management/org_converter.go @@ -26,7 +26,7 @@ func ListOrgDomainsRequestToModel(req *mgmt_pb.ListOrgDomainsRequest) (*query.Or Limit: limit, Asc: asc, }, - //SortingColumn: //TODO: sorting + // SortingColumn: //TODO: sorting Queries: queries, }, nil } @@ -89,7 +89,7 @@ func ListOrgMembersRequestToModel(ctx context.Context, req *mgmt_pb.ListOrgMembe Offset: offset, Limit: limit, Asc: asc, - //SortingColumn: //TODO: sorting + // SortingColumn: //TODO: sorting }, Queries: queries, }, diff --git a/internal/api/grpc/object/v2beta/converter.go b/internal/api/grpc/object/v2beta/converter.go index 74d1c119e3..a28f2cf0bb 100644 --- a/internal/api/grpc/object/v2beta/converter.go +++ b/internal/api/grpc/object/v2beta/converter.go @@ -2,6 +2,7 @@ package object import ( "context" + "time" "google.golang.org/protobuf/types/known/timestamppb" @@ -9,7 +10,8 @@ import ( "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/query" object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta" - // object_pb "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" + + org_pb "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" ) func DomainToDetailsPb(objectDetail *domain.ObjectDetails) *object.Details { @@ -82,3 +84,57 @@ func ListQueryToModel(query *object.ListQuery) (offset, limit uint64, asc bool) } return query.Offset, uint64(query.Limit), query.Asc } + +func DomainsToPb(domains []*query.Domain) []*org_pb.Domain { + d := make([]*org_pb.Domain, len(domains)) + for i, domain := range domains { + d[i] = DomainToPb(domain) + } + return d +} + +func DomainToPb(d *query.Domain) *org_pb.Domain { + return &org_pb.Domain{ + OrgId: d.OrgID, + DomainName: d.Domain, + IsVerified: d.IsVerified, + IsPrimary: d.IsPrimary, + ValidationType: DomainValidationTypeFromModel(d.ValidationType), + Details: ToViewDetailsPb( + d.Sequence, + d.CreationDate, + d.ChangeDate, + d.OrgID, + ), + } +} + +func DomainValidationTypeFromModel(validationType domain.OrgDomainValidationType) org_pb.DomainValidationType { + switch validationType { + case domain.OrgDomainValidationTypeDNS: + return org_pb.DomainValidationType_DOMAIN_VALIDATION_TYPE_DNS + case domain.OrgDomainValidationTypeHTTP: + return org_pb.DomainValidationType_DOMAIN_VALIDATION_TYPE_HTTP + default: + return org_pb.DomainValidationType_DOMAIN_VALIDATION_TYPE_UNSPECIFIED + } +} + +func ToViewDetailsPb( + sequence uint64, + creationDate, + changeDate time.Time, + resourceOwner string, +) *object.Details { + details := &object.Details{ + Sequence: sequence, + ResourceOwner: resourceOwner, + } + if !creationDate.IsZero() { + details.CreationDate = timestamppb.New(creationDate) + } + if !changeDate.IsZero() { + details.ChangeDate = timestamppb.New(changeDate) + } + return details +} diff --git a/internal/api/grpc/org/v2beta/helper.go b/internal/api/grpc/org/v2beta/helper.go index a43aff45e2..cfd373518a 100644 --- a/internal/api/grpc/org/v2beta/helper.go +++ b/internal/api/grpc/org/v2beta/helper.go @@ -53,14 +53,14 @@ func OrganizationViewToPb(org *query.Org) *org_pb.Organization { } } -func OrgStateToPb(state domain.OrgState) org_pb.OrganizationState { +func OrgStateToPb(state domain.OrgState) org_pb.OrgState { switch state { case domain.OrgStateActive: - return org_pb.OrganizationState_ORGANIZATION_STATE_ACTIVE + return org_pb.OrgState_ORG_STATE_ACTIVE case domain.OrgStateInactive: - return org_pb.OrganizationState_ORGANIZATION_STATE_INACTIVE + return org_pb.OrgState_ORG_STATE_INACTIVE default: - return org_pb.OrganizationState_ORGANIZATION_STATE_UNSPECIFIED + return org_pb.OrgState_ORG_STATE_UNSPECIFIED } } @@ -171,3 +171,49 @@ func OrgViewToPb(org *query.Org) *org_pb.Organization { ), } } + +func ListOrgDomainsRequestToModel(req *org.ListOrganizationDomainsRequest) (*query.OrgDomainSearchQueries, error) { + offset, limit, asc := ListQueryToModel(req.Query) + // queries, err := org_grpc.DomainQueriesToModel(req.Queries) + queries, err := DomainQueriesToModel(req.Queries) + if err != nil { + return nil, err + } + return &query.OrgDomainSearchQueries{ + SearchRequest: query.SearchRequest{ + Offset: offset, + Limit: limit, + Asc: asc, + }, + // SortingColumn: //TODO: sorting + Queries: queries, + }, nil +} + +func ListQueryToModel(query *v2beta.ListQuery) (offset, limit uint64, asc bool) { + if query == nil { + return 0, 0, false + } + return query.Offset, uint64(query.Limit), query.Asc +} + +func DomainQueriesToModel(queries []*org_pb.DomainSearchQuery) (_ []query.SearchQuery, err error) { + q := make([]query.SearchQuery, len(queries)) + for i, query := range queries { + q[i], err = DomainQueryToModel(query) + if err != nil { + return nil, err + } + } + return q, nil +} + +func DomainQueryToModel(searchQuery *org_pb.DomainSearchQuery) (query.SearchQuery, error) { + switch q := searchQuery.Query.(type) { + case *org_pb.DomainSearchQuery_DomainNameQuery: + // return query.NewOrgDomainDomainSearchQuery(object.TextMethodToQuery(q.DomainNameQuery.Method), q.DomainNameQuery.Name) + return query.NewOrgDomainDomainSearchQuery(v2beta_object.TextMethodToQuery(q.DomainNameQuery.Method), q.DomainNameQuery.Name) + default: + return nil, zerrors.ThrowInvalidArgument(nil, "ORG-Ags89", "List.Query.Invalid") + } +} diff --git a/internal/api/grpc/org/v2beta/org.go b/internal/api/grpc/org/v2beta/org.go index 092436385c..b38d2ade5e 100644 --- a/internal/api/grpc/org/v2beta/org.go +++ b/internal/api/grpc/org/v2beta/org.go @@ -3,9 +3,11 @@ package org import ( "context" + "github.com/zitadel/zitadel/internal/api/authz" object "github.com/zitadel/zitadel/internal/api/grpc/object/v2beta" user "github.com/zitadel/zitadel/internal/api/grpc/user/v2beta" "github.com/zitadel/zitadel/internal/command" + "github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/zerrors" org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" v2beta_org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" @@ -89,6 +91,51 @@ func (s *Server) ReactivateOrganization(ctx context.Context, request *org.Reacti }, err } +func (s *Server) AddOrganizationDomain(ctx context.Context, request *org.AddOrganizationDomainRequest) (*org.AddOrganizationDomainResponse, error) { + userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Domain, request.OrganizationId) + if err != nil { + return nil, err + } + details, err := s.command.AddOrgDomain(ctx, request.OrganizationId, request.Domain, userIDs) + if err != nil { + return nil, err + } + return &org.AddOrganizationDomainResponse{ + Details: object.DomainToDetailsPb(details), + }, nil +} + +func (s *Server) ListOrganizationDomains(ctx context.Context, req *org.ListOrganizationDomainsRequest) (*org.ListOrganizationDomainsResponse, error) { + queries, err := ListOrgDomainsRequestToModel(req) + if err != nil { + return nil, err + } + orgIDQuery, err := query.NewOrgDomainOrgIDSearchQuery(authz.GetCtxData(ctx).OrgID) + if err != nil { + return nil, err + } + queries.Queries = append(queries.Queries, orgIDQuery) + + domains, err := s.query.SearchOrgDomains(ctx, queries, false) + if err != nil { + return nil, err + } + return &org.ListOrganizationDomainsResponse{ + Result: object.DomainsToPb(domains.Domains), + Details: object.ToListDetails(domains.SearchResponse), + }, nil +} + +// func (s *Server) RemoveOrganizagtionDomain(ctx context.Context, req *mgmt_pb.RemoveOrgDomainRequest) (*mgmt_pb.RemoveOrgDomainResponse, error) { +// details, err := s.command.RemoveOrgDomain(ctx, RemoveOrgDomainRequestToDomain(ctx, req)) +// if err != nil { +// return nil, err +// } +// return &mgmt_pb.RemoveOrgDomainResponse{ +// Details: object.DomainToChangeDetailsPb(details), +// }, err +// } + func createOrganizationRequestToCommand(request *v2beta_org.CreateOrganizationRequest) (*command.OrgSetup, error) { admins, err := createOrganizationRequestAdminsToCommand(request.GetAdmins()) if err != nil { @@ -132,3 +179,28 @@ func createOrganizationRequestAdminToCommand(admin *v2beta_org.CreateOrganizatio return nil, zerrors.ThrowUnimplementedf(nil, "ORGv2-SD2r1", "userType oneOf %T in method AddOrganization not implemented", a) } } + +func (s *Server) getClaimedUserIDsOfOrgDomain(ctx context.Context, orgDomain, orgID string) ([]string, error) { + queries := make([]query.SearchQuery, 0, 2) + loginName, err := query.NewUserPreferredLoginNameSearchQuery("@"+orgDomain, query.TextEndsWithIgnoreCase) + if err != nil { + return nil, err + } + queries = append(queries, loginName) + if orgID != "" { + owner, err := query.NewUserResourceOwnerSearchQuery(orgID, query.TextNotEquals) + if err != nil { + return nil, err + } + queries = append(queries, owner) + } + users, err := s.query.SearchUsers(ctx, &query.UserSearchQueries{Queries: queries}, nil) + if err != nil { + return nil, err + } + userIDs := make([]string, len(users.Users)) + for i, user := range users.Users { + userIDs[i] = user.ID + } + return userIDs, nil +} diff --git a/proto/zitadel/org/v2beta/org.proto b/proto/zitadel/org/v2beta/org.proto index baa0181eb4..33d3846d41 100644 --- a/proto/zitadel/org/v2beta/org.proto +++ b/proto/zitadel/org/v2beta/org.proto @@ -17,7 +17,7 @@ message Organization { ]; zitadel.object.v2beta.Details details = 2; // Current state of the organization, for example active, inactive and deleted. - OrganizationState state = 3; + OrgState state = 3; // Name of the organization. string name = 4 [ (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { @@ -32,12 +32,16 @@ message Organization { ]; } -// TODO rename to OrgState -enum OrganizationState { - ORGANIZATION_STATE_UNSPECIFIED = 0; - ORGANIZATION_STATE_ACTIVE = 1; - ORGANIZATION_STATE_INACTIVE = 2; - ORGANIZATION_STATE_REMOVED = 3; +enum OrgState { + ORG_STATE_UNSPECIFIED = 0; + ORG_STATE_ACTIVE = 1; + ORG_STATE_INACTIVE = 2; + ORG_STATE_REMOVED = 3; +} + +enum OrgFieldName { + ORG_FIELD_NAME_UNSPECIFIED = 0; + ORG_FIELD_NAME_NAME = 1; } message OrgQuery { @@ -81,7 +85,7 @@ message OrgDomainQuery { } message OrgStateQuery { - OrganizationState state = 1 [ + OrgState state = 1 [ (validate.rules).enum.defined_only = true, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "current state of the organization"; @@ -98,3 +102,64 @@ message OrgIDQuery { ]; } +// from proto/zitadel/org.proto +message DomainSearchQuery { + oneof query { + option (validate.required) = true; + + DomainNameQuery domain_name_query = 1; + } +} + +// from proto/zitadel/org.proto +message DomainNameQuery { + string name = 1 [ + (validate.rules).string = {max_len: 200}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"zitadel.cloud\""; + } + ]; + zitadel.object.v2beta.TextQueryMethod method = 2 [ + (validate.rules).enum.defined_only = true, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "defines which text equality method is used"; + } + ]; +} + +// from proto/zitadel/org.proto +message Domain { + string org_id = 1 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"69629023906488334\"" + } + ]; + zitadel.object.v2beta.Details details = 2; + string domain_name = 3 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"zitadel.com\""; + } + ]; + bool is_verified = 4 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "defines if the domain is verified" + } + ]; + bool is_primary = 5 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "defines if the domain is the primary domain" + } + ]; + DomainValidationType validation_type = 6 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "defines the protocol the domain was validated with"; + } + ]; +} + +// from proto/zitadel/org.proto +enum DomainValidationType { + DOMAIN_VALIDATION_TYPE_UNSPECIFIED = 0; + DOMAIN_VALIDATION_TYPE_HTTP = 1; + DOMAIN_VALIDATION_TYPE_DNS = 2; +} diff --git a/proto/zitadel/org/v2beta/org_service.proto b/proto/zitadel/org/v2beta/org_service.proto index 49076fb643..753ff0569a 100644 --- a/proto/zitadel/org/v2beta/org_service.proto +++ b/proto/zitadel/org/v2beta/org_service.proto @@ -109,7 +109,7 @@ service OrganizationService { // Create a new organization and grant the user(s) permission to manage it rpc CreateOrganization(CreateOrganizationRequest) returns (CreateOrganizationResponse) { option (google.api.http) = { - post: "/v2beta/organizations" + post: "/v2beta/organization" body: "*" }; @@ -136,7 +136,7 @@ service OrganizationService { rpc UpdateOrganization(UpdateOrganizationRequest) returns (UpdateOrganizationResponse) { option (google.api.http) = { - put: "/v2beta/organizations" + put: "/v2beta/organization" body: "*" }; @@ -162,75 +162,75 @@ service OrganizationService { }; } - rpc GetOrganizationByID(GetOrganizationByIDRequest) returns (GetOrganizationByIDResponse) { - option (google.api.http) = { - get: "/v2beta/organizations" - }; + rpc GetOrganizationByID(GetOrganizationByIDRequest) returns (GetOrganizationByIDResponse) { + option (google.api.http) = { + get: "/v2beta/organization" + }; - option (zitadel.protoc_gen_zitadel.v2.options) = { - auth_option: { - permission: "iam.read"; - } - http_response: { - success_code: 200 - } - }; + option (zitadel.protoc_gen_zitadel.v2.options) = { + auth_option: { + permission: "iam.read"; + } + http_response: { + success_code: 200 + } + }; - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - tags: "Organizations"; - summary: "Get Organization By ID"; - description: "Returns an organization by its ID." - responses: { - key: "200"; - value: { - description: "requested organization found"; - }; - }; - }; - } - - rpc ListOrganizations(ListOrganizationsRequest) returns (ListOrganizationsResponse) { - option (google.api.http) = { - post: "/v2beta/organizations/_search"; - body: "*"; - }; - - option (zitadel.protoc_gen_zitadel.v2.options) = { - auth_option: { - permission: "iam.read"; - } - http_response: { - success_code: 200 - } - }; - - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { - tags: "Organizations"; - summary: "Search Organization"; - description: "Returns a list of organizations that match the requesting filters. All filters are applied with an AND condition." - responses: { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags: "Organizations"; + summary: "Get Organization By ID"; + description: "Returns an organization by its ID." + responses: { key: "200"; value: { - description: "list of organizations matching the query"; + description: "requested organization found"; }; + }; + }; + } + + rpc ListOrganizations(ListOrganizationsRequest) returns (ListOrganizationsResponse) { + option (google.api.http) = { + post: "/v2beta/organization/_search"; + body: "*"; + }; + + option (zitadel.protoc_gen_zitadel.v2.options) = { + auth_option: { + permission: "iam.read"; + } + http_response: { + success_code: 200 + } + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags: "Organizations"; + summary: "Search Organization"; + description: "Returns a list of organizations that match the requesting filters. All filters are applied with an AND condition." + responses: { + key: "200"; + value: { + description: "list of organizations matching the query"; }; - responses: { - key: "400"; - value: { - description: "invalid list query"; - schema: { - json_schema: { - ref: "#/definitions/rpcStatus"; - }; + }; + responses: { + key: "400"; + value: { + description: "invalid list query"; + schema: { + json_schema: { + ref: "#/definitions/rpcStatus"; }; }; }; }; - } + }; + } rpc DeleteOrganization(DeleteOrganizationRequest) returns (DeleteOrganizationResponse) { option (google.api.http) = { - delete: "/v2beta/organizations" + delete: "/v2beta/organization" }; option (zitadel.protoc_gen_zitadel.v2.options) = { @@ -268,7 +268,7 @@ service OrganizationService { rpc DeactivateOrganization(DeactivateOrganizationRequest) returns (DeactivateOrganizationResponse) { option (google.api.http) = { - post: "/v2beta/_deactivate" + post: "/v2beta/organization/_deactivate" body: "*" }; @@ -298,7 +298,7 @@ service OrganizationService { rpc ReactivateOrganization(ReactivateOrganizationRequest) returns (ReactivateOrganizationResponse) { option (google.api.http) = { - post: "/orgs/me/_reactivate" + post: "/v2beta/organization/_reactivate" body: "*" }; @@ -326,6 +326,250 @@ service OrganizationService { }; } + // rpc SetOrganizationMetadata(SetOrganizationMetadataRequest) returns (SetOrganizationMetadataResponse) { + // option (google.api.http) = { + // post: "/v2beta/organization//metadata/{key}" + // body: "*" + // }; + + // option (zitadel.protoc_gen_zitadel.v2.options) = { + // auth_option: { + // permission: "org.write" + // } + // http_response: { + // success_code: 200 + // } + // }; + + // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + // tags: "Organizations"; + // tags: "Organization Metadata"; + // summary: "Set Organization Metadata"; + // description: "This endpoint either adds or updates a metadata value for the requested key. Make sure the value is base64 encoded." + // parameters: { + // headers: { + // name: "x-zitadel-orgid"; + // description: "The default is always the organization of the requesting user. If you like to get users of another organization include the header. Make sure the user has permission to access the requested data."; + // type: STRING, + // required: false; + // }; + // }; + // }; + // } + + // rpc BulkSetOrganizationMetadata(BulkSetOrganizationMetadataRequest) returns (BulkSetOrganizationMetadataResponse) { + // option (google.api.http) = { + // post: "/metadata/_bulk" + // body: "*" + // }; + + // option (zitadel.v1.auth_option) = { + // permission: "org.write" + // }; + + // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + // tags: "Organizations"; + // tags: "Organization Metadata"; + // summary: "Bulk Set Organization Metadata"; + // description: "This endpoint sets a list of metadata to the organization. Make sure the values are base64 encoded." + // parameters: { + // headers: { + // name: "x-zitadel-orgid"; + // description: "The default is always the organization of the requesting user. If you like to get users of another organization include the header. Make sure the user has permission to access the requested data."; + // type: STRING, + // required: false; + // }; + // }; + // }; + // } + + // rpc ListOrgMetadata(ListOrgMetadataRequest) returns (ListOrgMetadataResponse) { + // option (google.api.http) = { + // post: "/metadata/_search" + // body: "*" + // }; + + // option (zitadel.v1.auth_option) = { + // permission: "org.read" + // }; + + // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + // tags: "Organizations"; + // tags: "Organization Metadata"; + // summary: "Search Organization Metadata"; + // description: "Get the metadata of an organization filtered by your query." + // parameters: { + // headers: { + // name: "x-zitadel-orgid"; + // description: "The default is always the organization of the requesting user. If you like to get users of another organization include the header. Make sure the user has permission to access the requested data."; + // type: STRING, + // required: false; + // }; + // }; + // }; + // } + + // rpc GetOrgMetadata(GetOrgMetadataRequest) returns (GetOrgMetadataResponse) { + // option (google.api.http) = { + // get: "/metadata/{key}" + // }; + + // option (zitadel.v1.auth_option) = { + // permission: "org.read" + // }; + + // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + // tags: "Organizations"; + // tags: "Organization Metadata"; + // summary: "Get Organization Metadata By Key"; + // description: "Get a metadata object from an organization by a specific key." + // parameters: { + // headers: { + // name: "x-zitadel-orgid"; + // description: "The default is always the organization of the requesting user. If you like to get users of another organization include the header. Make sure the user has permission to access the requested data."; + // type: STRING, + // required: false; + // }; + // }; + // }; + // } + + // rpc RemoveOrgMetadata(RemoveOrgMetadataRequest) returns (RemoveOrgMetadataResponse) { + // option (google.api.http) = { + // delete: "/metadata/{key}" + // }; + + // option (zitadel.v1.auth_option) = { + // permission: "org.write" + // }; + + // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + // tags: "Organizations"; + // tags: "Organization Metadata"; + // summary: "Delete Organization Metadata By Key"; + // description: "Remove a metadata object from an organization with a specific key." + // parameters: { + // headers: { + // name: "x-zitadel-orgid"; + // description: "The default is always the organization of the requesting user. If you like to get users of another organization include the header. Make sure the user has permission to access the requested data."; + // type: STRING, + // required: false; + // }; + // }; + // }; + // } + + // rpc BulkRemoveOrgMetadata(BulkRemoveOrgMetadataRequest) returns (BulkRemoveOrgMetadataResponse) { + // option (google.api.http) = { + // delete: "/metadata/_bulk" + // body: "*" + // }; + + // option (zitadel.v1.auth_option) = { + // permission: "org.write" + // }; + + // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + // tags: "Organizations"; + // tags: "Organization Metadata"; + // summary: "Bulk Delete Metadata"; + // description: "Remove a list of metadata objects from an organization with a list of keys." + // parameters: { + // headers: { + // name: "x-zitadel-orgid"; + // description: "The default is always the organization of the requesting user. If you like to get/set a result of another organization include the header. Make sure the user has permission to access the requested data."; + // type: STRING, + // required: false; + // }; + // }; + // }; + // } + + // rpc ListOrganizationDomains(ListOrganizationDomainsRequest) returns (ListOrganizationDomainsResponse) { + // option (google.api.http) = { + // post: "/orgs/me/domains/_search" + // body: "*" + // }; + + // option (zitadel.v1.auth_option) = { + // permission: "org.read" + // }; + + // option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + // tags: "Organizations"; + // summary: "Search Domains"; + // description: "Returns the list of registered domains of an organization. The domains are used to identify to which organization a user belongs." + // parameters: { + // headers: { + // name: "x-zitadel-orgid"; + // description: "The default is always the organization of the requesting user. If you like to get/set a result of another organization include the header. Make sure the user has permission to access the requested data."; + // type: STRING, + // required: false; + // }; + // }; + // }; + // } + + rpc AddOrganizationDomain(AddOrganizationDomainRequest) returns (AddOrganizationDomainResponse) { + option (google.api.http) = { + post: "/v2beta/organization/domains" + body: "*" + }; + + option (zitadel.protoc_gen_zitadel.v2.options) = { + auth_option: { + permission: "org.write" + } + http_response: { + success_code: 201 + } + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags: "Organizations"; + summary: "Add Domain"; + description: "Add a new domain to an organization. The domains are used to identify to which organization a user belongs." + parameters: { + headers: { + name: "x-zitadel-orgid"; + description: "The default is always the organization of the requesting user. If you like to get/set a result of another organization include the header. Make sure the user has permission to access the requested data."; + type: STRING, + required: false; + }; + }; + }; + } + + rpc ListOrganizationDomains(ListOrganizationDomainsRequest) returns (ListOrganizationDomainsResponse) { + option (google.api.http) = { + post: "/v2beta/organization/domains/_search" + body: "*" + }; + + option (zitadel.protoc_gen_zitadel.v2.options) = { + auth_option: { + permission: "org.read" + } + http_response: { + success_code: 201 + } + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags: "Organizations"; + summary: "Search Domains"; + description: "Returns the list of registered domains of an organization. The domains are used to identify to which organization a user belongs." + parameters: { + headers: { + name: "x-zitadel-orgid"; + description: "The default is always the organization of the requesting user. If you like to get/set a result of another organization include the header. Make sure the user has permission to access the requested data."; + type: STRING, + required: false; + }; + }; + }; + } + } message CreateOrganizationRequest{ @@ -479,3 +723,56 @@ message ReactivateOrganizationRequest { message ReactivateOrganizationResponse { zitadel.object.v2beta.Details details = 1; } + +// message SetOrganizationMetadataRequest { +// string key = 1 [ +// (validate.rules).string = {min_len: 1, max_len: 200}, +// (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { +// example: "\"key1\""; +// min_length: 1, +// max_length: 200; +// } +// ]; +// bytes value = 2 [ +// (validate.rules).bytes = {min_len: 1, max_len: 500000}, +// (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { +// description: "The value has to be base64 encoded."; +// example: "\"VGhpcyBpcyBteSB0ZXN0IHZhbHVl\""; +// min_length: 1, +// max_length: 500000; +// } +// ]; +// } + +// message SetOrganizationMetadataResponse { +// zitadel.v1.ObjectDetails details = 1; +// } + +message AddOrganizationDomainRequest { + string organization_id = 1; + string domain = 2 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (google.api.field_behavior) = REQUIRED, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + min_length: 1; + max_length: 200; + example: "\"testdomain.com\""; + } + ]; +} + +message AddOrganizationDomainResponse { + zitadel.object.v2beta.Details details = 1; +} + +message ListOrganizationDomainsRequest { + //list limitations and ordering + zitadel.object.v2beta.ListQuery query = 1; + //criteria the client is looking for + repeated DomainSearchQuery queries = 2; +} + +message ListOrganizationDomainsResponse { + zitadel.object.v2beta.ListDetails details = 1; + repeated Domain result = 2; +}