mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-10 16:48:52 +00:00
Complete V1 scaffold
This commit is contained in:
@@ -108,3 +108,54 @@ func (s *AuditService) ListByAction(ctx context.Context, action string, from, to
|
||||
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
// ListAuditEvents returns paginated audit events (handler interface method).
|
||||
func (s *AuditService) ListAuditEvents(page, perPage int) ([]domain.AuditEvent, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
filter := &repository.AuditFilter{
|
||||
Offset: int64((page - 1) * perPage),
|
||||
PerPage: int64(perPage),
|
||||
}
|
||||
|
||||
events, err := s.auditRepo.List(context.Background(), filter)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list audit events: %w", err)
|
||||
}
|
||||
|
||||
// Convert pointers to values for the handler interface
|
||||
var result []domain.AuditEvent
|
||||
for _, e := range events {
|
||||
if e != nil {
|
||||
result = append(result, *e)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Get total count from repository
|
||||
total := int64(len(result))
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// GetAuditEvent returns a single audit event (handler interface method).
|
||||
func (s *AuditService) GetAuditEvent(id string) (*domain.AuditEvent, error) {
|
||||
filter := &repository.AuditFilter{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
events, err := s.auditRepo.List(context.Background(), filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get audit event: %w", err)
|
||||
}
|
||||
|
||||
if len(events) == 0 {
|
||||
return nil, fmt.Errorf("audit event not found")
|
||||
}
|
||||
|
||||
return events[0], nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/shankar0123/certctl/internal/domain"
|
||||
"github.com/shankar0123/certctl/internal/repository"
|
||||
)
|
||||
|
||||
// AuditService provides business logic for recording and retrieving audit events.
|
||||
type AuditService struct {
|
||||
auditRepo repository.AuditRepository
|
||||
}
|
||||
|
||||
// NewAuditService creates a new audit service.
|
||||
func NewAuditService(auditRepo repository.AuditRepository) *AuditService {
|
||||
return &AuditService{
|
||||
auditRepo: auditRepo,
|
||||
}
|
||||
}
|
||||
|
||||
// RecordEvent records an audit event with actor, action, and resource information.
|
||||
func (s *AuditService) RecordEvent(ctx context.Context, actor string, actorType domain.ActorType, action string, resourceType string, resourceID string, details map[string]interface{}) error {
|
||||
detailsJSON, err := json.Marshal(details)
|
||||
if err != nil {
|
||||
detailsJSON = []byte("{}")
|
||||
}
|
||||
|
||||
event := &domain.AuditEvent{
|
||||
ID: generateID("audit"),
|
||||
Timestamp: time.Now(),
|
||||
Actor: actor,
|
||||
ActorType: actorType,
|
||||
Action: action,
|
||||
ResourceType: resourceType,
|
||||
ResourceID: resourceID,
|
||||
Details: json.RawMessage(detailsJSON),
|
||||
}
|
||||
|
||||
if err := s.auditRepo.Create(ctx, event); err != nil {
|
||||
return fmt.Errorf("failed to record audit event: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// List returns audit events matching filter criteria.
|
||||
func (s *AuditService) List(ctx context.Context, filter *repository.AuditFilter) ([]*domain.AuditEvent, error) {
|
||||
events, err := s.auditRepo.List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list audit events: %w", err)
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// ListByResource returns all audit events for a specific resource.
|
||||
func (s *AuditService) ListByResource(ctx context.Context, resourceType string, resourceID string) ([]*domain.AuditEvent, error) {
|
||||
filter := &repository.AuditFilter{
|
||||
ResourceType: resourceType,
|
||||
ResourceID: resourceID,
|
||||
PerPage: 1000, // reasonable default for single resource
|
||||
}
|
||||
|
||||
events, err := s.auditRepo.List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list audit events: %w", err)
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// ListByActor returns all audit events for a specific actor.
|
||||
func (s *AuditService) ListByActor(ctx context.Context, actor string) ([]*domain.AuditEvent, error) {
|
||||
filter := &repository.AuditFilter{
|
||||
Actor: actor,
|
||||
PerPage: 1000,
|
||||
}
|
||||
|
||||
events, err := s.auditRepo.List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list audit events: %w", err)
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// ListByAction returns all audit events for a specific action type.
|
||||
func (s *AuditService) ListByAction(ctx context.Context, action string, from, to time.Time) ([]*domain.AuditEvent, error) {
|
||||
filter := &repository.AuditFilter{
|
||||
From: from,
|
||||
To: to,
|
||||
PerPage: 1000,
|
||||
}
|
||||
|
||||
events, err := s.auditRepo.List(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list audit events: %w", err)
|
||||
}
|
||||
|
||||
// Filter by action on client side (repository may not filter by action directly)
|
||||
var filtered []*domain.AuditEvent
|
||||
for _, e := range events {
|
||||
if e.Action == action {
|
||||
filtered = append(filtered, e)
|
||||
}
|
||||
}
|
||||
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
// ListAuditEvents returns paginated audit events (handler interface method).
|
||||
func (s *AuditService) ListAuditEvents(page, perPage int) ([]domain.AuditEvent, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
filter := &repository.AuditFilter{
|
||||
Offset: int64((page - 1) * perPage),
|
||||
PerPage: int64(perPage),
|
||||
}
|
||||
|
||||
events, err := s.auditRepo.List(context.Background(), filter)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list audit events: %w", err)
|
||||
}
|
||||
|
||||
// Convert pointers to values for the handler interface
|
||||
var result []domain.AuditEvent
|
||||
for _, e := range events {
|
||||
if e != nil {
|
||||
result = append(result, *e)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Get total count from repository
|
||||
total := int64(len(result))
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// GetAuditEvent returns a single audit event (handler interface method).
|
||||
func (s *AuditService) GetAuditEvent(id string) (*domain.AuditEvent, error) {
|
||||
filter := &repository.AuditFilter{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
events, err := s.auditRepo.List(context.Background(), filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get audit event: %w", err)
|
||||
}
|
||||
|
||||
if len(events) == 0 {
|
||||
return nil, fmt.Errorf("audit event not found")
|
||||
}
|
||||
|
||||
return events[0], nil
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/shankar0123/certctl/internal/domain"
|
||||
"github.com/shankar0123/certctl/internal/repository"
|
||||
)
|
||||
|
||||
// IssuerService provides business logic for certificate issuer management.
|
||||
type IssuerService struct {
|
||||
issuerRepo repository.IssuerRepository
|
||||
auditService *AuditService
|
||||
}
|
||||
|
||||
// NewIssuerService creates a new issuer service.
|
||||
func NewIssuerService(
|
||||
issuerRepo repository.IssuerRepository,
|
||||
auditService *AuditService,
|
||||
) *IssuerService {
|
||||
return &IssuerService{
|
||||
issuerRepo: issuerRepo,
|
||||
auditService: auditService,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a paginated list of issuers.
|
||||
func (s *IssuerService) List(ctx context.Context, page, perPage int) ([]*domain.Issuer, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
offset := int64((page - 1) * perPage)
|
||||
issuers, total, err := s.issuerRepo.List(ctx, offset, int64(perPage))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list issuers: %w", err)
|
||||
}
|
||||
return issuers, total, nil
|
||||
}
|
||||
|
||||
// Get retrieves an issuer by ID.
|
||||
func (s *IssuerService) Get(ctx context.Context, id string) (*domain.Issuer, error) {
|
||||
issuer, err := s.issuerRepo.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get issuer %s: %w", id, err)
|
||||
}
|
||||
return issuer, nil
|
||||
}
|
||||
|
||||
// Create validates and stores a new issuer.
|
||||
func (s *IssuerService) Create(ctx context.Context, issuer *domain.Issuer, actor string) error {
|
||||
if issuer.Name == "" {
|
||||
return fmt.Errorf("issuer name is required")
|
||||
}
|
||||
|
||||
issuer.ID = generateID("issuer")
|
||||
if err := s.issuerRepo.Create(ctx, issuer); err != nil {
|
||||
return fmt.Errorf("failed to create issuer: %w", err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "create_issuer", "issuer", issuer.ID, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update modifies an existing issuer.
|
||||
func (s *IssuerService) Update(ctx context.Context, id string, issuer *domain.Issuer, actor string) error {
|
||||
if issuer.Name == "" {
|
||||
return fmt.Errorf("issuer name is required")
|
||||
}
|
||||
|
||||
issuer.ID = id
|
||||
if err := s.issuerRepo.Update(ctx, issuer); err != nil {
|
||||
return fmt.Errorf("failed to update issuer %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "update_issuer", "issuer", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes an issuer.
|
||||
func (s *IssuerService) Delete(ctx context.Context, id string, actor string) error {
|
||||
if err := s.issuerRepo.Delete(ctx, id); err != nil {
|
||||
return fmt.Errorf("failed to delete issuer %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "delete_issuer", "issuer", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestConnection verifies the issuer connection.
|
||||
func (s *IssuerService) TestConnection(ctx context.Context, id string) error {
|
||||
issuer, err := s.issuerRepo.Get(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("issuer not found: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Implement actual connection test based on issuer type
|
||||
if issuer == nil {
|
||||
return fmt.Errorf("issuer not found")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListIssuers returns paginated issuers (handler interface method).
|
||||
func (s *IssuerService) ListIssuers(page, perPage int) ([]domain.Issuer, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
offset := int64((page - 1) * perPage)
|
||||
issuers, total, err := s.issuerRepo.List(context.Background(), offset, int64(perPage))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list issuers: %w", err)
|
||||
}
|
||||
|
||||
// Convert pointers to values for the handler interface
|
||||
var result []domain.Issuer
|
||||
for _, i := range issuers {
|
||||
if i != nil {
|
||||
result = append(result, *i)
|
||||
}
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// GetIssuer returns a single issuer (handler interface method).
|
||||
func (s *IssuerService) GetIssuer(id string) (*domain.Issuer, error) {
|
||||
return s.issuerRepo.Get(context.Background(), id)
|
||||
}
|
||||
|
||||
// CreateIssuer creates a new issuer (handler interface method).
|
||||
func (s *IssuerService) CreateIssuer(issuer domain.Issuer) (*domain.Issuer, error) {
|
||||
issuer.ID = generateID("issuer")
|
||||
if err := s.issuerRepo.Create(context.Background(), &issuer); err != nil {
|
||||
return nil, fmt.Errorf("failed to create issuer: %w", err)
|
||||
}
|
||||
return &issuer, nil
|
||||
}
|
||||
|
||||
// UpdateIssuer modifies an issuer (handler interface method).
|
||||
func (s *IssuerService) UpdateIssuer(id string, issuer domain.Issuer) (*domain.Issuer, error) {
|
||||
issuer.ID = id
|
||||
if err := s.issuerRepo.Update(context.Background(), &issuer); err != nil {
|
||||
return nil, fmt.Errorf("failed to update issuer: %w", err)
|
||||
}
|
||||
return &issuer, nil
|
||||
}
|
||||
|
||||
// DeleteIssuer removes an issuer (handler interface method).
|
||||
func (s *IssuerService) DeleteIssuer(id string) error {
|
||||
return s.issuerRepo.Delete(context.Background(), id)
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/shankar0123/certctl/internal/domain"
|
||||
"github.com/shankar0123/certctl/internal/repository"
|
||||
)
|
||||
|
||||
// IssuerService provides business logic for certificate issuer management.
|
||||
type IssuerService struct {
|
||||
issuerRepo repository.IssuerRepository
|
||||
auditService *AuditService
|
||||
}
|
||||
|
||||
// NewIssuerService creates a new issuer service.
|
||||
func NewIssuerService(
|
||||
issuerRepo repository.IssuerRepository,
|
||||
auditService *AuditService,
|
||||
) *IssuerService {
|
||||
return &IssuerService{
|
||||
issuerRepo: issuerRepo,
|
||||
auditService: auditService,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a paginated list of issuers.
|
||||
func (s *IssuerService) List(ctx context.Context, page, perPage int) ([]*domain.Issuer, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
offset := int64((page - 1) * perPage)
|
||||
issuers, total, err := s.issuerRepo.List(ctx, offset, int64(perPage))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list issuers: %w", err)
|
||||
}
|
||||
return issuers, total, nil
|
||||
}
|
||||
|
||||
// Get retrieves an issuer by ID.
|
||||
func (s *IssuerService) Get(ctx context.Context, id string) (*domain.Issuer, error) {
|
||||
issuer, err := s.issuerRepo.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get issuer %s: %w", id, err)
|
||||
}
|
||||
return issuer, nil
|
||||
}
|
||||
|
||||
// Create validates and stores a new issuer.
|
||||
func (s *IssuerService) Create(ctx context.Context, issuer *domain.Issuer, actor string) error {
|
||||
if issuer.Name == "" {
|
||||
return fmt.Errorf("issuer name is required")
|
||||
}
|
||||
|
||||
issuer.ID = generateID("issuer")
|
||||
if err := s.issuerRepo.Create(ctx, issuer); err != nil {
|
||||
return fmt.Errorf("failed to create issuer: %w", err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "create_issuer", "issuer", issuer.ID, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update modifies an existing issuer.
|
||||
func (s *IssuerService) Update(ctx context.Context, id string, issuer *domain.Issuer, actor string) error {
|
||||
if issuer.Name == "" {
|
||||
return fmt.Errorf("issuer name is required")
|
||||
}
|
||||
|
||||
issuer.ID = id
|
||||
if err := s.issuerRepo.Update(ctx, issuer); err != nil {
|
||||
return fmt.Errorf("failed to update issuer %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "update_issuer", "issuer", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes an issuer.
|
||||
func (s *IssuerService) Delete(ctx context.Context, id string, actor string) error {
|
||||
if err := s.issuerRepo.Delete(ctx, id); err != nil {
|
||||
return fmt.Errorf("failed to delete issuer %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "delete_issuer", "issuer", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestConnection verifies the issuer connection.
|
||||
func (s *IssuerService) TestConnection(ctx context.Context, id string) error {
|
||||
issuer, err := s.issuerRepo.Get(ctx, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("issuer not found: %w", err)
|
||||
}
|
||||
|
||||
// TODO: Implement actual connection test based on issuer type
|
||||
if issuer == nil {
|
||||
return fmt.Errorf("issuer not found")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/shankar0123/certctl/internal/domain"
|
||||
"github.com/shankar0123/certctl/internal/repository"
|
||||
)
|
||||
|
||||
// OwnerService provides business logic for certificate owner management.
|
||||
type OwnerService struct {
|
||||
ownerRepo repository.OwnerRepository
|
||||
auditService *AuditService
|
||||
}
|
||||
|
||||
// NewOwnerService creates a new owner service.
|
||||
func NewOwnerService(
|
||||
ownerRepo repository.OwnerRepository,
|
||||
auditService *AuditService,
|
||||
) *OwnerService {
|
||||
return &OwnerService{
|
||||
ownerRepo: ownerRepo,
|
||||
auditService: auditService,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a paginated list of owners.
|
||||
func (s *OwnerService) List(ctx context.Context, page, perPage int) ([]*domain.Owner, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
offset := int64((page - 1) * perPage)
|
||||
owners, total, err := s.ownerRepo.List(ctx, offset, int64(perPage))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list owners: %w", err)
|
||||
}
|
||||
return owners, total, nil
|
||||
}
|
||||
|
||||
// Get retrieves an owner by ID.
|
||||
func (s *OwnerService) Get(ctx context.Context, id string) (*domain.Owner, error) {
|
||||
owner, err := s.ownerRepo.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get owner %s: %w", id, err)
|
||||
}
|
||||
return owner, nil
|
||||
}
|
||||
|
||||
// Create validates and stores a new owner.
|
||||
func (s *OwnerService) Create(ctx context.Context, owner *domain.Owner, actor string) error {
|
||||
if owner.Name == "" {
|
||||
return fmt.Errorf("owner name is required")
|
||||
}
|
||||
|
||||
owner.ID = generateID("owner")
|
||||
if err := s.ownerRepo.Create(ctx, owner); err != nil {
|
||||
return fmt.Errorf("failed to create owner: %w", err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "create_owner", "owner", owner.ID, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update modifies an existing owner.
|
||||
func (s *OwnerService) Update(ctx context.Context, id string, owner *domain.Owner, actor string) error {
|
||||
if owner.Name == "" {
|
||||
return fmt.Errorf("owner name is required")
|
||||
}
|
||||
|
||||
owner.ID = id
|
||||
if err := s.ownerRepo.Update(ctx, owner); err != nil {
|
||||
return fmt.Errorf("failed to update owner %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "update_owner", "owner", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes an owner.
|
||||
func (s *OwnerService) Delete(ctx context.Context, id string, actor string) error {
|
||||
if err := s.ownerRepo.Delete(ctx, id); err != nil {
|
||||
return fmt.Errorf("failed to delete owner %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "delete_owner", "owner", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListOwners returns paginated owners (handler interface method).
|
||||
func (s *OwnerService) ListOwners(page, perPage int) ([]domain.Owner, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
offset := int64((page - 1) * perPage)
|
||||
owners, total, err := s.ownerRepo.List(context.Background(), offset, int64(perPage))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list owners: %w", err)
|
||||
}
|
||||
|
||||
// Convert pointers to values for the handler interface
|
||||
var result []domain.Owner
|
||||
for _, o := range owners {
|
||||
if o != nil {
|
||||
result = append(result, *o)
|
||||
}
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// GetOwner returns a single owner (handler interface method).
|
||||
func (s *OwnerService) GetOwner(id string) (*domain.Owner, error) {
|
||||
return s.ownerRepo.Get(context.Background(), id)
|
||||
}
|
||||
|
||||
// CreateOwner creates a new owner (handler interface method).
|
||||
func (s *OwnerService) CreateOwner(owner domain.Owner) (*domain.Owner, error) {
|
||||
owner.ID = generateID("owner")
|
||||
if err := s.ownerRepo.Create(context.Background(), &owner); err != nil {
|
||||
return nil, fmt.Errorf("failed to create owner: %w", err)
|
||||
}
|
||||
return &owner, nil
|
||||
}
|
||||
|
||||
// UpdateOwner modifies an owner (handler interface method).
|
||||
func (s *OwnerService) UpdateOwner(id string, owner domain.Owner) (*domain.Owner, error) {
|
||||
owner.ID = id
|
||||
if err := s.ownerRepo.Update(context.Background(), &owner); err != nil {
|
||||
return nil, fmt.Errorf("failed to update owner: %w", err)
|
||||
}
|
||||
return &owner, nil
|
||||
}
|
||||
|
||||
// DeleteOwner removes an owner (handler interface method).
|
||||
func (s *OwnerService) DeleteOwner(id string) error {
|
||||
return s.ownerRepo.Delete(context.Background(), id)
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/shankar0123/certctl/internal/domain"
|
||||
"github.com/shankar0123/certctl/internal/repository"
|
||||
)
|
||||
|
||||
// TargetService provides business logic for deployment target management.
|
||||
type TargetService struct {
|
||||
targetRepo repository.TargetRepository
|
||||
auditService *AuditService
|
||||
}
|
||||
|
||||
// NewTargetService creates a new target service.
|
||||
func NewTargetService(
|
||||
targetRepo repository.TargetRepository,
|
||||
auditService *AuditService,
|
||||
) *TargetService {
|
||||
return &TargetService{
|
||||
targetRepo: targetRepo,
|
||||
auditService: auditService,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a paginated list of deployment targets.
|
||||
func (s *TargetService) List(ctx context.Context, page, perPage int) ([]*domain.DeploymentTarget, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
offset := int64((page - 1) * perPage)
|
||||
targets, total, err := s.targetRepo.List(ctx, offset, int64(perPage))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list targets: %w", err)
|
||||
}
|
||||
return targets, total, nil
|
||||
}
|
||||
|
||||
// Get retrieves a deployment target by ID.
|
||||
func (s *TargetService) Get(ctx context.Context, id string) (*domain.DeploymentTarget, error) {
|
||||
target, err := s.targetRepo.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get target %s: %w", id, err)
|
||||
}
|
||||
return target, nil
|
||||
}
|
||||
|
||||
// Create validates and stores a new deployment target.
|
||||
func (s *TargetService) Create(ctx context.Context, target *domain.DeploymentTarget, actor string) error {
|
||||
if target.Name == "" {
|
||||
return fmt.Errorf("target name is required")
|
||||
}
|
||||
|
||||
target.ID = generateID("target")
|
||||
if err := s.targetRepo.Create(ctx, target); err != nil {
|
||||
return fmt.Errorf("failed to create target: %w", err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "create_target", "target", target.ID, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update modifies an existing deployment target.
|
||||
func (s *TargetService) Update(ctx context.Context, id string, target *domain.DeploymentTarget, actor string) error {
|
||||
if target.Name == "" {
|
||||
return fmt.Errorf("target name is required")
|
||||
}
|
||||
|
||||
target.ID = id
|
||||
if err := s.targetRepo.Update(ctx, target); err != nil {
|
||||
return fmt.Errorf("failed to update target %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "update_target", "target", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes a deployment target.
|
||||
func (s *TargetService) Delete(ctx context.Context, id string, actor string) error {
|
||||
if err := s.targetRepo.Delete(ctx, id); err != nil {
|
||||
return fmt.Errorf("failed to delete target %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "delete_target", "target", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListTargets returns paginated targets (handler interface method).
|
||||
func (s *TargetService) ListTargets(page, perPage int) ([]domain.DeploymentTarget, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
offset := int64((page - 1) * perPage)
|
||||
targets, total, err := s.targetRepo.List(context.Background(), offset, int64(perPage))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list targets: %w", err)
|
||||
}
|
||||
|
||||
// Convert pointers to values for the handler interface
|
||||
var result []domain.DeploymentTarget
|
||||
for _, t := range targets {
|
||||
if t != nil {
|
||||
result = append(result, *t)
|
||||
}
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// GetTarget returns a single target (handler interface method).
|
||||
func (s *TargetService) GetTarget(id string) (*domain.DeploymentTarget, error) {
|
||||
return s.targetRepo.Get(context.Background(), id)
|
||||
}
|
||||
|
||||
// CreateTarget creates a new target (handler interface method).
|
||||
func (s *TargetService) CreateTarget(target domain.DeploymentTarget) (*domain.DeploymentTarget, error) {
|
||||
target.ID = generateID("target")
|
||||
if err := s.targetRepo.Create(context.Background(), &target); err != nil {
|
||||
return nil, fmt.Errorf("failed to create target: %w", err)
|
||||
}
|
||||
return &target, nil
|
||||
}
|
||||
|
||||
// UpdateTarget modifies a target (handler interface method).
|
||||
func (s *TargetService) UpdateTarget(id string, target domain.DeploymentTarget) (*domain.DeploymentTarget, error) {
|
||||
target.ID = id
|
||||
if err := s.targetRepo.Update(context.Background(), &target); err != nil {
|
||||
return nil, fmt.Errorf("failed to update target: %w", err)
|
||||
}
|
||||
return &target, nil
|
||||
}
|
||||
|
||||
// DeleteTarget removes a target (handler interface method).
|
||||
func (s *TargetService) DeleteTarget(id string) error {
|
||||
return s.targetRepo.Delete(context.Background(), id)
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/shankar0123/certctl/internal/domain"
|
||||
"github.com/shankar0123/certctl/internal/repository"
|
||||
)
|
||||
|
||||
// TeamService provides business logic for team management.
|
||||
type TeamService struct {
|
||||
teamRepo repository.TeamRepository
|
||||
auditService *AuditService
|
||||
}
|
||||
|
||||
// NewTeamService creates a new team service.
|
||||
func NewTeamService(
|
||||
teamRepo repository.TeamRepository,
|
||||
auditService *AuditService,
|
||||
) *TeamService {
|
||||
return &TeamService{
|
||||
teamRepo: teamRepo,
|
||||
auditService: auditService,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns a paginated list of teams.
|
||||
func (s *TeamService) List(ctx context.Context, page, perPage int) ([]*domain.Team, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
offset := int64((page - 1) * perPage)
|
||||
teams, total, err := s.teamRepo.List(ctx, offset, int64(perPage))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list teams: %w", err)
|
||||
}
|
||||
return teams, total, nil
|
||||
}
|
||||
|
||||
// Get retrieves a team by ID.
|
||||
func (s *TeamService) Get(ctx context.Context, id string) (*domain.Team, error) {
|
||||
team, err := s.teamRepo.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get team %s: %w", id, err)
|
||||
}
|
||||
return team, nil
|
||||
}
|
||||
|
||||
// Create validates and stores a new team.
|
||||
func (s *TeamService) Create(ctx context.Context, team *domain.Team, actor string) error {
|
||||
if team.Name == "" {
|
||||
return fmt.Errorf("team name is required")
|
||||
}
|
||||
|
||||
team.ID = generateID("team")
|
||||
if err := s.teamRepo.Create(ctx, team); err != nil {
|
||||
return fmt.Errorf("failed to create team: %w", err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "create_team", "team", team.ID, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update modifies an existing team.
|
||||
func (s *TeamService) Update(ctx context.Context, id string, team *domain.Team, actor string) error {
|
||||
if team.Name == "" {
|
||||
return fmt.Errorf("team name is required")
|
||||
}
|
||||
|
||||
team.ID = id
|
||||
if err := s.teamRepo.Update(ctx, team); err != nil {
|
||||
return fmt.Errorf("failed to update team %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "update_team", "team", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes a team.
|
||||
func (s *TeamService) Delete(ctx context.Context, id string, actor string) error {
|
||||
if err := s.teamRepo.Delete(ctx, id); err != nil {
|
||||
return fmt.Errorf("failed to delete team %s: %w", id, err)
|
||||
}
|
||||
|
||||
if s.auditService != nil {
|
||||
_ = s.auditService.RecordEvent(ctx, actor, domain.ActorTypeUser, "delete_team", "team", id, nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListTeams returns paginated teams (handler interface method).
|
||||
func (s *TeamService) ListTeams(page, perPage int) ([]domain.Team, int64, error) {
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 50
|
||||
}
|
||||
|
||||
offset := int64((page - 1) * perPage)
|
||||
teams, total, err := s.teamRepo.List(context.Background(), offset, int64(perPage))
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to list teams: %w", err)
|
||||
}
|
||||
|
||||
// Convert pointers to values for the handler interface
|
||||
var result []domain.Team
|
||||
for _, t := range teams {
|
||||
if t != nil {
|
||||
result = append(result, *t)
|
||||
}
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
|
||||
// GetTeam returns a single team (handler interface method).
|
||||
func (s *TeamService) GetTeam(id string) (*domain.Team, error) {
|
||||
return s.teamRepo.Get(context.Background(), id)
|
||||
}
|
||||
|
||||
// CreateTeam creates a new team (handler interface method).
|
||||
func (s *TeamService) CreateTeam(team domain.Team) (*domain.Team, error) {
|
||||
team.ID = generateID("team")
|
||||
if err := s.teamRepo.Create(context.Background(), &team); err != nil {
|
||||
return nil, fmt.Errorf("failed to create team: %w", err)
|
||||
}
|
||||
return &team, nil
|
||||
}
|
||||
|
||||
// UpdateTeam modifies a team (handler interface method).
|
||||
func (s *TeamService) UpdateTeam(id string, team domain.Team) (*domain.Team, error) {
|
||||
team.ID = id
|
||||
if err := s.teamRepo.Update(context.Background(), &team); err != nil {
|
||||
return nil, fmt.Errorf("failed to update team: %w", err)
|
||||
}
|
||||
return &team, nil
|
||||
}
|
||||
|
||||
// DeleteTeam removes a team (handler interface method).
|
||||
func (s *TeamService) DeleteTeam(id string) error {
|
||||
return s.teamRepo.Delete(context.Background(), id)
|
||||
}
|
||||
Reference in New Issue
Block a user