Files
zitadel/backend/v3/api/org/v2/org.go
T
b339a3e696 feat: instance domain APIs with relational tables (#11051)
# Which Problems Are Solved

This PR implements the endpoints listed in
https://github.com/zitadel/zitadel/issues/10444 .

# How the Problems Are Solved

The implementation follows the same pattern as the Instance one. The
`Add` and `Remove` are implementing the `Commander` interface, while
`List` Domains endpoints are implementing the `Querier` interace.

The PR adds also some forgotten calls to the relational logic for the
Instance API. The commits are identifiable by the label `instance:`
prepended to them. This is the complete list: bafce01b0 , 6fe7257ab ,
e27bc9c34 , 8133ede73 , fde667953 , a3e1135ed , ee1a6f9c1

# Additional Context

- Closes #10444

---------

Co-authored-by: Elio Bischof <[email protected]>
Co-authored-by: Lebogang Phoshoko <[email protected]>
Co-authored-by: Wim Van Laer <[email protected]>
Co-authored-by: Max Peintner <[email protected]>
Co-authored-by: Gayathri Vijayan <[email protected]>
2025-12-17 12:01:09 +01:00

161 lines
6.2 KiB
Go

package orgv2
import (
"context"
"errors"
"connectrpc.com/connect"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/backend/v3/api/org/v2/convert"
"github.com/zitadel/zitadel/backend/v3/domain"
"github.com/zitadel/zitadel/backend/v3/storage/database"
"github.com/zitadel/zitadel/backend/v3/storage/database/repository"
filter "github.com/zitadel/zitadel/pkg/grpc/filter/v2beta"
"github.com/zitadel/zitadel/pkg/grpc/object/v2"
v2_org "github.com/zitadel/zitadel/pkg/grpc/org/v2"
v2beta_org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
)
// =================
// v2Beta endpoints
// =================
func UpdateOrganizationBeta(ctx context.Context, request *connect.Request[v2beta_org.UpdateOrganizationRequest]) (*connect.Response[v2beta_org.UpdateOrganizationResponse], error) {
orgUpdateCmd := domain.NewUpdateOrgCommand(request.Msg.GetId(), request.Msg.GetName())
// TODO(IAM-Marco) Finish implementation in https://github.com/zitadel/zitadel/issues/10447
domainAddCmd := domain.NewAddOrgDomainCommand(request.Msg.GetId(), request.Msg.GetName())
domainSetPrimaryCmd := domain.NewSetPrimaryOrgDomainCommand(request.Msg.GetId(), request.Msg.GetName())
domainRemoveCmd := domain.NewRemoveOrgDomainCommand(request.Msg.GetId(), orgUpdateCmd.OldDomainName, orgUpdateCmd.IsOldDomainVerified)
batchCmd := domain.BatchExecutors(orgUpdateCmd, domainAddCmd, domainSetPrimaryCmd, domainRemoveCmd)
err := domain.Invoke(ctx, batchCmd, domain.WithOrganizationRepo(repository.OrganizationRepository()))
if err != nil {
return nil, err
}
return &connect.Response[v2beta_org.UpdateOrganizationResponse]{
Msg: &v2beta_org.UpdateOrganizationResponse{
// TODO(IAM-Marco): Change this with the real update date when OrganizationRepo.Update()
// returns the timestamp. See https://github.com/zitadel/zitadel/issues/10881
ChangeDate: timestamppb.Now(),
},
}, nil
}
// TODO(IAM-Marco): Remove in V5 (see https://github.com/zitadel/zitadel/issues/10877)
func ListOrganizationsBeta(ctx context.Context, request *connect.Request[v2beta_org.ListOrganizationsRequest]) (*connect.Response[v2beta_org.ListOrganizationsResponse], error) {
orgListQuery := domain.NewListOrgsQuery(convert.OrganizationBetaRequestToV2Request(request.Msg))
err := domain.Invoke(ctx, orgListQuery,
domain.WithOrganizationRepo(repository.OrganizationRepository()),
domain.WithOrganizationDomainRepo(repository.OrganizationDomainRepository()),
)
if err != nil {
return nil, err
}
orgs := convert.DomainOrganizationListModelToGRPCBetaResponse(orgListQuery.Result())
return &connect.Response[v2beta_org.ListOrganizationsResponse]{
Msg: &v2beta_org.ListOrganizationsResponse{
Organizations: orgs,
Pagination: &filter.PaginationResponse{
TotalResult: uint64(len(orgs)),
AppliedLimit: uint64(request.Msg.GetPagination().GetLimit()),
},
},
}, nil
}
func DeleteOrganizationBeta(ctx context.Context, request *connect.Request[v2beta_org.DeleteOrganizationRequest]) (*connect.Response[v2beta_org.DeleteOrganizationResponse], error) {
orgDeleteCmd := domain.NewDeleteOrgCommand(request.Msg.GetId())
err := domain.Invoke(ctx, orgDeleteCmd,
domain.WithOrganizationRepo(repository.OrganizationRepository()),
domain.WithProjectRepo(repository.ProjectRepository()),
)
if err != nil {
var notFoundError *database.NoRowFoundError
if errors.As(err, &notFoundError) {
return connect.NewResponse(&v2beta_org.DeleteOrganizationResponse{}), nil
}
return nil, err
}
return &connect.Response[v2beta_org.DeleteOrganizationResponse]{
Msg: &v2beta_org.DeleteOrganizationResponse{
// TODO(IAM-Marco): Change this with the real update date when OrganizationRepo.Delete()
// returns the timestamp. See https://github.com/zitadel/zitadel/issues/10881
DeletionDate: timestamppb.Now(),
},
}, nil
}
func DeactivateOrganizationBeta(ctx context.Context, request *connect.Request[v2beta_org.DeactivateOrganizationRequest]) (*connect.Response[v2beta_org.DeactivateOrganizationResponse], error) {
orgDeactivateCmd := domain.NewDeactivateOrgCommand(request.Msg.GetId())
err := domain.Invoke(ctx, orgDeactivateCmd,
domain.WithOrganizationRepo(repository.OrganizationRepository()),
)
if err != nil {
return nil, err
}
return &connect.Response[v2beta_org.DeactivateOrganizationResponse]{
Msg: &v2beta_org.DeactivateOrganizationResponse{
// TODO(IAM-Marco): Change this with the real update date when OrganizationRepo.Update()
// returns the timestamp. See https://github.com/zitadel/zitadel/issues/10881
ChangeDate: timestamppb.Now(),
},
}, nil
}
func ActivateOrganizationBeta(ctx context.Context, request *connect.Request[v2beta_org.ActivateOrganizationRequest]) (*connect.Response[v2beta_org.ActivateOrganizationResponse], error) {
orgActivateCmd := domain.NewActivateOrgCommand(request.Msg.GetId())
err := domain.Invoke(ctx, orgActivateCmd,
domain.WithOrganizationRepo(repository.OrganizationRepository()),
)
if err != nil {
return nil, err
}
return &connect.Response[v2beta_org.ActivateOrganizationResponse]{
Msg: &v2beta_org.ActivateOrganizationResponse{
// TODO(IAM-Marco): Change this with the real update date when OrganizationRepo.Update()
// returns the timestamp. See https://github.com/zitadel/zitadel/issues/10881
ChangeDate: timestamppb.Now(),
},
}, nil
}
// =================
// v2 endpoints
// =================
func ListOrganizations(ctx context.Context, request *connect.Request[v2_org.ListOrganizationsRequest]) (*connect.Response[v2_org.ListOrganizationsResponse], error) {
orgListQuery := domain.NewListOrgsQuery(request.Msg)
err := domain.Invoke(ctx, orgListQuery,
domain.WithOrganizationRepo(repository.OrganizationRepository()),
domain.WithOrganizationDomainRepo(repository.OrganizationDomainRepository()),
)
if err != nil {
return nil, err
}
orgs := convert.DomainOrganizationListModelToGRPCResponse(orgListQuery.Result())
return &connect.Response[v2_org.ListOrganizationsResponse]{
Msg: &v2_org.ListOrganizationsResponse{
Result: orgs,
Details: &object.ListDetails{
// TODO(IAM-Marco): Return correct result once permissions are in place
TotalResult: uint64(len(orgs)),
},
SortingColumn: request.Msg.GetSortingColumn(),
},
}, nil
}