diff --git a/docs/docs/apis/proto/admin.md b/docs/docs/apis/proto/admin.md index f8f4e856ab..fd3e76e406 100644 --- a/docs/docs/apis/proto/admin.md +++ b/docs/docs/apis/proto/admin.md @@ -430,6 +430,19 @@ and adds the user to the orgs members as ORG_OWNER POST: /orgs/_setup +### RemoveOrg + +> **rpc** RemoveOrg([RemoveOrgRequest](#removeorgrequest)) +[RemoveOrgResponse](#removeorgresponse) + +Sets the state of the organisation and all its resource (Users, Projects, Grants to and from the org) to removed +Users of this organisation will not be able login + + + + DELETE: /orgs/{org_id} + + ### GetIDPByID > **rpc** GetIDPByID([GetIDPByIDRequest](#getidpbyidrequest)) @@ -3533,6 +3546,28 @@ This is an empty request +### RemoveOrgRequest + + + +| Field | Type | Description | Validation | +| ----- | ---- | ----------- | ----------- | +| org_id | string | - | string.min_len: 1
string.max_len: 200
| + + + + +### RemoveOrgResponse + + + +| Field | Type | Description | Validation | +| ----- | ---- | ----------- | ----------- | +| details | zitadel.v1.ObjectDetails | - | | + + + + ### RemoveSMSProviderRequest diff --git a/docs/docs/apis/proto/org.md b/docs/docs/apis/proto/org.md index 8f9895093f..ba28470deb 100644 --- a/docs/docs/apis/proto/org.md +++ b/docs/docs/apis/proto/org.md @@ -95,6 +95,18 @@ title: zitadel/org.proto | ----- | ---- | ----------- | ----------- | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.name_query | OrgNameQuery | - | | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.domain_query | OrgDomainQuery | - | | +| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) query.state_query | OrgStateQuery | - | | + + + + +### OrgStateQuery + + + +| Field | Type | Description | Validation | +| ----- | ---- | ----------- | ----------- | +| state | OrgState | - | enum.defined_only: true
| diff --git a/internal/api/grpc/admin/org.go b/internal/api/grpc/admin/org.go index b3b378461f..4874b01711 100644 --- a/internal/api/grpc/admin/org.go +++ b/internal/api/grpc/admin/org.go @@ -27,6 +27,16 @@ func (s *Server) SetDefaultOrg(ctx context.Context, req *admin_pb.SetDefaultOrgR }, nil } +func (s *Server) RemoveOrg(ctx context.Context, req *admin_pb.RemoveOrgRequest) (*admin_pb.RemoveOrgResponse, error) { + details, err := s.command.RemoveOrg(ctx, req.OrgId) + if err != nil { + return nil, err + } + return &admin_pb.RemoveOrgResponse{ + Details: object.DomainToChangeDetailsPb(details), + }, nil +} + func (s *Server) GetDefaultOrg(ctx context.Context, _ *admin_pb.GetDefaultOrgRequest) (*admin_pb.GetDefaultOrgResponse, error) { org, err := s.query.OrgByID(ctx, true, authz.GetInstance(ctx).DefaultOrganisationID()) return &admin_pb.GetDefaultOrgResponse{Org: org_grpc.OrgToPb(org)}, err diff --git a/internal/api/grpc/org/converter.go b/internal/api/grpc/org/converter.go index acd1c1c054..f98c97e4ff 100644 --- a/internal/api/grpc/org/converter.go +++ b/internal/api/grpc/org/converter.go @@ -25,6 +25,8 @@ func OrgQueryToModel(apiQuery *org_pb.OrgQuery) (query.SearchQuery, error) { return query.NewOrgDomainSearchQuery(object.TextMethodToQuery(q.DomainQuery.Method), q.DomainQuery.Domain) case *org_pb.OrgQuery_NameQuery: return query.NewOrgNameSearchQuery(object.TextMethodToQuery(q.NameQuery.Method), q.NameQuery.Name) + case *org_pb.OrgQuery_StateQuery: + return query.NewOrgStateSearchQuery(int32(q.StateQuery.State)) default: return nil, errors.ThrowInvalidArgument(nil, "ORG-vR9nC", "List.Query.Invalid") } diff --git a/internal/query/org.go b/internal/query/org.go index 4ddd71a023..d81c8c1d62 100644 --- a/internal/query/org.go +++ b/internal/query/org.go @@ -215,6 +215,10 @@ func NewOrgNameSearchQuery(method TextComparison, value string) (SearchQuery, er return NewTextQuery(OrgColumnName, value, method) } +func NewOrgStateSearchQuery(value int32) (SearchQuery, error) { + return NewNumberQuery(OrgColumnState, value, NumberEquals) +} + func NewOrgIDsSearchQuery(ids ...string) (SearchQuery, error) { list := make([]interface{}, len(ids)) for i, value := range ids { diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto index e57780ff42..61a1821ad0 100644 --- a/proto/zitadel/admin.proto +++ b/proto/zitadel/admin.proto @@ -613,6 +613,41 @@ service AdminService { }; } + + // Sets the state of the organisation and all its resource (Users, Projects, Grants to and from the org) to removed + // Users of this organisation will not be able login + rpc RemoveOrg(RemoveOrgRequest) returns (RemoveOrgResponse) { + option (google.api.http) = { + delete: "/orgs/{org_id}" + }; + + option (zitadel.v1.auth_option) = { + permission: "iam.write"; + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags: "orgs"; + tags: "global"; + responses: { + key: "200"; + value: { + description: "org removed successfully"; + }; + }; + responses: { + key: "400"; + value: { + description: "invalid org"; + schema: { + json_schema: { + ref: "#/definitions/rpcStatus"; + }; + }; + }; + }; + }; + } + + // Returns a identity provider configuration of the IAM instance rpc GetIDPByID(GetIDPByIDRequest) returns (GetIDPByIDResponse) { option (google.api.http) = { @@ -3018,6 +3053,28 @@ message SetUpOrgResponse { string user_id = 3; } +message RemoveOrgRequest { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { + json_schema: { + required: ["org_id"] + }; + }; + + string org_id = 1 [ + (validate.rules).string = {min_len: 1, max_len: 200}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"69629023906488334\""; + min_length: 1; + max_length: 200; + } + ]; +} + +message RemoveOrgResponse { + zitadel.v1.ObjectDetails details = 1; +} + + message GetIDPByIDRequest { string id = 1 [ (validate.rules).string = {min_len: 1, max_len: 200}, diff --git a/proto/zitadel/org.proto b/proto/zitadel/org.proto index ef278724c6..d65b58609b 100644 --- a/proto/zitadel/org.proto +++ b/proto/zitadel/org.proto @@ -80,6 +80,7 @@ message OrgQuery { OrgNameQuery name_query = 1; OrgDomainQuery domain_query = 2; + OrgStateQuery state_query = 3; } } @@ -113,6 +114,15 @@ message OrgDomainQuery { ]; } +message OrgStateQuery { + OrgState state = 1 [ + (validate.rules).enum.defined_only = true, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "current state of the organisation"; + } + ]; +} + enum OrgFieldName { ORG_FIELD_NAME_UNSPECIFIED = 0; ORG_FIELD_NAME_NAME = 1;