diff --git a/internal/api/grpc/org/v2beta/integration_test/org_test.go b/internal/api/grpc/org/v2beta/integration_test/org_test.go index e48151bb7c..2c90462838 100644 --- a/internal/api/grpc/org/v2beta/integration_test/org_test.go +++ b/internal/api/grpc/org/v2beta/integration_test/org_test.go @@ -15,7 +15,9 @@ import ( gofakeit "github.com/brianvoe/gofakeit/v6" "github.com/zitadel/zitadel/internal/integration" + org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" + v2beta_org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta" "github.com/zitadel/zitadel/pkg/grpc/user/v2" user_v2beta "github.com/zitadel/zitadel/pkg/grpc/user/v2beta" ) @@ -23,7 +25,7 @@ import ( var ( CTX context.Context Instance *integration.Instance - Client org.OrganizationServiceClient + Client v2beta_org.OrganizationServiceClient User *user.AddHumanUserResponse ) @@ -42,66 +44,20 @@ func TestMain(m *testing.M) { }()) } -func TestServer_GetOrganizationByID(t *testing.T) { - orgs, orgsName, err := createOrgs(1) - if err != nil { - assert.Fail(t, "unable to create org") - } - orgId := orgs[0].OrganizationId - orgName := orgsName[0] - - tests := []struct { - name string - ctx context.Context - req *org.GetOrganizationByIDRequest - want *org.GetOrganizationByIDResponse - wantErr bool - }{ - { - name: "get organization happy path", - ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner), - req: &org.GetOrganizationByIDRequest{ - Id: orgId, - }, - }, - { - name: "get organization that doesn't exist", - ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner), - req: &org.GetOrganizationByIDRequest{ - Id: "non existing organization", - }, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := Client.GetOrganizationByID(tt.ctx, tt.req) - if tt.wantErr { - require.Error(t, err) - return - } - require.NoError(t, err) - - require.Equal(t, orgId, got.Organization.Id) - require.Equal(t, orgName, got.Organization.Name) - }) - } -} - func TestServer_CreateOrganization(t *testing.T) { idpResp := Instance.AddGenericOAuthProvider(CTX, Instance.DefaultOrg.Id) tests := []struct { name string ctx context.Context - req *org.CreateOrganizationRequest - want *org.CreateOrganizationResponse + req *v2beta_org.CreateOrganizationRequest + want *v2beta_org.CreateOrganizationResponse wantErr bool }{ { name: "missing permission", ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner), - req: &org.CreateOrganizationRequest{ + req: &v2beta_org.CreateOrganizationRequest{ Name: "name", Admins: nil, }, @@ -110,7 +66,7 @@ func TestServer_CreateOrganization(t *testing.T) { { name: "empty name", ctx: CTX, - req: &org.CreateOrganizationRequest{ + req: &v2beta_org.CreateOrganizationRequest{ Name: "", Admins: nil, }, @@ -119,9 +75,9 @@ func TestServer_CreateOrganization(t *testing.T) { { name: "invalid admin type", ctx: CTX, - req: &org.CreateOrganizationRequest{ + req: &v2beta_org.CreateOrganizationRequest{ Name: gofakeit.AppName(), - Admins: []*org.CreateOrganizationRequest_Admin{ + Admins: []*v2beta_org.CreateOrganizationRequest_Admin{ {}, }, }, @@ -130,11 +86,11 @@ func TestServer_CreateOrganization(t *testing.T) { { name: "admin with init", ctx: CTX, - req: &org.CreateOrganizationRequest{ + req: &v2beta_org.CreateOrganizationRequest{ Name: gofakeit.AppName(), - Admins: []*org.CreateOrganizationRequest_Admin{ + Admins: []*v2beta_org.CreateOrganizationRequest_Admin{ { - UserType: &org.CreateOrganizationRequest_Admin_Human{ + UserType: &v2beta_org.CreateOrganizationRequest_Admin_Human{ Human: &user_v2beta.AddHumanUserRequest{ Profile: &user_v2beta.SetHumanProfile{ GivenName: "firstname", @@ -151,9 +107,9 @@ func TestServer_CreateOrganization(t *testing.T) { }, }, }, - want: &org.CreateOrganizationResponse{ + want: &v2beta_org.CreateOrganizationResponse{ OrganizationId: integration.NotEmpty, - CreatedAdmins: []*org.CreateOrganizationResponse_CreatedAdmin{ + CreatedAdmins: []*v2beta_org.CreateOrganizationResponse_CreatedAdmin{ { UserId: integration.NotEmpty, EmailCode: gu.Ptr(integration.NotEmpty), @@ -165,14 +121,14 @@ func TestServer_CreateOrganization(t *testing.T) { { name: "existing user and new human with idp", ctx: CTX, - req: &org.CreateOrganizationRequest{ + req: &v2beta_org.CreateOrganizationRequest{ Name: gofakeit.AppName(), - Admins: []*org.CreateOrganizationRequest_Admin{ + Admins: []*v2beta_org.CreateOrganizationRequest_Admin{ { - UserType: &org.CreateOrganizationRequest_Admin_UserId{UserId: User.GetUserId()}, + UserType: &v2beta_org.CreateOrganizationRequest_Admin_UserId{UserId: User.GetUserId()}, }, { - UserType: &org.CreateOrganizationRequest_Admin_Human{ + UserType: &v2beta_org.CreateOrganizationRequest_Admin_Human{ Human: &user_v2beta.AddHumanUserRequest{ Profile: &user_v2beta.SetHumanProfile{ GivenName: "firstname", @@ -196,8 +152,8 @@ func TestServer_CreateOrganization(t *testing.T) { }, }, }, - want: &org.CreateOrganizationResponse{ - CreatedAdmins: []*org.CreateOrganizationResponse_CreatedAdmin{ + want: &v2beta_org.CreateOrganizationResponse{ + CreatedAdmins: []*v2beta_org.CreateOrganizationResponse_CreatedAdmin{ // a single admin is expected, because the first provided already exists { UserId: integration.NotEmpty, @@ -246,14 +202,14 @@ func TestServer_UpdateOrganization(t *testing.T) { tests := []struct { name string ctx context.Context - req *org.UpdateOrganizationRequest - want *org.UpdateOrganizationResponse + req *v2beta_org.UpdateOrganizationRequest + want *v2beta_org.UpdateOrganizationResponse wantErr bool }{ { name: "update org with new name", ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner), - req: &org.UpdateOrganizationRequest{ + req: &v2beta_org.UpdateOrganizationRequest{ Id: orgId, Name: "new org name", }, @@ -261,7 +217,7 @@ func TestServer_UpdateOrganization(t *testing.T) { { name: "update org with same name", ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner), - req: &org.UpdateOrganizationRequest{ + req: &v2beta_org.UpdateOrganizationRequest{ Id: orgId, Name: orgName, }, @@ -269,7 +225,7 @@ func TestServer_UpdateOrganization(t *testing.T) { { name: "update org with no id", ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner), - req: &org.UpdateOrganizationRequest{ + req: &v2beta_org.UpdateOrganizationRequest{ Id: orgId, // Name: "", }, @@ -295,6 +251,52 @@ func TestServer_UpdateOrganization(t *testing.T) { } } +func TestServer_GetOrganizationByID(t *testing.T) { + orgs, orgsName, err := createOrgs(1) + if err != nil { + assert.Fail(t, "unable to create org") + } + orgId := orgs[0].OrganizationId + orgName := orgsName[0] + + tests := []struct { + name string + ctx context.Context + req *v2beta_org.GetOrganizationByIDRequest + want *v2beta_org.GetOrganizationByIDResponse + wantErr bool + }{ + { + name: "get organization happy path", + ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner), + req: &v2beta_org.GetOrganizationByIDRequest{ + Id: orgId, + }, + }, + { + name: "get organization that doesn't exist", + ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner), + req: &v2beta_org.GetOrganizationByIDRequest{ + Id: "non existing organization", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Client.GetOrganizationByID(tt.ctx, tt.req) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + + require.Equal(t, orgId, got.Organization.Id) + require.Equal(t, orgName, got.Organization.Name) + }) + } +} + // TODO: finish off qyery testing in ListOrganizations func TestServer_ListOrganization(t *testing.T) { noOfOrgs := 3 @@ -306,15 +308,15 @@ func TestServer_ListOrganization(t *testing.T) { tests := []struct { name string ctx context.Context - req *org.ListOrganizationsRequest - want []*org.Organization + req *v2beta_org.ListOrganizationsRequest + want []*v2beta_org.Organization wantErr bool }{ { name: "list organizations happy path", ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner), - req: &org.ListOrganizationsRequest{}, - want: []*org.Organization{ + req: &v2beta_org.ListOrganizationsRequest{}, + want: []*v2beta_org.Organization{ { Id: orgs[0].OrganizationId, Name: orgsName[0], @@ -370,8 +372,8 @@ func TestServer_DeleteOrganization(t *testing.T) { name string ctx context.Context createOrgFunc func() string - req *org.DeleteOrganizationRequest - want *org.DeleteOrganizationResponse + req *v2beta_org.DeleteOrganizationRequest + want *v2beta_org.DeleteOrganizationResponse err error }{ { @@ -384,12 +386,12 @@ func TestServer_DeleteOrganization(t *testing.T) { } return orgs[0].OrganizationId }, - req: &org.DeleteOrganizationRequest{}, + req: &v2beta_org.DeleteOrganizationRequest{}, }, { name: "delete non existent org", ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner), - req: &org.DeleteOrganizationRequest{ + req: &v2beta_org.DeleteOrganizationRequest{ Id: "non existent org id", }, err: fmt.Errorf("Organisation not found"), @@ -415,7 +417,7 @@ func TestServer_DeleteOrganization(t *testing.T) { assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute)) assert.NotEmpty(t, got.GetDetails().GetResourceOwner()) - _, err = Client.GetOrganizationByID(tt.ctx, &org.GetOrganizationByIDRequest{ + _, err = Client.GetOrganizationByID(tt.ctx, &v2beta_org.GetOrganizationByIDRequest{ Id: tt.req.Id, }) require.Contains(t, err.Error(), "Organisation not found") @@ -423,16 +425,121 @@ func TestServer_DeleteOrganization(t *testing.T) { } } -func createOrgs(noOfOrgs int) ([]*org.CreateOrganizationResponse, []string, error) { +func TestServer_DeactivateReactivateNonExistentOrganization(t *testing.T) { + ctx := Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner) + + // deactivate non existent organization + _, err := Client.DeactivateOrganization(ctx, &v2beta_org.DeactivateOrganizationRequest{ + Id: "non existent organization", + }) + require.Contains(t, err.Error(), "Organisation not found") + + // reactivate non existent organization + _, err = Client.ReactivateOrganization(ctx, &v2beta_org.ReactivateOrganizationRequest{ + Id: "non existent organization", + }) + require.Contains(t, err.Error(), "Organisation not found") +} + +func TestServer_DeactivateReactivateOrganization(t *testing.T) { + // 1. create organization + orgs, _, err := createOrgs(1) + if err != nil { + assert.Fail(t, "unable to create orgs") + } + orgId := orgs[0].OrganizationId + ctx := Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner) + + // 2. check inital state of organization + res, err := Client.GetOrganizationByID(ctx, &org.GetOrganizationByIDRequest{ + Id: orgId, + }) + require.NoError(t, err) + require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_ACTIVE, res.Organization.State) + + // 3. deactivate organization once + deactivate_res, err := Client.DeactivateOrganization(ctx, &v2beta_org.DeactivateOrganizationRequest{ + Id: orgId, + }) + require.NoError(t, err) + assert.NotZero(t, deactivate_res.GetDetails().GetSequence()) + gotCD := deactivate_res.GetDetails().GetChangeDate().AsTime() + now := time.Now() + assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute)) + assert.NotEmpty(t, deactivate_res.GetDetails().GetResourceOwner()) + + // 4. check organization state is deactivated + res, err = Client.GetOrganizationByID(ctx, &v2beta_org.GetOrganizationByIDRequest{ + Id: orgId, + }) + require.NoError(t, err) + require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_INACTIVE, res.Organization.State) + + // 5. repeat deactivate organization once + deactivate_res, err = Client.DeactivateOrganization(ctx, &v2beta_org.DeactivateOrganizationRequest{ + Id: orgId, + }) + require.NoError(t, err) + assert.NotZero(t, deactivate_res.GetDetails().GetSequence()) + gotCD = deactivate_res.GetDetails().GetChangeDate().AsTime() + now = time.Now() + assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute)) + assert.NotEmpty(t, deactivate_res.GetDetails().GetResourceOwner()) + + // 6. repeat check organization state is still deactivated + res, err = Client.GetOrganizationByID(ctx, &v2beta_org.GetOrganizationByIDRequest{ + Id: orgId, + }) + require.NoError(t, err) + require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_INACTIVE, res.Organization.State) + + // 7. reactivate organization + reactivate_res, err := Client.ReactivateOrganization(ctx, &v2beta_org.ReactivateOrganizationRequest{ + Id: orgId, + }) + require.NoError(t, err) + assert.NotZero(t, reactivate_res.GetDetails().GetSequence()) + gotCD = reactivate_res.GetDetails().GetChangeDate().AsTime() + now = time.Now() + assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute)) + assert.NotEmpty(t, reactivate_res.GetDetails().GetResourceOwner()) + + // 8. check organization state is active + res, err = Client.GetOrganizationByID(ctx, &v2beta_org.GetOrganizationByIDRequest{ + Id: orgId, + }) + require.NoError(t, err) + require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_ACTIVE, res.Organization.State) + + // 9. repeat reactivate organization + reactivate_res, err = Client.ReactivateOrganization(ctx, &v2beta_org.ReactivateOrganizationRequest{ + Id: orgId, + }) + require.NoError(t, err) + assert.NotZero(t, reactivate_res.GetDetails().GetSequence()) + gotCD = reactivate_res.GetDetails().GetChangeDate().AsTime() + now = time.Now() + assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute)) + assert.NotEmpty(t, reactivate_res.GetDetails().GetResourceOwner()) + + // 10. repeat check organization state is still active + res, err = Client.GetOrganizationByID(ctx, &v2beta_org.GetOrganizationByIDRequest{ + Id: orgId, + }) + require.NoError(t, err) + require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_ACTIVE, res.Organization.State) +} + +func createOrgs(noOfOrgs int) ([]*v2beta_org.CreateOrganizationResponse, []string, error) { var err error - orgs := make([]*org.CreateOrganizationResponse, noOfOrgs) + orgs := make([]*v2beta_org.CreateOrganizationResponse, noOfOrgs) orgsName := make([]string, noOfOrgs) for i := range noOfOrgs { orgName := gofakeit.Name() orgsName[i] = orgName orgs[i], err = Client.CreateOrganization(CTX, - &org.CreateOrganizationRequest{ + &v2beta_org.CreateOrganizationRequest{ Name: orgName, }, ) @@ -444,7 +551,7 @@ func createOrgs(noOfOrgs int) ([]*org.CreateOrganizationResponse, []string, erro return orgs, orgsName, nil } -func assertCreatedAdmin(t *testing.T, expected, got *org.CreateOrganizationResponse_CreatedAdmin) { +func assertCreatedAdmin(t *testing.T, expected, got *v2beta_org.CreateOrganizationResponse_CreatedAdmin) { if expected.GetUserId() != "" { assert.NotEmpty(t, got.GetUserId()) } else { diff --git a/internal/api/grpc/org/v2beta/org.go b/internal/api/grpc/org/v2beta/org.go index adccac9427..092436385c 100644 --- a/internal/api/grpc/org/v2beta/org.go +++ b/internal/api/grpc/org/v2beta/org.go @@ -7,6 +7,7 @@ import ( user "github.com/zitadel/zitadel/internal/api/grpc/user/v2beta" "github.com/zitadel/zitadel/internal/command" "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" ) @@ -68,6 +69,26 @@ func (s *Server) DeleteOrganization(ctx context.Context, request *v2beta_org.Del }, nil } +func (s *Server) DeactivateOrganization(ctx context.Context, request *org.DeactivateOrganizationRequest) (*org.DeactivateOrganizationResponse, error) { + objectDetails, err := s.command.DeactivateOrg(ctx, request.Id) + if err != nil { + return nil, err + } + return &org.DeactivateOrganizationResponse{ + Details: object.DomainToDetailsPb(objectDetails), + }, nil +} + +func (s *Server) ReactivateOrganization(ctx context.Context, request *org.ReactivateOrganizationRequest) (*org.ReactivateOrganizationResponse, error) { + objectDetails, err := s.command.ReactivateOrg(ctx, request.Id) + if err != nil { + return nil, err + } + return &org.ReactivateOrganizationResponse{ + Details: object.DomainToDetailsPb(objectDetails), + }, err +} + func createOrganizationRequestToCommand(request *v2beta_org.CreateOrganizationRequest) (*command.OrgSetup, error) { admins, err := createOrganizationRequestAdminsToCommand(request.GetAdmins()) if err != nil { diff --git a/internal/command/org.go b/internal/command/org.go index 595dc042a1..114cde4fe1 100644 --- a/internal/command/org.go +++ b/internal/command/org.go @@ -353,7 +353,7 @@ func (c *Commands) UpdateOrg(ctx context.Context, orgID, name string) (*domain.O return nil, err } if !isOrgStateExists(orgWriteModel.State) { - return nil, zerrors.ThrowNotFound(nil, "ORG-1MRds", "Errors.Org.NotFound") + return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil } if orgWriteModel.Name == name { return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil @@ -388,7 +388,7 @@ func (c *Commands) DeactivateOrg(ctx context.Context, orgID string) (*domain.Obj return nil, zerrors.ThrowNotFound(nil, "ORG-oL9nT", "Errors.Org.NotFound") } if orgWriteModel.State == domain.OrgStateInactive { - return nil, zerrors.ThrowPreconditionFailed(nil, "EVENT-Dbs2g", "Errors.Org.AlreadyDeactivated") + return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil } orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, org.NewOrgDeactivatedEvent(ctx, orgAgg)) @@ -411,7 +411,7 @@ func (c *Commands) ReactivateOrg(ctx context.Context, orgID string) (*domain.Obj return nil, zerrors.ThrowNotFound(nil, "ORG-Dgf3g", "Errors.Org.NotFound") } if orgWriteModel.State == domain.OrgStateActive { - return nil, zerrors.ThrowPreconditionFailed(nil, "EVENT-bfnrh", "Errors.Org.AlreadyActive") + return writeModelToObjectDetails(&orgWriteModel.WriteModel), nil } orgAgg := OrgAggregateFromWriteModel(&orgWriteModel.WriteModel) pushedEvents, err := c.eventstore.Push(ctx, org.NewOrgReactivatedEvent(ctx, orgAgg)) diff --git a/proto/zitadel/org/v2beta/org.proto b/proto/zitadel/org/v2beta/org.proto index fb6868c002..baa0181eb4 100644 --- a/proto/zitadel/org/v2beta/org.proto +++ b/proto/zitadel/org/v2beta/org.proto @@ -32,6 +32,7 @@ message Organization { ]; } +// TODO rename to OrgState enum OrganizationState { ORGANIZATION_STATE_UNSPECIFIED = 0; ORGANIZATION_STATE_ACTIVE = 1; @@ -80,7 +81,7 @@ message OrgDomainQuery { } message OrgStateQuery { - OrgState state = 1 [ + OrganizationState state = 1 [ (validate.rules).enum.defined_only = true, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "current state of the organization"; @@ -97,14 +98,3 @@ message OrgIDQuery { ]; } -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; -} diff --git a/proto/zitadel/org/v2beta/org_service.proto b/proto/zitadel/org/v2beta/org_service.proto index a51bb51b7b..49076fb643 100644 --- a/proto/zitadel/org/v2beta/org_service.proto +++ b/proto/zitadel/org/v2beta/org_service.proto @@ -249,7 +249,7 @@ service OrganizationService { responses: { key: "200"; value: { - description: "org removed successfully"; + description: "org deleted successfully"; }; }; responses: { @@ -266,6 +266,66 @@ service OrganizationService { }; } + rpc DeactivateOrganization(DeactivateOrganizationRequest) returns (DeactivateOrganizationResponse) { + option (google.api.http) = { + post: "/v2beta/_deactivate" + 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"; + summary: "Deactivate Organization"; + description: "Sets the state of my organization to deactivated. Users of this organization will not be able to log in." + 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 ReactivateOrganization(ReactivateOrganizationRequest) returns (ReactivateOrganizationResponse) { + option (google.api.http) = { + post: "/orgs/me/_reactivate" + 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"; + summary: "Reactivate Organization"; + description: "Set the state of my organization to active. The state of the organization has to be deactivated to perform the request. Users of this organization will be able to log in again." + 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; + }; + }; + }; + } + } message CreateOrganizationRequest{ @@ -387,3 +447,35 @@ message DeleteOrganizationRequest { message DeleteOrganizationResponse { zitadel.object.v2beta.Details details = 1; } + +//This is an empty request +message DeactivateOrganizationRequest { + string 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 DeactivateOrganizationResponse { + zitadel.object.v2beta.Details details = 1; +} + +//This is an empty request +message ReactivateOrganizationRequest { + string 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 ReactivateOrganizationResponse { + zitadel.object.v2beta.Details details = 1; +}