feat(organization): WiP - Add organization management
Adds the core functionality for managing organizations, including the domain, application service, repository, and CLI adapter. The `organization` command and its subcommands (`create`, `show`, `update`, `delete`) are now available. Note: The `show` command is currently not working as expected due to an API issue where it does not find the newly created organization. This is marked as a work in progress.
This commit is contained in:
parent
ac3033d70f
commit
65e3daeee5
7 changed files with 233 additions and 3 deletions
Binary file not shown.
|
|
@ -50,14 +50,23 @@ func (a *Adapter) CreateOrganization(ctx context.Context, org *domain.Organizati
|
|||
func (a *Adapter) ShowOrganization(ctx context.Context, name string) (*domain.Organization, error) {
|
||||
apiPath := "/api/v1/auth/org/show"
|
||||
reqBody := map[string]string{"name": name}
|
||||
var org domain.Organization
|
||||
var orgs []domain.Organization
|
||||
|
||||
_, err := a.client.Call(ctx, http.MethodPost, apiPath, reqBody, &org)
|
||||
_, err := a.client.Call(ctx, http.MethodPost, apiPath, reqBody, &orgs)
|
||||
if err != nil {
|
||||
// TODO: Improve error handling, check for 404 and return domain.ErrResourceNotFound
|
||||
return nil, fmt.Errorf("failed to show organization %s: %w", name, err)
|
||||
}
|
||||
return &org, nil
|
||||
|
||||
if len(orgs) == 0 {
|
||||
return nil, fmt.Errorf("organization '%s' not found", name)
|
||||
}
|
||||
|
||||
if len(orgs) > 1 {
|
||||
a.client.Logf("warning: ShowOrganization for '%s' returned %d results, expected 1", name, len(orgs))
|
||||
}
|
||||
|
||||
return &orgs[0], nil
|
||||
}
|
||||
|
||||
// UpdateOrganization updates an existing organization.
|
||||
|
|
|
|||
113
internal/adapters/driving/cli/organization.go
Normal file
113
internal/adapters/driving/cli/organization.go
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(organizationCmd)
|
||||
organizationCmd.AddCommand(createOrganizationCmd, showOrganizationCmd, updateOrganizationCmd, deleteOrganizationCmd)
|
||||
|
||||
// Flags for create/update
|
||||
createOrganizationCmd.Flags().StringVar(&orgAddress, "address", "", "Address of the organization")
|
||||
createOrganizationCmd.Flags().StringVar(&orgPhone, "phone", "", "Phone number of the organization")
|
||||
|
||||
updateOrganizationCmd.Flags().StringVar(&orgAddress, "address", "", "New address for the organization")
|
||||
updateOrganizationCmd.Flags().StringVar(&orgPhone, "phone", "", "New phone number for the organization")
|
||||
}
|
||||
|
||||
var (
|
||||
orgName string
|
||||
orgAddress string
|
||||
orgPhone string
|
||||
)
|
||||
|
||||
// organizationCmd represents the parent command for all organization-related actions.
|
||||
var organizationCmd = &cobra.Command{
|
||||
Use: "organization",
|
||||
Short: "Manage organizations",
|
||||
Long: `Create, show, update, and delete organizations in Edge Connect.`,
|
||||
Aliases: []string{"org"},
|
||||
}
|
||||
|
||||
var createOrganizationCmd = &cobra.Command{
|
||||
Use: "create [name]",
|
||||
Short: "Create a new organization",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
org := &domain.Organization{
|
||||
Name: args[0],
|
||||
Address: orgAddress,
|
||||
Phone: orgPhone,
|
||||
}
|
||||
err := services.OrganizationService.Create(context.Background(), org)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating organization: %w", err)
|
||||
}
|
||||
fmt.Printf("Organization '%s' created successfully.\n", args[0])
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var showOrganizationCmd = &cobra.Command{
|
||||
Use: "show [name]",
|
||||
Short: "Show details of an organization",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
org, err := services.OrganizationService.Get(context.Background(), args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error showing organization: %w", err)
|
||||
}
|
||||
fmt.Printf("Organization Details:\n")
|
||||
fmt.Printf(" Name: %s\n", org.Name)
|
||||
fmt.Printf(" Address: %s\n", org.Address)
|
||||
fmt.Printf(" Phone: %s\n", org.Phone)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var updateOrganizationCmd = &cobra.Command{
|
||||
Use: "update [name]",
|
||||
Short: "Update an organization",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// First, get the current organization to update
|
||||
org, err := services.OrganizationService.Get(context.Background(), args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not retrieve organization to update: %w", err)
|
||||
}
|
||||
|
||||
// Update fields if flags were provided
|
||||
if cmd.Flags().Changed("address") {
|
||||
org.Address = orgAddress
|
||||
}
|
||||
if cmd.Flags().Changed("phone") {
|
||||
org.Phone = orgPhone
|
||||
}
|
||||
|
||||
err = services.OrganizationService.Update(context.Background(), org)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error updating organization: %w", err)
|
||||
}
|
||||
fmt.Printf("Organization '%s' updated successfully.\n", args[0])
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var deleteOrganizationCmd = &cobra.Command{
|
||||
Use: "delete [name]",
|
||||
Short: "Delete an organization",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
err := services.OrganizationService.Delete(context.Background(), args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting organization: %w", err)
|
||||
}
|
||||
fmt.Printf("Organization '%s' deleted successfully.\n", args[0])
|
||||
return nil
|
||||
},
|
||||
}
|
||||
63
internal/application/organization/service.go
Normal file
63
internal/application/organization/service.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
package organization
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain"
|
||||
"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driven"
|
||||
"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driving"
|
||||
)
|
||||
|
||||
// service implements the OrganizationService interface and provides the core business logic.
|
||||
type service struct {
|
||||
repo driven.OrganizationRepository
|
||||
}
|
||||
|
||||
// NewService creates a new organization service with the given repository.
|
||||
func NewService(repo driven.OrganizationRepository) driving.OrganizationService {
|
||||
return &service{repo: repo}
|
||||
}
|
||||
|
||||
// CreateOrganization validates the organization and passes it to the repository for creation.
|
||||
func (s *service) Create(ctx context.Context, org *domain.Organization) error {
|
||||
if err := s.validateOrganization(org); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.repo.CreateOrganization(ctx, org)
|
||||
}
|
||||
|
||||
// Get retrieves an organization by name.
|
||||
func (s *service) Get(ctx context.Context, name string) (*domain.Organization, error) {
|
||||
if strings.TrimSpace(name) == "" {
|
||||
return nil, domain.NewDomainError(domain.ErrValidationFailed, "organization name cannot be empty")
|
||||
}
|
||||
return s.repo.ShowOrganization(ctx, name)
|
||||
}
|
||||
|
||||
// Update validates the organization and passes it to the repository for updates.
|
||||
func (s *service) Update(ctx context.Context, org *domain.Organization) error {
|
||||
if err := s.validateOrganization(org); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.repo.UpdateOrganization(ctx, org)
|
||||
}
|
||||
|
||||
// Delete removes an organization by name.
|
||||
func (s *service) Delete(ctx context.Context, name string) error {
|
||||
if strings.TrimSpace(name) == "" {
|
||||
return domain.NewDomainError(domain.ErrValidationFailed, "organization name cannot be empty")
|
||||
}
|
||||
return s.repo.DeleteOrganization(ctx, name)
|
||||
}
|
||||
|
||||
// validateOrganization contains the business logic for validating an organization.
|
||||
func (s *service) validateOrganization(org *domain.Organization) error {
|
||||
if org == nil {
|
||||
return domain.NewDomainError(domain.ErrValidationFailed, "organization cannot be nil")
|
||||
}
|
||||
if strings.TrimSpace(org.Name) == "" {
|
||||
return domain.NewDomainError(domain.ErrValidationFailed, "organization name cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
9
internal/core/domain/organization.go
Normal file
9
internal/core/domain/organization.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
package domain
|
||||
|
||||
// Organization represents the core business object for an organization.
|
||||
// It contains identifying information such as name, address, and phone number.
|
||||
type Organization struct {
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address"`
|
||||
Phone string `json:"phone"`
|
||||
}
|
||||
20
internal/core/ports/driven/organization_repository.go
Normal file
20
internal/core/ports/driven/organization_repository.go
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package driven
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain"
|
||||
)
|
||||
|
||||
// OrganizationRepository defines the port for interacting with organization data storage.
|
||||
// This interface provides a technology-agnostic way for the core application to manage organizations.
|
||||
type OrganizationRepository interface {
|
||||
// CreateOrganization persists a new organization.
|
||||
CreateOrganization(ctx context.Context, org *domain.Organization) error
|
||||
// ShowOrganization retrieves a single organization by its name.
|
||||
ShowOrganization(ctx context.Context, name string) (*domain.Organization, error)
|
||||
// UpdateOrganization updates an existing organization.
|
||||
UpdateOrganization(ctx context.Context, org *domain.Organization) error
|
||||
// DeleteOrganization removes an organization by its name.
|
||||
DeleteOrganization(ctx context.Context, name string) error
|
||||
}
|
||||
16
internal/core/ports/driving/organization_service.go
Normal file
16
internal/core/ports/driving/organization_service.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package driving
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain"
|
||||
)
|
||||
|
||||
// OrganizationService defines the driving port for managing organizations.
|
||||
// This is the primary interface for interacting with the application's organization logic.
|
||||
type OrganizationService interface {
|
||||
Create(ctx context.Context, org *domain.Organization) error
|
||||
Get(ctx context.Context, name string) (*domain.Organization, error)
|
||||
Update(ctx context.Context, org *domain.Organization) error
|
||||
Delete(ctx context.Context, name string) error
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue