89 lines
2.5 KiB
Go
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,
|
|
})
|
|
}
|