Files
2026-05-31 02:17:46 +03:30

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,
}
}
}
}