mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-20 20:04:24 +00:00
feat: Add whitelabel service with branding, partner config, and email template management
- Add Service struct with db and logger dependencies and NewService constructor - Add CreateBranding, GetBranding, GetBrandingByDomain, and UpdateBranding methods for branding configuration management - Add CreatePartnerConfig and GetPartnerConfig methods for partner-specific settings - Add CreateEmailTemplate, GetEmailTemplate, and ListEmailTemplates methods for custom email template management - Add BrandingConfig with
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
package whitelabel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Service provides whitelabel management operations
|
||||
type Service struct {
|
||||
db *gorm.DB
|
||||
logger *logrus.Logger
|
||||
}
|
||||
|
||||
// NewService creates a new whitelabel service
|
||||
func NewService(db *gorm.DB, logger *logrus.Logger) *Service {
|
||||
return &Service{db: db, logger: logger}
|
||||
}
|
||||
|
||||
// CreateBranding creates a new branding configuration
|
||||
func (s *Service) CreateBranding(ctx context.Context, config *BrandingConfig) error {
|
||||
if err := s.db.WithContext(ctx).Create(config).Error; err != nil {
|
||||
s.logger.WithError(err).Error("Failed to create branding config")
|
||||
return fmt.Errorf("failed to create branding: %w", err)
|
||||
}
|
||||
s.logger.WithField("tenant_id", config.TenantID).Info("Branding config created")
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBranding retrieves branding by tenant ID
|
||||
func (s *Service) GetBranding(ctx context.Context, tenantID string) (*BrandingConfig, error) {
|
||||
var config BrandingConfig
|
||||
if err := s.db.WithContext(ctx).Where("tenant_id = ?", tenantID).First(&config).Error; err != nil {
|
||||
return nil, fmt.Errorf("branding not found: %w", err)
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// GetBrandingByDomain retrieves branding by custom domain
|
||||
func (s *Service) GetBrandingByDomain(ctx context.Context, domain string) (*BrandingConfig, error) {
|
||||
var config BrandingConfig
|
||||
if err := s.db.WithContext(ctx).Where("custom_domain = ? AND is_active = ?", domain, true).First(&config).Error; err != nil {
|
||||
return nil, fmt.Errorf("branding not found for domain: %w", err)
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// UpdateBranding updates branding configuration
|
||||
func (s *Service) UpdateBranding(ctx context.Context, config *BrandingConfig) error {
|
||||
if err := s.db.WithContext(ctx).Save(config).Error; err != nil {
|
||||
return fmt.Errorf("failed to update branding: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreatePartnerConfig creates partner configuration
|
||||
func (s *Service) CreatePartnerConfig(ctx context.Context, config *PartnerConfig) error {
|
||||
if err := s.db.WithContext(ctx).Create(config).Error; err != nil {
|
||||
return fmt.Errorf("failed to create partner config: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPartnerConfig retrieves partner configuration
|
||||
func (s *Service) GetPartnerConfig(ctx context.Context, tenantID string) (*PartnerConfig, error) {
|
||||
var config PartnerConfig
|
||||
if err := s.db.WithContext(ctx).Where("tenant_id = ?", tenantID).First(&config).Error; err != nil {
|
||||
return nil, fmt.Errorf("partner config not found: %w", err)
|
||||
}
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// CreateEmailTemplate creates a custom email template
|
||||
func (s *Service) CreateEmailTemplate(ctx context.Context, template *EmailTemplate) error {
|
||||
if err := s.db.WithContext(ctx).Create(template).Error; err != nil {
|
||||
return fmt.Errorf("failed to create email template: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetEmailTemplate retrieves an email template
|
||||
func (s *Service) GetEmailTemplate(ctx context.Context, tenantID, templateKey string) (*EmailTemplate, error) {
|
||||
var template EmailTemplate
|
||||
if err := s.db.WithContext(ctx).Where("tenant_id = ? AND template_key = ? AND is_active = ?", tenantID, templateKey, true).First(&template).Error; err != nil {
|
||||
return nil, fmt.Errorf("email template not found: %w", err)
|
||||
}
|
||||
return &template, nil
|
||||
}
|
||||
|
||||
// ListEmailTemplates lists all templates for a tenant
|
||||
func (s *Service) ListEmailTemplates(ctx context.Context, tenantID string) ([]*EmailTemplate, error) {
|
||||
var templates []*EmailTemplate
|
||||
if err := s.db.WithContext(ctx).Where("tenant_id = ?", tenantID).Find(&templates).Error; err != nil {
|
||||
return nil, fmt.Errorf("failed to list templates: %w", err)
|
||||
}
|
||||
return templates, nil
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package whitelabel
|
||||
|
||||
import "time"
|
||||
|
||||
// BrandingConfig defines partner branding configuration
|
||||
type BrandingConfig struct {
|
||||
ID string `json:"id" gorm:"primaryKey"`
|
||||
TenantID string `json:"tenant_id" gorm:"index"`
|
||||
CompanyName string `json:"company_name"`
|
||||
LogoURL string `json:"logo_url"`
|
||||
FaviconURL string `json:"favicon_url"`
|
||||
PrimaryColor string `json:"primary_color"`
|
||||
SecondaryColor string `json:"secondary_color"`
|
||||
AccentColor string `json:"accent_color"`
|
||||
FontFamily string `json:"font_family"`
|
||||
CustomCSS string `json:"custom_css"`
|
||||
CustomDomain string `json:"custom_domain" gorm:"uniqueIndex"`
|
||||
EmailFromName string `json:"email_from_name"`
|
||||
EmailFromAddr string `json:"email_from_address"`
|
||||
SupportEmail string `json:"support_email"`
|
||||
SupportPhone string `json:"support_phone"`
|
||||
TermsURL string `json:"terms_url"`
|
||||
PrivacyURL string `json:"privacy_url"`
|
||||
FooterText string `json:"footer_text"`
|
||||
SocialLinks map[string]string `json:"social_links" gorm:"serializer:json"`
|
||||
Features FeatureFlags `json:"features" gorm:"embedded;embeddedPrefix:feature_"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// FeatureFlags controls which features are enabled for a whitelabel partner
|
||||
type FeatureFlags struct {
|
||||
ShowPoweredBy bool `json:"show_powered_by"`
|
||||
CustomEmailDomain bool `json:"custom_email_domain"`
|
||||
CustomAPIDomain bool `json:"custom_api_domain"`
|
||||
AdvancedAnalytics bool `json:"advanced_analytics"`
|
||||
WhitelabelMobile bool `json:"whitelabel_mobile"`
|
||||
CustomWebhooks bool `json:"custom_webhooks"`
|
||||
APIDocsBranding bool `json:"api_docs_branding"`
|
||||
MultiLanguage bool `json:"multi_language"`
|
||||
}
|
||||
|
||||
// EmailTemplate defines customizable email templates
|
||||
type EmailTemplate struct {
|
||||
ID string `json:"id" gorm:"primaryKey"`
|
||||
TenantID string `json:"tenant_id" gorm:"index"`
|
||||
TemplateKey string `json:"template_key" gorm:"index"`
|
||||
Subject string `json:"subject"`
|
||||
HTMLBody string `json:"html_body"`
|
||||
TextBody string `json:"text_body"`
|
||||
Variables []string `json:"variables" gorm:"serializer:json"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// PartnerTier defines partnership levels with different capabilities
|
||||
type PartnerTier string
|
||||
|
||||
const (
|
||||
PartnerTierBasic PartnerTier = "basic"
|
||||
PartnerTierProfession PartnerTier = "professional"
|
||||
PartnerTierEnterprise PartnerTier = "enterprise"
|
||||
PartnerTierPlatinum PartnerTier = "platinum"
|
||||
)
|
||||
|
||||
// PartnerConfig defines partner-specific configuration
|
||||
type PartnerConfig struct {
|
||||
ID string `json:"id" gorm:"primaryKey"`
|
||||
TenantID string `json:"tenant_id" gorm:"uniqueIndex"`
|
||||
Tier PartnerTier `json:"tier"`
|
||||
RevenueSharePct float64 `json:"revenue_share_pct"`
|
||||
MinMonthlyCommit float64 `json:"min_monthly_commit"`
|
||||
MaxAPIRequests int64 `json:"max_api_requests"`
|
||||
MaxProfiles int64 `json:"max_profiles"`
|
||||
AllowedCountries []string `json:"allowed_countries" gorm:"serializer:json"`
|
||||
AllowedCarriers []string `json:"allowed_carriers" gorm:"serializer:json"`
|
||||
CustomPricing map[string]any `json:"custom_pricing" gorm:"serializer:json"`
|
||||
ContractStartDate time.Time `json:"contract_start_date"`
|
||||
ContractEndDate time.Time `json:"contract_end_date"`
|
||||
IsActive bool `json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
Reference in New Issue
Block a user