360 lines
9.2 KiB
Go
360 lines
9.2 KiB
Go
package cms
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"tm/pkg/logger"
|
|
"tm/pkg/response"
|
|
)
|
|
|
|
// Service defines the interface for CMS business operations
|
|
type Service interface {
|
|
// Create creates a new CMS entry
|
|
Create(ctx context.Context, form *CMSForm) (*CMSResponse, error)
|
|
|
|
// GetByID retrieves a CMS entry by ID
|
|
GetByID(ctx context.Context, id string) (*CMSResponse, error)
|
|
|
|
// GetByKey retrieves a CMS entry by key
|
|
GetByKey(ctx context.Context, key string) (*CMSResponse, error)
|
|
|
|
// Update updates a CMS entry
|
|
Update(ctx context.Context, id string, form *CMSForm) (*CMSResponse, error)
|
|
|
|
// Delete deletes a CMS entry by ID
|
|
Delete(ctx context.Context, id string) error
|
|
|
|
// Search searches CMS entries with filters and pagination
|
|
Search(ctx context.Context, form *SearchCMSForm, pagination *response.Pagination) (*CMSListResponse, error)
|
|
}
|
|
|
|
// cmsService implements Service interface
|
|
type cmsService struct {
|
|
repo Repository
|
|
logger logger.Logger
|
|
}
|
|
|
|
// NewService creates a new CMS service
|
|
func NewService(repo Repository, logger logger.Logger) Service {
|
|
return &cmsService{
|
|
repo: repo,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// Create creates a new CMS entry
|
|
func (s *cmsService) Create(ctx context.Context, form *CMSForm) (*CMSResponse, error) {
|
|
s.logger.Info("Creating new CMS entry", map[string]interface{}{
|
|
"key": form.Key,
|
|
})
|
|
|
|
// Check if CMS with this key already exists
|
|
existing, err := s.repo.GetByKey(ctx, form.Key)
|
|
if err == nil && existing != nil {
|
|
s.logger.Warn("CMS with this key already exists", map[string]interface{}{
|
|
"key": form.Key,
|
|
})
|
|
return nil, ErrCMSKeyExists
|
|
}
|
|
|
|
// Create CMS entity
|
|
cms := &CMS{
|
|
Key: form.Key,
|
|
}
|
|
|
|
// Copy form data to entity
|
|
s.copyFormToEntity(form, cms)
|
|
|
|
// Save to database
|
|
if err := s.repo.Create(ctx, cms); err != nil {
|
|
s.logger.Error("Failed to create CMS", map[string]interface{}{
|
|
"key": form.Key,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, fmt.Errorf("failed to create CMS: %w", err)
|
|
}
|
|
|
|
s.logger.Info("CMS entry created successfully", map[string]interface{}{
|
|
"id": cms.GetID(),
|
|
"key": form.Key,
|
|
})
|
|
|
|
return cms.ToResponse(), nil
|
|
}
|
|
|
|
// GetByID retrieves a CMS entry by ID
|
|
func (s *cmsService) GetByID(ctx context.Context, id string) (*CMSResponse, error) {
|
|
s.logger.Debug("Retrieving CMS by ID", map[string]interface{}{
|
|
"id": id,
|
|
})
|
|
|
|
cms, err := s.repo.GetByID(ctx, id)
|
|
if err != nil {
|
|
if errors.Is(err, ErrCMSNotFound) {
|
|
return nil, ErrCMSNotFound
|
|
}
|
|
s.logger.Error("Failed to get CMS by ID", map[string]interface{}{
|
|
"id": id,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, fmt.Errorf("failed to get CMS: %w", err)
|
|
}
|
|
|
|
return cms.ToResponse(), nil
|
|
}
|
|
|
|
// GetByKey retrieves a CMS entry by key
|
|
func (s *cmsService) GetByKey(ctx context.Context, key string) (*CMSResponse, error) {
|
|
s.logger.Debug("Retrieving CMS by key", map[string]interface{}{
|
|
"key": key,
|
|
})
|
|
|
|
cms, err := s.repo.GetByKey(ctx, key)
|
|
if err != nil {
|
|
if errors.Is(err, ErrCMSNotFound) {
|
|
return nil, ErrCMSNotFound
|
|
}
|
|
s.logger.Error("Failed to get CMS by key", map[string]interface{}{
|
|
"key": key,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, fmt.Errorf("failed to get CMS: %w", err)
|
|
}
|
|
|
|
return cms.ToResponse(), nil
|
|
}
|
|
|
|
// Update updates a CMS entry
|
|
func (s *cmsService) Update(ctx context.Context, id string, form *CMSForm) (*CMSResponse, error) {
|
|
s.logger.Info("Updating CMS entry", map[string]interface{}{
|
|
"id": id,
|
|
"key": form.Key,
|
|
})
|
|
|
|
// Get existing CMS
|
|
cms, err := s.repo.GetByID(ctx, id)
|
|
if err != nil {
|
|
if errors.Is(err, ErrCMSNotFound) {
|
|
return nil, ErrCMSNotFound
|
|
}
|
|
s.logger.Error("Failed to get existing CMS for update", map[string]interface{}{
|
|
"id": id,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, fmt.Errorf("failed to get CMS for update: %w", err)
|
|
}
|
|
|
|
// Check if key is being changed and if new key already exists
|
|
if cms.Key != form.Key {
|
|
existing, err := s.repo.GetByKey(ctx, form.Key)
|
|
if err == nil && existing != nil && existing.GetID() != id {
|
|
s.logger.Warn("CMS with this key already exists", map[string]interface{}{
|
|
"key": form.Key,
|
|
})
|
|
return nil, ErrCMSKeyExists
|
|
}
|
|
cms.Key = form.Key
|
|
}
|
|
|
|
// Copy form data to entity
|
|
s.copyFormToEntity(form, cms)
|
|
|
|
// Update in database
|
|
if err := s.repo.Update(ctx, cms); err != nil {
|
|
s.logger.Error("Failed to update CMS", map[string]interface{}{
|
|
"id": id,
|
|
"key": form.Key,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, fmt.Errorf("failed to update CMS: %w", err)
|
|
}
|
|
|
|
s.logger.Info("CMS entry updated successfully", map[string]interface{}{
|
|
"id": id,
|
|
"key": form.Key,
|
|
})
|
|
|
|
return cms.ToResponse(), nil
|
|
}
|
|
|
|
// Delete deletes a CMS entry by ID
|
|
func (s *cmsService) Delete(ctx context.Context, id string) error {
|
|
s.logger.Info("Deleting CMS entry", map[string]interface{}{
|
|
"id": id,
|
|
})
|
|
|
|
if err := s.repo.Delete(ctx, id); err != nil {
|
|
if errors.Is(err, ErrCMSNotFound) {
|
|
return ErrCMSNotFound
|
|
}
|
|
s.logger.Error("Failed to delete CMS", map[string]interface{}{
|
|
"id": id,
|
|
"error": err.Error(),
|
|
})
|
|
return fmt.Errorf("failed to delete CMS: %w", err)
|
|
}
|
|
|
|
s.logger.Info("CMS entry deleted successfully", map[string]interface{}{
|
|
"id": id,
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// Search searches CMS entries with filters and pagination
|
|
func (s *cmsService) Search(ctx context.Context, form *SearchCMSForm, pagination *response.Pagination) (*CMSListResponse, error) {
|
|
s.logger.Debug("Searching CMS entries", map[string]interface{}{
|
|
"filters": form,
|
|
"pagination": pagination,
|
|
})
|
|
|
|
result, err := s.repo.Search(ctx, form, pagination)
|
|
if err != nil {
|
|
s.logger.Error("Failed to search CMS entries", map[string]interface{}{
|
|
"filters": form,
|
|
"error": err.Error(),
|
|
})
|
|
return nil, fmt.Errorf("failed to search CMS entries: %w", err)
|
|
}
|
|
|
|
// Convert to response format
|
|
cmsResponses := make([]*CMSResponse, len(result.Items))
|
|
for i, cms := range result.Items {
|
|
cmsResponses[i] = cms.ToResponse()
|
|
}
|
|
|
|
s.logger.Info("CMS search completed", map[string]interface{}{
|
|
"total_count": result.TotalCount,
|
|
"items_count": len(result.Items),
|
|
})
|
|
|
|
return &CMSListResponse{
|
|
CMS: cmsResponses,
|
|
Meta: pagination.ListMeta(result.TotalCount, result.NextCursor, result.HasMore, result.PageOffset),
|
|
}, nil
|
|
}
|
|
|
|
// copyFormToEntity copies data from form to entity
|
|
func (s *cmsService) copyFormToEntity(form *CMSForm, cms *CMS) {
|
|
if form.Type != "" {
|
|
cms.Type = CMSType(form.Type)
|
|
}
|
|
|
|
switch cms.Type {
|
|
case CMSTypeCompany:
|
|
if form.Language != "" {
|
|
cms.Language = form.Language
|
|
}
|
|
if form.CompanyName != "" {
|
|
cms.CompanyName = form.CompanyName
|
|
}
|
|
if form.Country != "" {
|
|
cms.Country = form.Country
|
|
}
|
|
case CMSTypeOrganization:
|
|
cms.Language = ""
|
|
cms.CompanyName = ""
|
|
cms.Country = ""
|
|
}
|
|
|
|
// Hero section
|
|
if form.Hero.Title != "" {
|
|
cms.Hero.Title = form.Hero.Title
|
|
}
|
|
if form.Hero.Description != "" {
|
|
cms.Hero.Description = form.Hero.Description
|
|
}
|
|
if form.Hero.ButtonText != "" {
|
|
cms.Hero.ButtonText = form.Hero.ButtonText
|
|
}
|
|
if form.Hero.ButtonLink != "" {
|
|
cms.Hero.ButtonLink = form.Hero.ButtonLink
|
|
}
|
|
if form.Hero.GifFile != "" {
|
|
cms.Hero.GifFile = form.Hero.GifFile
|
|
}
|
|
|
|
// Chart section
|
|
if form.Chart.Title != "" {
|
|
cms.Chart.Title = form.Chart.Title
|
|
}
|
|
if form.Chart.MissedAmount != "" {
|
|
cms.Chart.MissedAmount = form.Chart.MissedAmount
|
|
}
|
|
if len(form.Chart.Data) > 0 {
|
|
cms.Chart.Data = make([]chartPoint, len(form.Chart.Data))
|
|
for i, point := range form.Chart.Data {
|
|
cms.Chart.Data[i] = chartPoint(point)
|
|
}
|
|
}
|
|
|
|
// Features section
|
|
s.copyCardSectionForm(&form.Features, &cms.Features)
|
|
|
|
// Challenges section
|
|
s.copyCardSectionForm(&form.Challenges, &cms.Challenges)
|
|
|
|
// Advantages section
|
|
s.copyCardSectionForm(&form.Advantages, &cms.Advantages)
|
|
|
|
// Contact section
|
|
if form.Contact.Title != "" {
|
|
cms.Contact.Title = form.Contact.Title
|
|
}
|
|
if form.Contact.Description != "" {
|
|
cms.Contact.Description = form.Contact.Description
|
|
}
|
|
if form.Contact.SubmitButtonText != "" {
|
|
cms.Contact.SubmitButtonText = form.Contact.SubmitButtonText
|
|
}
|
|
if len(form.Contact.Fields) > 0 {
|
|
cms.Contact.Fields = make([]formField, len(form.Contact.Fields))
|
|
for i, field := range form.Contact.Fields {
|
|
cms.Contact.Fields[i] = formField{
|
|
Name: field.Name,
|
|
Label: field.Label,
|
|
Placeholder: field.Placeholder,
|
|
Required: field.Required,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Footer section
|
|
if form.Footer.Email != "" {
|
|
cms.Footer.Email = form.Footer.Email
|
|
}
|
|
if form.Footer.Phone != "" {
|
|
cms.Footer.Phone = form.Footer.Phone
|
|
}
|
|
if form.Footer.Location != "" {
|
|
cms.Footer.Location = form.Footer.Location
|
|
}
|
|
if form.Footer.Tagline != "" {
|
|
cms.Footer.Tagline = form.Footer.Tagline
|
|
}
|
|
if form.Footer.Copyright != "" {
|
|
cms.Footer.Copyright = form.Footer.Copyright
|
|
}
|
|
}
|
|
|
|
// copyCardSectionForm copies card section form data to entity
|
|
func (s *cmsService) copyCardSectionForm(formSection *cardSectionForm, entitySection *cardSection) {
|
|
if formSection.Title != "" {
|
|
entitySection.Title = formSection.Title
|
|
}
|
|
if formSection.Description != "" {
|
|
entitySection.Description = formSection.Description
|
|
}
|
|
if len(formSection.Cards) > 0 {
|
|
entitySection.Cards = make([]card, len(formSection.Cards))
|
|
for i, cardForm := range formSection.Cards {
|
|
entitySection.Cards[i] = card{
|
|
Icon: cardForm.Icon,
|
|
Title: cardForm.Title,
|
|
Description: cardForm.Description,
|
|
}
|
|
}
|
|
}
|
|
}
|