fixup! fixup! fixup! fixup! fixup! fixup! refactor(api): moving organization API resourced based

added DeleteOrganization()
This commit is contained in:
Iraq Jaber
2025-04-30 09:43:36 +02:00
parent ada2a2c9be
commit 40de3d462a
3 changed files with 113 additions and 47 deletions

View File

@@ -35,6 +35,7 @@ func TestMain(m *testing.M) {
Instance = integration.NewInstance(ctx) Instance = integration.NewInstance(ctx)
Client = Instance.Client.OrgV2beta Client = Instance.Client.OrgV2beta
CTX = Instance.WithAuthorization(ctx, integration.UserTypeIAMOwner)
CTX = Instance.WithAuthorization(ctx, integration.UserTypeIAMOwner) CTX = Instance.WithAuthorization(ctx, integration.UserTypeIAMOwner)
User = Instance.CreateHumanUser(CTX) User = Instance.CreateHumanUser(CTX)
return m.Run() return m.Run()
@@ -58,14 +59,14 @@ func TestServer_GetOrganizationByID(t *testing.T) {
}{ }{
{ {
name: "get organization happy path", name: "get organization happy path",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner), ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner),
req: &org.GetOrganizationByIDRequest{ req: &org.GetOrganizationByIDRequest{
Id: orgId, Id: orgId,
}, },
}, },
{ {
name: "get organization that doesn't exist", name: "get organization that doesn't exist",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner), ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner),
req: &org.GetOrganizationByIDRequest{ req: &org.GetOrganizationByIDRequest{
Id: "non existing organization", Id: "non existing organization",
}, },
@@ -249,25 +250,25 @@ func TestServer_UpdateOrganization(t *testing.T) {
want *org.UpdateOrganizationResponse want *org.UpdateOrganizationResponse
wantErr bool wantErr bool
}{ }{
{
name: "update org with same name",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner),
req: &org.UpdateOrganizationRequest{
Id: orgId,
Name: orgName,
},
},
{ {
name: "update org with new name", name: "update org with new name",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner), ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner),
req: &org.UpdateOrganizationRequest{ req: &org.UpdateOrganizationRequest{
Id: orgId, Id: orgId,
Name: "new org name", Name: "new org name",
}, },
}, },
{
name: "update org with same name",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner),
req: &org.UpdateOrganizationRequest{
Id: orgId,
Name: orgName,
},
},
{ {
name: "update org with no id", name: "update org with no id",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner), ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner),
req: &org.UpdateOrganizationRequest{ req: &org.UpdateOrganizationRequest{
Id: orgId, Id: orgId,
// Name: "", // Name: "",
@@ -299,7 +300,7 @@ func TestServer_ListOrganization(t *testing.T) {
noOfOrgs := 3 noOfOrgs := 3
orgs, orgsName, err := createOrgs(noOfOrgs) orgs, orgsName, err := createOrgs(noOfOrgs)
if err != nil { if err != nil {
assert.Fail(t, "unable to create org") assert.Fail(t, "unable to create orgs")
} }
tests := []struct { tests := []struct {
@@ -310,8 +311,8 @@ func TestServer_ListOrganization(t *testing.T) {
wantErr bool wantErr bool
}{ }{
{ {
name: "update org with same name", name: "list organizations happy path",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeOrgOwner), ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner),
req: &org.ListOrganizationsRequest{}, req: &org.ListOrganizationsRequest{},
want: []*org.Organization{ want: []*org.Organization{
{ {
@@ -358,17 +359,75 @@ func TestServer_ListOrganization(t *testing.T) {
// require.Equal(t, org.do, got.Result[i].Name) // require.Equal(t, org.do, got.Result[i].Name)
} }
} }
fmt.Printf("@@ >>>>>>>>>>>>>>>>>>>>>>>>>>>> foundOrgs = %+v\n", foundOrgs)
require.Equal(t, len(tt.want), foundOrgs) require.Equal(t, len(tt.want), foundOrgs)
}, retryDuration, tick, "timeout waiting for expected organizations being created") }, retryDuration, tick, "timeout waiting for expected organizations being created")
}) })
} }
} }
func TestServer_DeleteOrganization(t *testing.T) {
tests := []struct {
name string
ctx context.Context
createOrgFunc func() string
req *org.DeleteOrganizationRequest
want *org.DeleteOrganizationResponse
err error
}{
{
name: "delete org happy path",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner),
createOrgFunc: func() string {
orgs, _, err := createOrgs(1)
if err != nil {
assert.Fail(t, "unable to create org")
}
return orgs[0].OrganizationId
},
req: &org.DeleteOrganizationRequest{},
},
{
name: "delete non existent org",
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner),
req: &org.DeleteOrganizationRequest{
Id: "non existent org id",
},
err: fmt.Errorf("Organisation not found"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.createOrgFunc != nil {
tt.req.Id = tt.createOrgFunc()
}
got, err := Client.DeleteOrganization(tt.ctx, tt.req)
if tt.err != nil {
require.Contains(t, err.Error(), tt.err.Error())
return
}
require.NoError(t, err)
// check details
assert.NotZero(t, got.GetDetails().GetSequence())
gotCD := got.GetDetails().GetChangeDate().AsTime()
now := time.Now()
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{
Id: tt.req.Id,
})
require.Contains(t, err.Error(), "Organisation not found")
})
}
}
func createOrgs(noOfOrgs int) ([]*org.CreateOrganizationResponse, []string, error) { func createOrgs(noOfOrgs int) ([]*org.CreateOrganizationResponse, []string, error) {
var err error var err error
orgs := make([]*org.CreateOrganizationResponse, noOfOrgs) orgs := make([]*org.CreateOrganizationResponse, noOfOrgs)
orgsName := make([]string, noOfOrgs) orgsName := make([]string, noOfOrgs)
for i := range noOfOrgs { for i := range noOfOrgs {
orgName := gofakeit.Name() orgName := gofakeit.Name()
orgsName[i] = orgName orgsName[i] = orgName

View File

@@ -58,6 +58,16 @@ func (s *Server) ListOrganizations(ctx context.Context, request *v2beta_org.List
}, nil }, nil
} }
func (s *Server) DeleteOrganization(ctx context.Context, request *v2beta_org.DeleteOrganizationRequest) (*v2beta_org.DeleteOrganizationResponse, error) {
details, err := s.command.RemoveOrg(ctx, request.Id)
if err != nil {
return nil, err
}
return &v2beta_org.DeleteOrganizationResponse{
Details: object.DomainToDetailsPb(details),
}, nil
}
func createOrganizationRequestToCommand(request *v2beta_org.CreateOrganizationRequest) (*command.OrgSetup, error) { func createOrganizationRequestToCommand(request *v2beta_org.CreateOrganizationRequest) (*command.OrgSetup, error) {
admins, err := createOrganizationRequestAdminsToCommand(request.GetAdmins()) admins, err := createOrganizationRequestAdminsToCommand(request.GetAdmins())
if err != nil { if err != nil {

View File

@@ -244,7 +244,7 @@ service OrganizationService {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
tags: "Organizations"; tags: "Organizations";
summary: "Remove Organization"; summary: "Deletes Organization";
description: "Deletes the organization and all its resources (Users, Projects, Grants to and from the org). Users of this organization will not be able to log in." description: "Deletes the organization and all its resources (Users, Projects, Grants to and from the org). Users of this organization will not be able to log in."
responses: { responses: {
key: "200"; key: "200";
@@ -346,45 +346,42 @@ message GetOrganizationByIDResponse {
} }
message ListOrganizationsRequest { message ListOrganizationsRequest {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
json_schema: { json_schema: {
description: "Search query for lists"; description: "Search query for lists";
required: ["query"] required: ["query"]
}; };
}; };
//list limitations and ordering // list limitations and ordering
// zitadel.v1.ListQuery query = 1; zitadel.object.v2beta.ListQuery query = 1;
zitadel.object.v2beta.ListQuery query = 1; // the field the result is sorted
// the field the result is sorted zitadel.org.v2beta.OrgFieldName sorting_column = 2;
// zitadel.org.v1.OrgFieldName sorting_column = 2; //criteria the client is looking for
zitadel.org.v2beta.OrgFieldName sorting_column = 2; repeated zitadel.org.v2beta.OrgQuery queries = 3;
//criteria the client is looking for
repeated zitadel.org.v2beta.OrgQuery queries = 3;
} }
message ListOrganizationsResponse { message ListOrganizationsResponse {
zitadel.object.v2beta.ListDetails details = 1; zitadel.object.v2beta.ListDetails details = 1;
// zitadel.org.v2beta.Organization organization = 1; zitadel.org.v2beta.OrgFieldName sorting_column = 2;
zitadel.org.v2beta.OrgFieldName sorting_column = 2; repeated zitadel.org.v2beta.Organization result = 3;
repeated zitadel.org.v2beta.Organization result = 3;
} }
message DeleteOrganizationRequest { message DeleteOrganizationRequest {
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
json_schema: { json_schema: {
required: ["org_id"] required: ["id"]
};
}; };
};
string org_id = 1 [ string id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200}, (validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"69629023906488334\""; example: "\"69629023906488334\"";
min_length: 1; min_length: 1;
max_length: 200; max_length: 200;
} }
]; ];
} }
message DeleteOrganizationResponse { message DeleteOrganizationResponse {