mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 07:47:32 +00:00
implementation done
This commit is contained in:
23
backend/v3/api/database.go
Normal file
23
backend/v3/api/database.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
v2beta "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
|
||||
)
|
||||
|
||||
func V2BetaTextFilterToDatabase(filter v2beta.TextQueryMethod) database.TextOperation {
|
||||
switch filter {
|
||||
case v2beta.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS:
|
||||
return database.TextOperationEqual
|
||||
case v2beta.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS_IGNORE_CASE:
|
||||
return database.TextOperationEqualIgnoreCase
|
||||
case v2beta.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH:
|
||||
return database.TextOperationStartsWith
|
||||
case v2beta.TextQueryMethod_TEXT_QUERY_METHOD_STARTS_WITH_IGNORE_CASE:
|
||||
return database.TextOperationStartsWithIgnoreCase
|
||||
case v2beta.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS, v2beta.TextQueryMethod_TEXT_QUERY_METHOD_CONTAINS_IGNORE_CASE, v2beta.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH, v2beta.TextQueryMethod_TEXT_QUERY_METHOD_ENDS_WITH_IGNORE_CASE:
|
||||
panic("unimplemented text query method: " + filter.String())
|
||||
default:
|
||||
panic("unknown text query method: " + filter.String())
|
||||
}
|
||||
}
|
27
backend/v3/api/domain.go
Normal file
27
backend/v3/api/domain.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/zitadel/zitadel/backend/v3/domain"
|
||||
filter "github.com/zitadel/zitadel/pkg/grpc/filter/v2beta"
|
||||
org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
|
||||
)
|
||||
|
||||
func V2BetaOrgStateToDomain(state org.OrgState) domain.OrgState {
|
||||
switch state {
|
||||
case org.OrgState_ORG_STATE_ACTIVE:
|
||||
return domain.OrgStateActive
|
||||
case org.OrgState_ORG_STATE_INACTIVE:
|
||||
return domain.OrgStateInactive
|
||||
default:
|
||||
// TODO: removed is not supported in the domain
|
||||
panic("unknown org state: " + state.String())
|
||||
}
|
||||
}
|
||||
|
||||
func V2BetaPaginationToDomain(pagination *filter.PaginationRequest) domain.Pagination {
|
||||
return domain.Pagination{
|
||||
Limit: pagination.Limit,
|
||||
Offset: uint32(pagination.Offset),
|
||||
Ascending: pagination.Asc,
|
||||
}
|
||||
}
|
@@ -2,70 +2,197 @@ package org
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/v3/api"
|
||||
"github.com/zitadel/zitadel/backend/v3/domain"
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
filter "github.com/zitadel/zitadel/pkg/grpc/filter/v2beta"
|
||||
org "github.com/zitadel/zitadel/pkg/grpc/org/v2beta"
|
||||
)
|
||||
|
||||
// import (
|
||||
// "context"
|
||||
|
||||
// "github.com/zitadel/zitadel/backend/v3/domain"
|
||||
// "github.com/zitadel/zitadel/pkg/grpc/org/v2"
|
||||
// )
|
||||
|
||||
// func CreateOrg(ctx context.Context, req *org.AddOrganizationRequest) (resp *org.AddOrganizationResponse, err error) {
|
||||
// cmd := domain.NewAddOrgCommand(
|
||||
// req.GetName(),
|
||||
// addOrgAdminToCommand(req.GetAdmins()...)...,
|
||||
// )
|
||||
// err = domain.Invoke(ctx, cmd)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return &org.AddOrganizationResponse{
|
||||
// OrganizationId: cmd.ID,
|
||||
// }, nil
|
||||
// }
|
||||
|
||||
// func addOrgAdminToCommand(admins ...*org.AddOrganizationRequest_Admin) []*domain.AddMemberCommand {
|
||||
// cmds := make([]*domain.AddMemberCommand, len(admins))
|
||||
// for i, admin := range admins {
|
||||
// cmds[i] = &domain.AddMemberCommand{
|
||||
// UserID: admin.GetUserId(),
|
||||
// Roles: admin.GetRoles(),
|
||||
// }
|
||||
// }
|
||||
// return cmds
|
||||
// }
|
||||
|
||||
// ActivateOrganization implements [orgconnect.OrganizationServiceHandler].
|
||||
func (s *Server) ActivateOrganization(ctx context.Context, req *connect.Request[org.ActivateOrganizationRequest]) (*connect.Response[org.ActivateOrganizationResponse], error) {
|
||||
return s.UnimplementedOrganizationServiceHandler.ActivateOrganization(ctx, req)
|
||||
err := domain.Invoke(ctx, domain.NewActivateOrganizationCommand(
|
||||
authz.GetInstance(ctx).InstanceID(),
|
||||
req.Msg.GetId(),
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// DISCUSS(adlerhurst): does returning the ChangeDate bring any value?
|
||||
return connect.NewResponse(&org.ActivateOrganizationResponse{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// CreateOrganization implements [orgconnect.OrganizationServiceHandler].
|
||||
func (s *Server) CreateOrganization(ctx context.Context, req *connect.Request[org.CreateOrganizationRequest]) (*connect.Response[org.CreateOrganizationResponse], error) {
|
||||
return s.UnimplementedOrganizationServiceHandler.CreateOrganization(ctx, req)
|
||||
// TODO: Implement admins
|
||||
opts := make([]domain.CreateOrganizationCommandOpts, 0, 1+len(req.Msg.Admins))
|
||||
if req.Msg.Id != nil {
|
||||
opts = append(opts, domain.WithOrganizationID(req.Msg.GetId()))
|
||||
}
|
||||
cmd := domain.NewCreateOrganizationCommand(
|
||||
authz.GetInstance(ctx).InstanceID(),
|
||||
req.Msg.GetName(),
|
||||
opts...,
|
||||
)
|
||||
err := domain.Invoke(ctx, cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return connect.NewResponse(&org.CreateOrganizationResponse{
|
||||
Id: cmd.ID,
|
||||
CreationDate: timestamppb.New(cmd.CreatedAt),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// DeactivateOrganization implements [orgconnect.OrganizationServiceHandler].
|
||||
func (s *Server) DeactivateOrganization(ctx context.Context, req *connect.Request[org.DeactivateOrganizationRequest]) (*connect.Response[org.DeactivateOrganizationResponse], error) {
|
||||
return s.UnimplementedOrganizationServiceHandler.DeactivateOrganization(ctx, req)
|
||||
err := domain.Invoke(ctx, domain.NewDeactivateOrganizationCommand(
|
||||
authz.GetInstance(ctx).InstanceID(),
|
||||
req.Msg.GetId(),
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// DISCUSS(adlerhurst): does returning the ChangeDate bring any value?
|
||||
return connect.NewResponse(&org.DeactivateOrganizationResponse{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// DeleteOrganization implements [orgconnect.OrganizationServiceHandler].
|
||||
func (s *Server) DeleteOrganization(ctx context.Context, req *connect.Request[org.DeleteOrganizationRequest]) (*connect.Response[org.DeleteOrganizationResponse], error) {
|
||||
return s.UnimplementedOrganizationServiceHandler.DeleteOrganization(ctx, req)
|
||||
err := domain.Invoke(ctx, domain.NewDeleteOrganizationCommand(
|
||||
authz.GetInstance(ctx).InstanceID(),
|
||||
req.Msg.GetId(),
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// DISCUSS(adlerhurst): does returning the DeletionDate bring any value?
|
||||
return connect.NewResponse(&org.DeleteOrganizationResponse{
|
||||
DeletionDate: timestamppb.Now(),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// ListOrganizations implements [orgconnect.OrganizationServiceHandler].
|
||||
func (s *Server) ListOrganizations(ctx context.Context, req *connect.Request[org.ListOrganizationsRequest]) (*connect.Response[org.ListOrganizationsResponse], error) {
|
||||
return s.UnimplementedOrganizationServiceHandler.ListOrganizations(ctx, req)
|
||||
opts := orgFiltersToDomain(req.Msg.GetFilter())
|
||||
opts = slices.Grow(opts, 2)
|
||||
opts = append(opts, api.V2BetaPaginationToDomain(req.Msg.GetPagination()))
|
||||
if req.Msg.SortingColumn != org.OrgFieldName_ORG_FIELD_NAME_UNSPECIFIED {
|
||||
opts = append(opts, domain.WithOrgQuerySortingColumn(orgFieldNameToDatabase(req.Msg.SortingColumn)))
|
||||
}
|
||||
|
||||
query := domain.NewOrgsQuery(
|
||||
authz.GetInstance(ctx).InstanceID(),
|
||||
opts...,
|
||||
)
|
||||
err := domain.Invoke(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return connect.NewResponse(&org.ListOrganizationsResponse{
|
||||
Organizations: orgsFromDomain(query.Result),
|
||||
Pagination: &filter.PaginationResponse{
|
||||
AppliedLimit: uint64(req.Msg.Pagination.Limit),
|
||||
// TotalResult: TODO(adlerhurst): needs implementation in lower layers
|
||||
},
|
||||
}), nil
|
||||
}
|
||||
|
||||
// UpdateOrganization implements [orgconnect.OrganizationServiceHandler].
|
||||
func (s *Server) UpdateOrganization(ctx context.Context, req *connect.Request[org.UpdateOrganizationRequest]) (*connect.Response[org.UpdateOrganizationResponse], error) {
|
||||
return s.UnimplementedOrganizationServiceHandler.UpdateOrganization(ctx, req)
|
||||
opts := make([]domain.UpdateOrganizationCommandOpts, 0, 1)
|
||||
if req.Msg.Name != "" {
|
||||
opts = append(opts, domain.WithOrganizationName(req.Msg.GetName()))
|
||||
}
|
||||
|
||||
err := domain.Invoke(ctx, domain.NewUpdateOrganizationCommand(
|
||||
authz.GetInstance(ctx).InstanceID(),
|
||||
req.Msg.GetId(),
|
||||
opts...,
|
||||
))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return connect.NewResponse(&org.UpdateOrganizationResponse{
|
||||
ChangeDate: timestamppb.Now(),
|
||||
}), nil
|
||||
}
|
||||
|
||||
func orgFiltersToDomain(filters []*org.OrganizationSearchFilter) []domain.OrgsQueryOpts {
|
||||
opts := make([]domain.OrgsQueryOpts, len(filters))
|
||||
for i, filter := range filters {
|
||||
opts[i] = orgFilterToDomain(filter)
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
func orgFilterToDomain(filter *org.OrganizationSearchFilter) domain.OrgsQueryOpts {
|
||||
switch f := filter.Filter.(type) {
|
||||
case *org.OrganizationSearchFilter_NameFilter:
|
||||
return domain.WithOrgByNameQuery(api.V2BetaTextFilterToDatabase(f.NameFilter.Method), f.NameFilter.Name)
|
||||
case *org.OrganizationSearchFilter_DomainFilter:
|
||||
return domain.WithOrgByDomainQuery(api.V2BetaTextFilterToDatabase(f.DomainFilter.Method), f.DomainFilter.Domain)
|
||||
case *org.OrganizationSearchFilter_IdFilter:
|
||||
return domain.WithOrgByIDQuery(f.IdFilter.Id)
|
||||
case *org.OrganizationSearchFilter_StateFilter:
|
||||
return domain.WithOrgByStateQuery(api.V2BetaOrgStateToDomain(f.StateFilter.State))
|
||||
default:
|
||||
panic("unknown organization search filter: " + filter.String())
|
||||
}
|
||||
}
|
||||
|
||||
func orgsFromDomain(orgs []*domain.Organization) []*org.Organization {
|
||||
result := make([]*org.Organization, len(orgs))
|
||||
for i, o := range orgs {
|
||||
result[i] = &org.Organization{
|
||||
Id: o.ID,
|
||||
Name: o.Name,
|
||||
State: orgStateFromDomain(o.State),
|
||||
CreationDate: timestamppb.New(o.CreatedAt),
|
||||
ChangedDate: timestamppb.New(o.UpdatedAt),
|
||||
PrimaryDomain: orgPrimaryDomainFromDomain(o.Domains),
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func orgStateFromDomain(state domain.OrgState) org.OrgState {
|
||||
switch state {
|
||||
case domain.OrgStateActive:
|
||||
return org.OrgState_ORG_STATE_ACTIVE
|
||||
case domain.OrgStateInactive:
|
||||
return org.OrgState_ORG_STATE_INACTIVE
|
||||
default:
|
||||
return org.OrgState_ORG_STATE_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func orgPrimaryDomainFromDomain(domains []*domain.OrganizationDomain) string {
|
||||
for _, d := range domains {
|
||||
if d.IsPrimary {
|
||||
return d.Domain
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func orgFieldNameToDatabase(fieldName org.OrgFieldName) func(query *domain.OrgsQuery) database.Column {
|
||||
switch fieldName {
|
||||
case org.OrgFieldName_ORG_FIELD_NAME_NAME:
|
||||
return domain.OrderOrgsByName
|
||||
case org.OrgFieldName_ORG_FIELD_NAME_CREATION_DATE:
|
||||
return domain.OrderOrgsByCreationDate
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user