chore: removed temp go files
This commit is contained in:
117
config.go
117
config.go
@@ -1,117 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
// Server
|
|
||||||
Port string
|
|
||||||
|
|
||||||
// Database
|
|
||||||
PGHost string
|
|
||||||
PGPort string
|
|
||||||
PGUser string
|
|
||||||
PGPassword string
|
|
||||||
PGDatabase string
|
|
||||||
|
|
||||||
// SMTP
|
|
||||||
SMTPServer string
|
|
||||||
SMTPPort int
|
|
||||||
SMTPUser string
|
|
||||||
SMTPPassword string
|
|
||||||
SenderEmail string
|
|
||||||
|
|
||||||
// Admin
|
|
||||||
AdminUsername string
|
|
||||||
AdminPassword string
|
|
||||||
|
|
||||||
// App
|
|
||||||
SecretKey string
|
|
||||||
BaseURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
var config *Config
|
|
||||||
|
|
||||||
func loadConfig() *Config {
|
|
||||||
// Load .env file
|
|
||||||
err := godotenv.Load()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Warning: Could not load .env file: %v", err)
|
|
||||||
} else {
|
|
||||||
log.Println("Successfully loaded .env file")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug: Print raw values before any processing
|
|
||||||
rawPassword := os.Getenv("PG_PASSWORD")
|
|
||||||
log.Printf("Raw PG_PASSWORD length: %d, value: [%s]", len(rawPassword), rawPassword)
|
|
||||||
log.Printf("Raw PG_USER: [%s]", os.Getenv("PG_USER"))
|
|
||||||
log.Printf("Raw PG_HOST: [%s]", os.Getenv("PG_HOST"))
|
|
||||||
|
|
||||||
cfg := &Config{
|
|
||||||
Port: getEnv("PORT", "5001"),
|
|
||||||
PGHost: getEnv("PG_HOST", "localhost"),
|
|
||||||
PGPort: getEnv("PG_PORT", "5432"),
|
|
||||||
PGUser: getEnv("PG_USER", "postgres"),
|
|
||||||
PGPassword: getEnv("PG_PASSWORD", ""),
|
|
||||||
PGDatabase: getEnv("PG_DATABASE", "newsletter"),
|
|
||||||
SMTPServer: getEnv("SMTP_SERVER", ""),
|
|
||||||
SMTPPort: getEnvInt("SMTP_PORT", 465),
|
|
||||||
SMTPUser: getEnv("SMTP_USER", ""),
|
|
||||||
SMTPPassword: getEnv("SMTP_PASSWORD", ""),
|
|
||||||
SenderEmail: getEnv("SENDER_EMAIL", ""),
|
|
||||||
AdminUsername: getEnv("ADMIN_USERNAME", "admin"),
|
|
||||||
AdminPassword: getEnv("ADMIN_PASSWORD", "changeme"),
|
|
||||||
SecretKey: getEnv("SECRET_KEY", "your-secret-key"),
|
|
||||||
BaseURL: getEnv("BASE_URL", "localhost:5001"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug output
|
|
||||||
log.Printf("=== Config Loaded ===")
|
|
||||||
log.Printf("PG_HOST: %s", cfg.PGHost)
|
|
||||||
log.Printf("PG_PORT: %s", cfg.PGPort)
|
|
||||||
log.Printf("PG_USER: %s", cfg.PGUser)
|
|
||||||
log.Printf("PG_DATABASE: %s", cfg.PGDatabase)
|
|
||||||
log.Printf("PG_PASSWORD length: %d", len(cfg.PGPassword))
|
|
||||||
log.Printf("BASE_URL: %s", cfg.BaseURL)
|
|
||||||
log.Printf("====================")
|
|
||||||
|
|
||||||
if cfg.SenderEmail == "" {
|
|
||||||
cfg.SenderEmail = cfg.SMTPUser
|
|
||||||
}
|
|
||||||
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEnv(key, defaultValue string) string {
|
|
||||||
value := os.Getenv(key)
|
|
||||||
if value == "" {
|
|
||||||
log.Printf("Env var %s not found, using default: %s", key, defaultValue)
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEnvInt(key string, defaultValue int) int {
|
|
||||||
value := os.Getenv(key)
|
|
||||||
if value == "" {
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
intVal, err := strconv.Atoi(value)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Invalid integer for %s: %v, using default", key, err)
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
return intVal
|
|
||||||
}
|
|
||||||
|
|
||||||
func maskPassword(pwd string) string {
|
|
||||||
if len(pwd) <= 2 {
|
|
||||||
return "***"
|
|
||||||
}
|
|
||||||
return pwd[:2] + "***" + pwd[len(pwd)-2:]
|
|
||||||
}
|
|
||||||
149
database.go
149
database.go
@@ -1,149 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
_ "github.com/lib/pq"
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
|
||||||
|
|
||||||
var db *sql.DB
|
|
||||||
|
|
||||||
type Admin struct {
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
func initDB() {
|
|
||||||
// Escape special characters in password
|
|
||||||
password := url.QueryEscape(config.PGPassword)
|
|
||||||
|
|
||||||
psqlInfo := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=require",
|
|
||||||
config.PGUser,
|
|
||||||
password,
|
|
||||||
config.PGHost,
|
|
||||||
config.PGPort,
|
|
||||||
config.PGDatabase,
|
|
||||||
)
|
|
||||||
|
|
||||||
log.Printf("Connecting to database: postgres://%s:***@%s:%s/%s",
|
|
||||||
config.PGUser, config.PGHost, config.PGPort, config.PGDatabase)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
db, err = sql.Open("postgres", psqlInfo)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Database connection error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
db.SetMaxOpenConns(25)
|
|
||||||
db.SetMaxIdleConns(5)
|
|
||||||
|
|
||||||
if err = db.Ping(); err != nil {
|
|
||||||
log.Fatalf("Failed to ping database: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("Database connection successful!")
|
|
||||||
createTables()
|
|
||||||
}
|
|
||||||
|
|
||||||
func createTables() {
|
|
||||||
queries := []string{
|
|
||||||
`CREATE TABLE IF NOT EXISTS subscribers (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
email TEXT UNIQUE NOT NULL
|
|
||||||
)`,
|
|
||||||
`CREATE TABLE IF NOT EXISTS admin_users (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
username TEXT UNIQUE NOT NULL,
|
|
||||||
password TEXT NOT NULL
|
|
||||||
)`,
|
|
||||||
`CREATE TABLE IF NOT EXISTS newsletters (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
subject TEXT NOT NULL,
|
|
||||||
body TEXT NOT NULL,
|
|
||||||
sent_at TIMESTAMP WITH TIME ZONE
|
|
||||||
DEFAULT CURRENT_TIMESTAMP
|
|
||||||
)`,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, query := range queries {
|
|
||||||
if _, err := db.Exec(query); err != nil {
|
|
||||||
log.Printf("Error creating table: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("Database tables ready.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAllEmails() ([]string, error) {
|
|
||||||
rows, err := db.Query("SELECT email FROM subscribers")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error retrieving emails: %v", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
var emails []string
|
|
||||||
for rows.Next() {
|
|
||||||
var email string
|
|
||||||
if err := rows.Scan(&email); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
emails = append(emails, email)
|
|
||||||
}
|
|
||||||
|
|
||||||
return emails, rows.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAdmin(username string) (*Admin, error) {
|
|
||||||
var admin Admin
|
|
||||||
err := db.QueryRow(
|
|
||||||
"SELECT username, password FROM admin_users WHERE username=$1",
|
|
||||||
username,
|
|
||||||
).Scan(&admin.Username, &admin.Password)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
return nil, fmt.Errorf("admin not found")
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &admin, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createDefaultAdmin() {
|
|
||||||
hashedPassword, err := hashPassword(config.AdminPassword)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error hashing password: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = db.Exec(
|
|
||||||
"INSERT INTO admin_users (username, password) "+
|
|
||||||
"VALUES ($1, $2) ON CONFLICT (username) DO NOTHING",
|
|
||||||
config.AdminUsername, hashedPassword,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error creating default admin: %v", err)
|
|
||||||
} else {
|
|
||||||
log.Println("Default admin user ready.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func hashPassword(password string) (string, error) {
|
|
||||||
hash, err := bcrypt.GenerateFromPassword(
|
|
||||||
[]byte(password),
|
|
||||||
bcrypt.DefaultCost,
|
|
||||||
)
|
|
||||||
return string(hash), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyPassword(hash, password string) bool {
|
|
||||||
return bcrypt.CompareHashAndPassword(
|
|
||||||
[]byte(hash),
|
|
||||||
[]byte(password),
|
|
||||||
) == nil
|
|
||||||
}
|
|
||||||
86
email.go
86
email.go
@@ -1,86 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/wneessen/go-mail"
|
|
||||||
)
|
|
||||||
|
|
||||||
func sendUpdateEmail(subject, body, recipient string) bool {
|
|
||||||
client, err := mail.NewClient(
|
|
||||||
config.SMTPServer,
|
|
||||||
mail.WithPort(config.SMTPPort),
|
|
||||||
mail.WithSMTPAuth(mail.SMTPAuthPlain),
|
|
||||||
mail.WithUsername(config.SMTPUser),
|
|
||||||
mail.WithPassword(config.SMTPPassword),
|
|
||||||
mail.WithTimeout(10*time.Second),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to create mail client: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
m := mail.NewMsg()
|
|
||||||
if err := m.From(config.SenderEmail); err != nil {
|
|
||||||
log.Printf("Failed to set from: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if err := m.To(recipient); err != nil {
|
|
||||||
log.Printf("Failed to set to: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
m.Subject(subject)
|
|
||||||
|
|
||||||
unsubLink := fmt.Sprintf(
|
|
||||||
"https://%s/unsubscribe?email=%s",
|
|
||||||
config.BaseURL,
|
|
||||||
recipient,
|
|
||||||
)
|
|
||||||
|
|
||||||
htmlBody := fmt.Sprintf(
|
|
||||||
"%s<br><br>If you ever wish to unsubscribe, "+
|
|
||||||
"please click <a href='%s'>here</a>",
|
|
||||||
body, unsubLink,
|
|
||||||
)
|
|
||||||
m.SetBodyString(mail.TypeTextHTML, htmlBody)
|
|
||||||
|
|
||||||
if err := client.Send(m); err != nil {
|
|
||||||
log.Printf("Failed to send email to %s: %v", recipient, err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Update email sent to: %s", recipient)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func processSendUpdateEmail(subject, body string) (string, error) {
|
|
||||||
subscribers, err := getAllEmails()
|
|
||||||
if err != nil {
|
|
||||||
return "Failed to retrieve subscribers", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(subscribers) == 0 {
|
|
||||||
return "No subscribers found.", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, email := range subscribers {
|
|
||||||
if !sendUpdateEmail(subject, body, email) {
|
|
||||||
return fmt.Sprintf("Failed to send to %s", email),
|
|
||||||
nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log newsletter
|
|
||||||
_, err = db.Exec(
|
|
||||||
"INSERT INTO newsletters (subject, body) VALUES ($1, $2)",
|
|
||||||
subject, body,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error logging newsletter: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Email has been sent to all subscribers.", nil
|
|
||||||
}
|
|
||||||
24
sessions.go
24
sessions.go
@@ -1,24 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/gorilla/sessions"
|
|
||||||
)
|
|
||||||
|
|
||||||
var store *sessions.CookieStore
|
|
||||||
|
|
||||||
func initSessions() {
|
|
||||||
if config.SecretKey == "" {
|
|
||||||
log.Fatal("SECRET_KEY not set in configuration")
|
|
||||||
}
|
|
||||||
store = sessions.NewCookieStore([]byte(config.SecretKey))
|
|
||||||
store.Options = &sessions.Options{
|
|
||||||
Path: "/",
|
|
||||||
MaxAge: 86400 * 7, // 7 days
|
|
||||||
HttpOnly: true,
|
|
||||||
Secure: false, // Set to true in production with HTTPS
|
|
||||||
SameSite: 0,
|
|
||||||
}
|
|
||||||
log.Println("Sessions initialized")
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user