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

added all Domain related endpoinds, testing not complete
This commit is contained in:
Iraq Jaber
2025-05-02 18:54:58 +02:00
parent 4d5cbc94e2
commit 9dbcfc255d
6 changed files with 397 additions and 46 deletions

View File

@@ -138,3 +138,25 @@ func ToViewDetailsPb(
}
return details
}
func DomainToChangeDetailsPb(objectDetail *domain.ObjectDetails) *object.Details {
details := &object.Details{
Sequence: objectDetail.Sequence,
ResourceOwner: objectDetail.ResourceOwner,
}
if !objectDetail.EventDate.IsZero() {
details.ChangeDate = timestamppb.New(objectDetail.EventDate)
}
return details
}
func DomainValidationTypeToDomain(validationType org_pb.DomainValidationType) domain.OrgDomainValidationType {
switch validationType {
case org_pb.DomainValidationType_DOMAIN_VALIDATION_TYPE_HTTP:
return domain.OrgDomainValidationTypeHTTP
case org_pb.DomainValidationType_DOMAIN_VALIDATION_TYPE_DNS:
return domain.OrgDomainValidationTypeDNS
default:
return domain.OrgDomainValidationTypeUnspecified
}
}

View File

@@ -1,19 +1,23 @@
package org
import (
"context"
"time"
"github.com/zitadel/zitadel/internal/api/authz"
v2beta_object "github.com/zitadel/zitadel/internal/api/grpc/object/v2beta"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
"github.com/zitadel/zitadel/internal/query"
"github.com/zitadel/zitadel/internal/zerrors"
// TODO fix below
org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
v2beta_org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
v2beta "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
org_pb "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
"google.golang.org/protobuf/types/known/timestamppb"
)
@@ -22,7 +26,6 @@ import (
func listOrgRequestToModel(request *v2beta_org.ListOrganizationsRequest) (*query.OrgSearchQueries, error) {
offset, limit, asc := v2beta_object.ListQueryToModel(request.Query)
// queries, err := org_pb.OrgQueriesToModel(request.Queries)
queries, err := OrgQueriesToModel(request.Queries)
if err != nil {
return nil, err
@@ -38,8 +41,8 @@ func listOrgRequestToModel(request *v2beta_org.ListOrganizationsRequest) (*query
}, nil
}
func OrganizationViewToPb(org *query.Org) *org_pb.Organization {
return &org_pb.Organization{
func OrganizationViewToPb(org *query.Org) *v2beta_org.Organization {
return &v2beta_org.Organization{
Id: org.ID,
State: OrgStateToPb(org.State),
Name: org.Name,
@@ -53,14 +56,14 @@ func OrganizationViewToPb(org *query.Org) *org_pb.Organization {
}
}
func OrgStateToPb(state domain.OrgState) org_pb.OrgState {
func OrgStateToPb(state domain.OrgState) v2beta_org.OrgState {
switch state {
case domain.OrgStateActive:
return org_pb.OrgState_ORG_STATE_ACTIVE
return v2beta_org.OrgState_ORG_STATE_ACTIVE
case domain.OrgStateInactive:
return org_pb.OrgState_ORG_STATE_INACTIVE
return v2beta_org.OrgState_ORG_STATE_INACTIVE
default:
return org_pb.OrgState_ORG_STATE_UNSPECIFIED
return v2beta_org.OrgState_ORG_STATE_UNSPECIFIED
}
}
@@ -99,15 +102,15 @@ func createdOrganizationToPb(createdOrg *command.CreatedOrg) (_ *org.CreateOrgan
}, nil
}
func OrgViewsToPb(orgs []*query.Org) []*org_pb.Organization {
o := make([]*org_pb.Organization, len(orgs))
func OrgViewsToPb(orgs []*query.Org) []*v2beta_org.Organization {
o := make([]*v2beta_org.Organization, len(orgs))
for i, org := range orgs {
o[i] = OrgViewToPb(org)
}
return o
}
func OrgQueriesToModel(queries []*org_pb.OrgQuery) (_ []query.SearchQuery, err error) {
func OrgQueriesToModel(queries []*v2beta_org.OrgQuery) (_ []query.SearchQuery, err error) {
q := make([]query.SearchQuery, len(queries))
for i, query := range queries {
q[i], err = OrgQueryToModel(query)
@@ -118,47 +121,47 @@ func OrgQueriesToModel(queries []*org_pb.OrgQuery) (_ []query.SearchQuery, err e
return q, nil
}
func OrgQueryToModel(apiQuery *org_pb.OrgQuery) (query.SearchQuery, error) {
func OrgQueryToModel(apiQuery *v2beta_org.OrgQuery) (query.SearchQuery, error) {
switch q := apiQuery.Query.(type) {
case *org_pb.OrgQuery_DomainQuery:
case *v2beta_org.OrgQuery_DomainQuery:
return query.NewOrgVerifiedDomainSearchQuery(v2beta_object.TextMethodToQuery(q.DomainQuery.Method), q.DomainQuery.Domain)
case *org_pb.OrgQuery_NameQuery:
case *v2beta_org.OrgQuery_NameQuery:
return query.NewOrgNameSearchQuery(v2beta_object.TextMethodToQuery(q.NameQuery.Method), q.NameQuery.Name)
case *org_pb.OrgQuery_StateQuery:
case *v2beta_org.OrgQuery_StateQuery:
return query.NewOrgStateSearchQuery(OrgStateToDomain(q.StateQuery.State))
case *org_pb.OrgQuery_IdQuery:
case *v2beta_org.OrgQuery_IdQuery:
return query.NewOrgIDSearchQuery(q.IdQuery.Id)
default:
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-vR9nC", "List.Query.Invalid")
}
}
func OrgStateToDomain(state org_pb.OrgState) domain.OrgState {
func OrgStateToDomain(state v2beta_org.OrgState) domain.OrgState {
switch state {
case org_pb.OrgState_ORG_STATE_ACTIVE:
case v2beta_org.OrgState_ORG_STATE_ACTIVE:
return domain.OrgStateActive
case org_pb.OrgState_ORG_STATE_INACTIVE:
case v2beta_org.OrgState_ORG_STATE_INACTIVE:
return domain.OrgStateInactive
case org_pb.OrgState_ORG_STATE_UNSPECIFIED:
case v2beta_org.OrgState_ORG_STATE_UNSPECIFIED:
fallthrough
default:
return domain.OrgStateUnspecified
}
}
func FieldNameToOrgColumn(fieldName org_pb.OrgFieldName) query.Column {
func FieldNameToOrgColumn(fieldName v2beta_org.OrgFieldName) query.Column {
switch fieldName {
case org_pb.OrgFieldName_ORG_FIELD_NAME_NAME:
case v2beta_org.OrgFieldName_ORG_FIELD_NAME_NAME:
return query.OrgColumnName
case org_pb.OrgFieldName_ORG_FIELD_NAME_UNSPECIFIED:
case v2beta_org.OrgFieldName_ORG_FIELD_NAME_UNSPECIFIED:
return query.Column{}
default:
return query.Column{}
}
}
func OrgViewToPb(org *query.Org) *org_pb.Organization {
return &org_pb.Organization{
func OrgViewToPb(org *query.Org) *v2beta_org.Organization {
return &v2beta_org.Organization{
Id: org.ID,
State: OrgStateToPb(org.State),
Name: org.Name,
@@ -197,7 +200,7 @@ func ListQueryToModel(query *v2beta.ListQuery) (offset, limit uint64, asc bool)
return query.Offset, uint64(query.Limit), query.Asc
}
func DomainQueriesToModel(queries []*org_pb.DomainSearchQuery) (_ []query.SearchQuery, err error) {
func DomainQueriesToModel(queries []*v2beta_org.DomainSearchQuery) (_ []query.SearchQuery, err error) {
q := make([]query.SearchQuery, len(queries))
for i, query := range queries {
q[i], err = DomainQueryToModel(query)
@@ -208,12 +211,40 @@ func DomainQueriesToModel(queries []*org_pb.DomainSearchQuery) (_ []query.Search
return q, nil
}
func DomainQueryToModel(searchQuery *org_pb.DomainSearchQuery) (query.SearchQuery, error) {
func DomainQueryToModel(searchQuery *v2beta_org.DomainSearchQuery) (query.SearchQuery, error) {
switch q := searchQuery.Query.(type) {
case *org_pb.DomainSearchQuery_DomainNameQuery:
case *v2beta_org.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")
}
}
func RemoveOrgDomainRequestToDomain(ctx context.Context, req *v2beta_org.DeleteOrganizationDomainRequest) *domain.OrgDomain {
return &domain.OrgDomain{
ObjectRoot: models.ObjectRoot{
AggregateID: req.OrganizationId,
},
Domain: req.Domain,
}
}
func GenerateOrgDomainValidationRequestToDomain(ctx context.Context, req *v2beta_org.GenerateOrganizationDomainValidationRequest) *domain.OrgDomain {
return &domain.OrgDomain{
ObjectRoot: models.ObjectRoot{
AggregateID: req.OrganizationId,
},
Domain: req.Domain,
ValidationType: v2beta_object.DomainValidationTypeToDomain(req.Type),
}
}
func ValidateOrgDomainRequestToDomain(ctx context.Context, req *v2beta_org.VerifyOrganizationDomainRequest) *domain.OrgDomain {
return &domain.OrgDomain{
ObjectRoot: models.ObjectRoot{
AggregateID: authz.GetCtxData(ctx).OrgID,
},
Domain: req.Domain,
}
}

View File

@@ -455,7 +455,7 @@ func TestServer_DeactivateReactivateOrganization(t *testing.T) {
Id: orgId,
})
require.NoError(t, err)
require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_ACTIVE, res.Organization.State)
require.Equal(t, v2beta_org.OrgState_ORG_STATE_ACTIVE, res.Organization.State)
// 3. deactivate organization once
deactivate_res, err := Client.DeactivateOrganization(ctx, &v2beta_org.DeactivateOrganizationRequest{
@@ -473,7 +473,7 @@ func TestServer_DeactivateReactivateOrganization(t *testing.T) {
Id: orgId,
})
require.NoError(t, err)
require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_INACTIVE, res.Organization.State)
require.Equal(t, v2beta_org.OrgState_ORG_STATE_INACTIVE, res.Organization.State)
// 5. repeat deactivate organization once
deactivate_res, err = Client.DeactivateOrganization(ctx, &v2beta_org.DeactivateOrganizationRequest{
@@ -491,7 +491,7 @@ func TestServer_DeactivateReactivateOrganization(t *testing.T) {
Id: orgId,
})
require.NoError(t, err)
require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_INACTIVE, res.Organization.State)
require.Equal(t, v2beta_org.OrgState_ORG_STATE_INACTIVE, res.Organization.State)
// 7. reactivate organization
reactivate_res, err := Client.ReactivateOrganization(ctx, &v2beta_org.ReactivateOrganizationRequest{
@@ -509,7 +509,7 @@ func TestServer_DeactivateReactivateOrganization(t *testing.T) {
Id: orgId,
})
require.NoError(t, err)
require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_ACTIVE, res.Organization.State)
require.Equal(t, v2beta_org.OrgState_ORG_STATE_ACTIVE, res.Organization.State)
// 9. repeat reactivate organization
reactivate_res, err = Client.ReactivateOrganization(ctx, &v2beta_org.ReactivateOrganizationRequest{
@@ -527,7 +527,7 @@ func TestServer_DeactivateReactivateOrganization(t *testing.T) {
Id: orgId,
})
require.NoError(t, err)
require.Equal(t, v2beta_org.OrganizationState_ORGANIZATION_STATE_ACTIVE, res.Organization.State)
require.Equal(t, v2beta_org.OrgState_ORG_STATE_ACTIVE, res.Organization.State)
}
func createOrgs(noOfOrgs int) ([]*v2beta_org.CreateOrganizationResponse, []string, error) {
@@ -551,6 +551,126 @@ func createOrgs(noOfOrgs int) ([]*v2beta_org.CreateOrganizationResponse, []strin
return orgs, orgsName, nil
}
func TestServer_AddOListDeleterganizationDomain(t *testing.T) {
// 1. create organization
orgs, _, err := createOrgs(1)
if err != nil {
assert.Fail(t, "unable to create org")
}
orgId := orgs[0].OrganizationId
ctx := Instance.WithAuthorization(context.Background(), integration.UserTypeIAMOwner)
domain := "www.domain.com"
// 2. add domain
addOrgDomainRes, err := Client.AddOrganizationDomain(ctx, &v2beta_org.AddOrganizationDomainRequest{
OrganizationId: orgId,
Domain: domain,
})
require.NoError(t, err)
// check details
assert.NotZero(t, addOrgDomainRes.GetDetails().GetSequence())
gotCD := addOrgDomainRes.GetDetails().GetChangeDate().AsTime()
now := time.Now()
assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute))
assert.NotEmpty(t, addOrgDomainRes.GetDetails().GetResourceOwner())
// 2. check domain is added
queryRes, err := Client.ListOrganizationDomains(CTX, &v2beta_org.ListOrganizationDomainsRequest{
OrganizationId: orgId,
})
require.NoError(t, err)
found := false
for _, res := range queryRes.Result {
if res.DomainName == domain {
found = true
}
}
require.True(t, found, "unable to find added domain")
// 3. readd domain
_, err = Client.AddOrganizationDomain(ctx, &v2beta_org.AddOrganizationDomainRequest{
OrganizationId: orgId,
Domain: domain,
})
// TODO remove error for adding already existing domain
// require.NoError(t, err)
require.Contains(t, err.Error(), "Errors.Already.Exists")
// check details
// assert.NotZero(t, addOrgDomainRes.GetDetails().GetSequence())
// gotCD = addOrgDomainRes.GetDetails().GetChangeDate().AsTime()
// now = time.Now()
// assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute))
// assert.NotEmpty(t, addOrgDomainRes.GetDetails().GetResourceOwner())
// 4. check domain is added
queryRes, err = Client.ListOrganizationDomains(CTX, &v2beta_org.ListOrganizationDomainsRequest{
OrganizationId: orgId,
})
require.NoError(t, err)
found = false
for _, res := range queryRes.Result {
if res.DomainName == domain {
found = true
}
}
require.True(t, found, "unable to find added domain")
// 5. delete organisation domain
deleteOrgDomainRes, err := Client.DeleteOrganizationDomain(ctx, &v2beta_org.DeleteOrganizationDomainRequest{
OrganizationId: orgId,
Domain: domain,
})
require.NoError(t, err)
// check details
assert.NotZero(t, deleteOrgDomainRes.GetDetails().GetSequence())
gotCD = deleteOrgDomainRes.GetDetails().GetChangeDate().AsTime()
now = time.Now()
assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute))
assert.NotEmpty(t, deleteOrgDomainRes.GetDetails().GetResourceOwner())
// 6. check organization domain deleted
queryRes, err = Client.ListOrganizationDomains(CTX, &v2beta_org.ListOrganizationDomainsRequest{
OrganizationId: orgId,
})
require.NoError(t, err)
found = false
for _, res := range queryRes.Result {
if res.DomainName == domain {
found = true
}
}
require.False(t, found, "deleted domain found")
// 7. redelete organisation domain
_, err = Client.DeleteOrganizationDomain(ctx, &v2beta_org.DeleteOrganizationDomainRequest{
OrganizationId: orgId,
Domain: domain,
})
// TODO remove error for deleting org domain already deleted
// require.NoError(t, err)
require.Contains(t, err.Error(), "Domain doesn't exist on organization")
// check details
// assert.NotZero(t, deleteOrgDomainRes.GetDetails().GetSequence())
// gotCD = deleteOrgDomainRes.GetDetails().GetChangeDate().AsTime()
// now = time.Now()
// assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute))
// assert.NotEmpty(t, deleteOrgDomainRes.GetDetails().GetResourceOwner())
// 8. check organization domain deleted
queryRes, err = Client.ListOrganizationDomains(CTX, &v2beta_org.ListOrganizationDomainsRequest{
OrganizationId: orgId,
})
require.NoError(t, err)
found = false
for _, res := range queryRes.Result {
if res.DomainName == domain {
found = true
}
}
require.False(t, found, "deleted domain found")
}
func assertCreatedAdmin(t *testing.T, expected, got *v2beta_org.CreateOrganizationResponse_CreatedAdmin) {
if expected.GetUserId() != "" {
assert.NotEmpty(t, got.GetUserId())

View File

@@ -3,7 +3,6 @@ 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"
@@ -110,7 +109,7 @@ func (s *Server) ListOrganizationDomains(ctx context.Context, req *org.ListOrgan
if err != nil {
return nil, err
}
orgIDQuery, err := query.NewOrgDomainOrgIDSearchQuery(authz.GetCtxData(ctx).OrgID)
orgIDQuery, err := query.NewOrgDomainOrgIDSearchQuery(req.OrganizationId)
if err != nil {
return nil, err
}
@@ -126,15 +125,40 @@ func (s *Server) ListOrganizationDomains(ctx context.Context, req *org.ListOrgan
}, 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 (s *Server) DeleteOrganizationDomain(ctx context.Context, req *org.DeleteOrganizationDomainRequest) (*org.DeleteOrganizationDomainResponse, error) {
details, err := s.command.RemoveOrgDomain(ctx, RemoveOrgDomainRequestToDomain(ctx, req))
if err != nil {
return nil, err
}
return &org.DeleteOrganizationDomainResponse{
Details: object.DomainToDetailsPb(details),
}, err
}
func (s *Server) GenerateOrganizationDomainValidation(ctx context.Context, req *org.GenerateOrganizationDomainValidationRequest) (*org.GenerateOrganizationDomainValidationResponse, error) {
token, url, err := s.command.GenerateOrgDomainValidation(ctx, GenerateOrgDomainValidationRequestToDomain(ctx, req))
if err != nil {
return nil, err
}
return &org.GenerateOrganizationDomainValidationResponse{
Token: token,
Url: url,
}, nil
}
func (s *Server) VerifyOrganizationDomain(ctx context.Context, request *org.VerifyOrganizationDomainRequest) (*org.VerifyOrganizationDomainResponse, error) {
userIDs, err := s.getClaimedUserIDsOfOrgDomain(ctx, request.Domain, request.OrganizationId)
if err != nil {
return nil, err
}
details, err := s.command.ValidateOrgDomain(ctx, ValidateOrgDomainRequestToDomain(ctx, request), userIDs)
if err != nil {
return nil, err
}
return &org.VerifyOrganizationDomainResponse{
Details: object.DomainToChangeDetailsPb(details),
}, nil
}
func createOrganizationRequestToCommand(request *v2beta_org.CreateOrganizationRequest) (*command.OrgSetup, error) {
admins, err := createOrganizationRequestAdminsToCommand(request.GetAdmins())