mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
dev day #69
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -26,6 +27,32 @@ type ContactController struct {
|
||||
emailService email.EmailService
|
||||
}
|
||||
|
||||
// GetNewsletterTokenForUser returns a short-lived newsletter preferences token for the authenticated user's email
|
||||
// GET /api/v1/newsletter/token/me (auth required)
|
||||
func (cc *ContactController) GetNewsletterTokenForUser(c *gin.Context) {
|
||||
u, ok := c.Get("user")
|
||||
if !ok || u == nil {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Not authenticated"})
|
||||
return
|
||||
}
|
||||
|
||||
user := u.(*models.User)
|
||||
email := strings.TrimSpace(strings.ToLower(user.Email))
|
||||
if email == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "User email not available"})
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a 24h token for managing newsletter preferences
|
||||
token, err := utils.GenerateSubscriberToken(email, 60*24)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"token": token})
|
||||
}
|
||||
|
||||
// SendNewsletterDigest builds and sends a digest newsletter based on a template type (admin only)
|
||||
// POST /api/v1/admin/newsletter/send-digest { type: "blogs|events|matches|scores|weekly", competitions?: "ABC, DEF" }
|
||||
func (cc *ContactController) SendNewsletterDigest(c *gin.Context) {
|
||||
@@ -921,18 +948,71 @@ func (cc *ContactController) SubscribeToNewsletter(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a subscriber token to include in follow-up emails (preferences links)
|
||||
token, _ := utils.GenerateSubscriberToken(subscription.Email, 60*24) // 1 day
|
||||
baseFE := strings.TrimSuffix(config.AppConfig.FrontendBaseURL, "/")
|
||||
setupURL := baseFE + "/newsletter/setup?token=" + url.QueryEscape(token)
|
||||
unsubscribeURL := baseFE + "/newsletter/preferences?token=" + url.QueryEscape(token)
|
||||
|
||||
// Auto-create fan user account if not exists
|
||||
var existingUser models.User
|
||||
if err := cc.DB.Where("LOWER(email) = LOWER(?)", subscription.Email).First(&existingUser).Error; err == gorm.ErrRecordNotFound {
|
||||
// Generate a strong random password (16 chars, mixed set)
|
||||
genPassword := func(n int) string {
|
||||
const letters = "abcdefghijklmnopqrstuvwxyz"
|
||||
const upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const digits = "0123456789"
|
||||
const symbols = "!@#$%^&*()-_=+[]{}?"
|
||||
pool := letters + upper + digits + symbols
|
||||
b := make([]byte, n)
|
||||
for i := 0; i < n; i++ {
|
||||
var rb [1]byte
|
||||
if _, err := rand.Read(rb[:]); err != nil {
|
||||
b[i] = pool[(time.Now().UnixNano()+int64(i))%int64(len(pool))]
|
||||
continue
|
||||
}
|
||||
b[i] = pool[int(rb[0])%len(pool)]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
plain := genPassword(16)
|
||||
hashed, hErr := utils.HashPassword(plain)
|
||||
if hErr == nil {
|
||||
u := models.User{
|
||||
Email: strings.TrimSpace(strings.ToLower(subscription.Email)),
|
||||
Password: hashed,
|
||||
FirstName: "",
|
||||
LastName: "",
|
||||
Role: "fan",
|
||||
IsActive: true,
|
||||
}
|
||||
if err := cc.DB.Create(&u).Error; err != nil {
|
||||
logger.Error("Failed to auto-create fan user for newsletter: %v", err)
|
||||
} else {
|
||||
// Send credentials email
|
||||
data := map[string]interface{}{
|
||||
"Email": subscription.Email,
|
||||
"Password": plain,
|
||||
"LoginURL": baseFE + "/login",
|
||||
"ResetURL": baseFE + "/forgot-password",
|
||||
"ManageURL": setupURL,
|
||||
"UnsubscribeURL": unsubscribeURL,
|
||||
}
|
||||
credEmail := &email.EmailData{
|
||||
Subject: "Váš fan účet byl vytvořen",
|
||||
To: []string{subscription.Email},
|
||||
Template: "fan_account_created",
|
||||
Data: data,
|
||||
}
|
||||
if err := cc.emailService.SendEmail(credEmail); err != nil {
|
||||
logger.Error("Failed to send fan account created email: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send setup email (link with token) AND welcome introduction email in goroutines
|
||||
go func() {
|
||||
// Generate token and build setup + unsubscribe URLs
|
||||
token, tErr := utils.GenerateSubscriberToken(subscription.Email, 60*24) // 1 day
|
||||
if tErr != nil {
|
||||
logger.Error("Failed to generate subscriber token: %v", tErr)
|
||||
return
|
||||
}
|
||||
baseFE := strings.TrimSuffix(config.AppConfig.FrontendBaseURL, "/")
|
||||
setupURL := baseFE + "/newsletter/setup?token=" + url.QueryEscape(token)
|
||||
unsubscribeURL := baseFE + "/newsletter/preferences?token=" + url.QueryEscape(token)
|
||||
|
||||
// 1) Setup email
|
||||
setupEmail := &email.EmailData{
|
||||
Subject: "Nastavte svůj newsletter",
|
||||
|
||||
Reference in New Issue
Block a user