Files
encore-test/advertising/advertising.go
fabio 664db8f7a0 feat(advertising): implement advertising service with CRUD operations and validation
- Added advertising.go for managing advertising entries with Create and List functionalities.
- Implemented CreateAdvertisingParams with validation for name, email, and status.
- Created migrations for advertising table structure.
- Added tests for advertising parameters validation.

feat(promo): introduce promo management with validation and CRUD operations

- Added promo.go for managing promotional entries with Create, Update, and List functionalities.
- Implemented CreatePromoParams and UpdatePromoParams with validation for position, section, and weeks.
- Created migrations for promo table structure.
- Added tests for promo parameters validation.

feat(images): add image management service with upload and retrieval

- Added images.go for managing image uploads and retrieval from storage.
- Implemented SaveImageParams with validation for image description and data.
- Created migrations for images table structure.
- Added tests for image parameters validation and data parsing.
2026-10-01 20:19:07 +02:00

155 lines
4.0 KiB
Go

// Service advertising gestisce l'elenco delle inserzioni pubblicitarie (Advertising Directory).
package advertising
import (
"context"
"net/mail"
"strings"
"time"
"encore.dev/beta/errs"
"encore.dev/storage/sqldb"
"encore.dev/types/uuid"
)
var db = sqldb.NewDatabase("advertising", sqldb.DatabaseConfig{
Migrations: "./migrations",
})
type Status string
const (
StatusActive Status = "active"
StatusInactive Status = "inactive"
)
type Advertising struct {
ID uuid.UUID `json:"id"`
Nome string `json:"nome"`
Email string `json:"email"`
Status Status `json:"status"`
CreatedAt time.Time `json:"created_at"`
}
type CreateAdvertisingParams struct {
Nome string `json:"nome"`
Email string `json:"email"`
Status Status `json:"status,omitempty"`
}
func (p *CreateAdvertisingParams) Validate() error {
if p == nil {
return &errs.Error{Code: errs.InvalidArgument, Message: "i parametri di creazione sono obbligatori"}
}
email, err := normalizeEmailValue(p.Email)
if err != nil {
return err
}
p.Email = email
nome := normalizeText(p.Nome)
if nome == "" {
return &errs.Error{Code: errs.InvalidArgument, Message: "il nome è obbligatorio"}
}
p.Nome = nome
if p.Status == "" {
p.Status = StatusActive
} else if p.Status != StatusActive && p.Status != StatusInactive {
return &errs.Error{Code: errs.InvalidArgument, Message: "lo status deve essere 'active' o 'inactive'"}
}
return nil
}
func normalizeEmailValue(email string) (string, error) {
email = strings.TrimSpace(strings.ToLower(email))
if email == "" {
return "", &errs.Error{Code: errs.InvalidArgument, Message: "l'email è obbligatoria"}
}
parsed, err := mail.ParseAddress(email)
if err != nil || !strings.Contains(parsed.Address, "@") || !strings.Contains(parsed.Address, ".") {
return "", &errs.Error{Code: errs.InvalidArgument, Message: "indirizzo email non valido"}
}
return strings.TrimSpace(strings.ToLower(parsed.Address)), nil
}
func normalizeText(value string) string {
value = strings.TrimSpace(value)
if value == "" {
return ""
}
parts := strings.Fields(value)
return strings.Join(parts, " ")
}
type ListAdvertisingResponse struct {
Advertising []*Advertising `json:"advertising"`
}
// List ritorna l'intera lista delle pubblicità ordinate per data di creazione.
//
//encore:api public method=GET path=/advertising
func List(ctx context.Context) (*ListAdvertisingResponse, error) {
rows, err := db.Query(ctx, `
SELECT id, nome, email, status, created_at
FROM advertising
ORDER BY created_at DESC
`)
if err != nil {
return nil, errs.WrapCode(err, errs.Internal, "errore durante il recupero delle pubblicità")
}
defer rows.Close()
var list []*Advertising
for rows.Next() {
var a Advertising
if err := rows.Scan(&a.ID, &a.Nome, &a.Email, &a.Status, &a.CreatedAt); err != nil {
return nil, errs.WrapCode(err, errs.Internal, "errore durante la lettura del record pubblicità")
}
list = append(list, &a)
}
if err := rows.Err(); err != nil {
return nil, errs.WrapCode(err, errs.Internal, "errore durante l'iterazione delle pubblicità")
}
if list == nil {
list = []*Advertising{}
}
return &ListAdvertisingResponse{Advertising: list}, nil
}
// Create crea un nuovo cliente/pubblicità con validazione dell'email e dei campi.
//
//encore:api public method=POST path=/advertising
func Create(ctx context.Context, p *CreateAdvertisingParams) (*Advertising, error) {
if err := p.Validate(); err != nil {
return nil, err
}
id, err := uuid.NewV4()
if err != nil {
return nil, errs.WrapCode(err, errs.Internal, "impossibile generare l'identificativo UUID")
}
item := Advertising{
ID: id,
Nome: p.Nome,
Email: p.Email,
Status: p.Status,
}
err = db.QueryRow(ctx, `
INSERT INTO advertising (id, nome, email, status)
VALUES ($1, $2, $3, $4)
RETURNING created_at
`, id, p.Nome, p.Email, p.Status).Scan(&item.CreatedAt)
if err != nil {
return nil, errs.WrapCode(err, errs.Internal, "impossibile creare la pubblicità")
}
return &item, nil
}