- 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.
155 lines
4.0 KiB
Go
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
|
|
}
|