Files
BagExchange/controllers/subscribe_controller.go
2026-02-19 20:08:06 +01:00

89 lines
2.5 KiB
Go

package controllers
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"log"
"net/mail"
"strings"
"time"
"github.com/gofiber/fiber/v3"
"gorm.io/gorm"
)
type SubscribeController struct {
DB *gorm.DB
IsUniqueConstraint func(error) bool
}
type subscribeRequest struct {
Email string `json:"email"`
BrowserData map[string]any `json:"browserData"`
}
const subscriptionCookieName = "bag_exchange_subscribed"
func (s *SubscribeController) Subscribe(c fiber.Ctx) error {
var req subscribeRequest
if err := json.Unmarshal(c.Body(), &req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(map[string]string{"error": "invalid payload"})
}
email := strings.ToLower(strings.TrimSpace(req.Email))
if _, err := mail.ParseAddress(email); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(map[string]string{"error": "invalid email"})
}
emailHash := hashEmail(email)
if c.Cookies(subscriptionCookieName) == emailHash {
return c.Status(fiber.StatusConflict).JSON(map[string]string{"status": "already_submitted"})
}
browserData := "{}"
if len(req.BrowserData) > 0 {
payload, err := json.Marshal(req.BrowserData)
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(map[string]string{"error": "invalid browser data"})
}
browserData = string(payload)
}
err := s.DB.Table("subscribers").Create(map[string]any{
"email": email,
"ip_address": c.IP(),
"user_agent": c.Get("User-Agent"),
"accept_language": c.Get("Accept-Language"),
"browser_data": browserData,
}).Error
if err != nil {
if s.IsUniqueConstraint != nil && s.IsUniqueConstraint(err) {
setSubscriptionCookie(c, emailHash)
return c.Status(fiber.StatusConflict).JSON(map[string]string{"status": "already_submitted"})
}
log.Printf("unable to insert subscriber: %v", err)
return c.Status(fiber.StatusInternalServerError).JSON(map[string]string{"error": "unable to save subscription"})
}
setSubscriptionCookie(c, emailHash)
return c.Status(fiber.StatusCreated).JSON(map[string]string{"status": "subscribed"})
}
func hashEmail(email string) string {
sum := sha256.Sum256([]byte(strings.ToLower(strings.TrimSpace(email))))
return hex.EncodeToString(sum[:])
}
func setSubscriptionCookie(c fiber.Ctx, value string) {
c.Cookie(&fiber.Cookie{
Name: subscriptionCookieName,
Value: value,
Path: "/",
HTTPOnly: false,
Secure: false,
Expires: time.Now().AddDate(1, 0, 0),
MaxAge: 60 * 60 * 24 * 365,
})
}