From ae6b8a3858b6816fb83c765f0073188d8ef10d11 Mon Sep 17 00:00:00 2001 From: Bryan Frimin Date: Wed, 1 Oct 2025 00:17:06 +0200 Subject: [PATCH] Add service impl Signed-off-by: Bryan Frimin --- pkg/coredata/custom_domain.go | 1 + pkg/probo/custom_domain_service.go | 129 +++++++++++++++++++++++++++++ pkg/probo/service.go | 19 +++++ 3 files changed, 149 insertions(+) create mode 100644 pkg/probo/custom_domain_service.go diff --git a/pkg/coredata/custom_domain.go b/pkg/coredata/custom_domain.go index 7db982b1b..265643922 100644 --- a/pkg/coredata/custom_domain.go +++ b/pkg/coredata/custom_domain.go @@ -58,6 +58,7 @@ func NewCustomDomain(orgID gid.GID, domain string) *CustomDomain { return &CustomDomain{ ID: gid.New(orgID.TenantID(), CustomDomainEntityType), OrganizationID: orgID, + SSLStatus: CustomDomainSSLStatusPending, Domain: domain, IsActive: false, CreatedAt: now, diff --git a/pkg/probo/custom_domain_service.go b/pkg/probo/custom_domain_service.go new file mode 100644 index 000000000..c9901aff1 --- /dev/null +++ b/pkg/probo/custom_domain_service.go @@ -0,0 +1,129 @@ +// Copyright (c) 2025 Probo Inc . +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +package probo + +import ( + "context" + "fmt" + + "github.com/getprobo/probo/pkg/certmanager" + "github.com/getprobo/probo/pkg/coredata" + "github.com/getprobo/probo/pkg/crypto/cipher" + "github.com/getprobo/probo/pkg/gid" + "github.com/getprobo/probo/pkg/page" + "go.gearno.de/kit/log" + "go.gearno.de/kit/pg" +) + +type ( + CustomDomainService struct { + svc *TenantService + acmeService *certmanager.ACMEService + encryptionKey cipher.EncryptionKey + logger *log.Logger + } + + CreateCustomDomainRequest struct { + OrganizationID gid.GID + Domain string + } +) + +func NewCustomDomainService( + svc *TenantService, + acmeService *certmanager.ACMEService, + encryptionKey cipher.EncryptionKey, + logger *log.Logger, +) *CustomDomainService { + return &CustomDomainService{ + svc: svc, + acmeService: acmeService, + encryptionKey: encryptionKey, + logger: logger.Named("custom_domain"), + } +} + +func (s *CustomDomainService) CreateCustomDomain( + ctx context.Context, + req CreateCustomDomainRequest, +) (*coredata.CustomDomain, error) { + var domain *coredata.CustomDomain + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + domain = coredata.NewCustomDomain(req.OrganizationID, req.Domain) + + if err := domain.Insert(ctx, conn, s.svc.scope, s.encryptionKey); err != nil { + return fmt.Errorf("cannot insert custom domain: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return domain, nil +} + +func (s *CustomDomainService) DeleteCustomDomain( + ctx context.Context, + domainID gid.GID, +) error { + return s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + domain := &coredata.CustomDomain{} + if err := domain.LoadByID(ctx, conn, s.svc.scope, s.encryptionKey, domainID); err != nil { + return fmt.Errorf("cannot load domain: %w", err) + } + + if err := domain.Delete(ctx, conn, s.svc.scope); err != nil { + return fmt.Errorf("cannot delete domain: %w", err) + } + + return nil + }, + ) +} + +func (s *CustomDomainService) ListOrganizationDomains( + ctx context.Context, + organizationID gid.GID, + cursor *page.Cursor[coredata.CustomDomainOrderField], +) (*page.Page[*coredata.CustomDomain, coredata.CustomDomainOrderField], error) { + var domains coredata.CustomDomains + + err := s.svc.pg.WithConn( + ctx, + func(conn pg.Conn) error { + err := domains.LoadByOrganizationID(ctx, conn, s.svc.scope, s.encryptionKey, organizationID, cursor) + if err != nil { + return fmt.Errorf("cannot list domains: %w", err) + } + + return nil + }, + ) + + if err != nil { + return nil, err + } + + return page.NewPage(domains, cursor), nil +} diff --git a/pkg/probo/service.go b/pkg/probo/service.go index 3558b3d2b..3dbc287ff 100644 --- a/pkg/probo/service.go +++ b/pkg/probo/service.go @@ -21,12 +21,14 @@ import ( "github.com/aws/aws-sdk-go-v2/service/s3" "github.com/getprobo/probo/pkg/agents" + "github.com/getprobo/probo/pkg/certmanager" "github.com/getprobo/probo/pkg/coredata" "github.com/getprobo/probo/pkg/crypto/cipher" "github.com/getprobo/probo/pkg/filevalidation" "github.com/getprobo/probo/pkg/gid" "github.com/getprobo/probo/pkg/html2pdf" "github.com/getprobo/probo/pkg/usrmgr" + "go.gearno.de/kit/log" "go.gearno.de/kit/pg" "go.gearno.de/x/ref" ) @@ -54,6 +56,8 @@ type ( agentConfig agents.Config html2pdfConverter *html2pdf.Converter usrmgr *usrmgr.Service + acmeService *certmanager.ACMEService + logger *log.Logger } TenantService struct { @@ -94,7 +98,11 @@ type ( Snapshots *SnapshotService ContinualImprovements *ContinualImprovementService ProcessingActivities *ProcessingActivityService +<<<<<<< HEAD Files *FileService +======= + CustomDomains *CustomDomainService +>>>>>>> 087e86b5 (Add service impl) } ) @@ -110,6 +118,8 @@ func NewService( agentConfig agents.Config, html2pdfConverter *html2pdf.Converter, usrmgrService *usrmgr.Service, + acmeService *certmanager.ACMEService, + logger *log.Logger, ) (*Service, error) { if bucket == "" { return nil, fmt.Errorf("bucket is required") @@ -126,6 +136,8 @@ func NewService( agentConfig: agentConfig, html2pdfConverter: html2pdfConverter, usrmgr: usrmgrService, + acmeService: acmeService, + logger: logger, } return svc, nil @@ -195,6 +207,13 @@ func (s *Service) WithTenant(tenantID gid.TenantID) *TenantService { tenantService.ContinualImprovements = &ContinualImprovementService{svc: tenantService} tenantService.ProcessingActivities = &ProcessingActivityService{svc: tenantService} tenantService.Files = &FileService{svc: tenantService} + tenantService.CustomDomains = &CustomDomainService{ + svc: tenantService, + encryptionKey: s.encryptionKey, + acmeService: s.acmeService, + logger: s.logger.Named("custom_domains"), + } + return tenantService }