140 lines
4.5 KiB
Go
140 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"shop/internal/auth"
|
|
"shop/internal/config"
|
|
"shop/internal/database"
|
|
"shop/internal/handlers"
|
|
"shop/internal/middleware"
|
|
"shop/internal/repository"
|
|
"shop/internal/upload"
|
|
"shop/internal/version"
|
|
)
|
|
|
|
func main() {
|
|
ctx := context.Background()
|
|
cfg := config.Load()
|
|
|
|
pool, err := database.Connect(ctx)
|
|
if err != nil {
|
|
log.Fatalf("database: %v", err)
|
|
}
|
|
defer pool.Close()
|
|
|
|
if err := database.Migrate(ctx, pool); err != nil {
|
|
log.Fatalf("migrate: %v", err)
|
|
}
|
|
|
|
productRepo := repository.NewProductRepository(pool)
|
|
categoryRepo := repository.NewCategoryRepository(pool)
|
|
adminRepo := repository.NewAdminRepository(pool)
|
|
statsRepo := repository.NewStatsRepository(pool)
|
|
userRepo := repository.NewUserRepository(pool)
|
|
cartRepo := repository.NewCartRepository(pool)
|
|
orderRepo := repository.NewOrderRepository(pool)
|
|
|
|
storage, err := upload.NewStorage(cfg.UploadDir)
|
|
if err != nil {
|
|
log.Fatalf("upload storage: %v", err)
|
|
}
|
|
|
|
if cfg.AdminEmail != "" && cfg.AdminPassword != "" {
|
|
if err := adminRepo.Upsert(ctx, cfg.AdminEmail, cfg.AdminPassword); err != nil {
|
|
log.Fatalf("admin seed: %v", err)
|
|
}
|
|
log.Printf("admin ready: %s", cfg.AdminEmail)
|
|
}
|
|
|
|
tmpl, err := handlers.ParseTemplates()
|
|
if err != nil {
|
|
log.Fatalf("templates: %v", err)
|
|
}
|
|
|
|
adminSession := auth.NewSession(cfg.SessionSecret, "shop_admin_session", "/admin")
|
|
userSession := auth.NewSession(cfg.SessionSecret, "shop_user_session", "/")
|
|
cartSession := auth.NewSession(cfg.SessionSecret, "shop_cart_key", "/")
|
|
|
|
customer := handlers.NewCustomerHandler(
|
|
productRepo, categoryRepo, userRepo, cartRepo, orderRepo, statsRepo,
|
|
userSession, cartSession, tmpl,
|
|
)
|
|
admin := handlers.NewAdminHandler(adminRepo, productRepo, categoryRepo, orderRepo, statsRepo, storage, adminSession, tmpl)
|
|
|
|
mux := http.NewServeMux()
|
|
mux.Handle("GET /static/", http.StripPrefix("/static/", handlers.StaticHandler()))
|
|
mux.Handle("GET /uploads/", storage.FileServer())
|
|
mux.HandleFunc("GET /health", customer.Health)
|
|
|
|
mux.HandleFunc("GET /{$}", customer.Home)
|
|
mux.HandleFunc("GET /product/{id}", customer.ProductPage)
|
|
mux.HandleFunc("GET /category/{slug}", customer.CategoryPage)
|
|
mux.HandleFunc("GET /register", customer.RegisterPage)
|
|
mux.HandleFunc("POST /register", customer.Register)
|
|
mux.HandleFunc("GET /login", customer.LoginPage)
|
|
mux.HandleFunc("POST /login", customer.Login)
|
|
mux.HandleFunc("POST /logout", customer.Logout)
|
|
mux.HandleFunc("GET /cart", customer.CartPage)
|
|
mux.HandleFunc("POST /cart/add", customer.CartAdd)
|
|
mux.HandleFunc("POST /cart/update", customer.CartUpdate)
|
|
mux.HandleFunc("POST /cart/remove", customer.CartRemove)
|
|
mux.HandleFunc("GET /checkout", customer.CheckoutPage)
|
|
mux.HandleFunc("POST /checkout", customer.Checkout)
|
|
mux.HandleFunc("GET /account", customer.Account)
|
|
mux.HandleFunc("POST /account", customer.Account)
|
|
|
|
mux.HandleFunc("GET /admin/login", admin.LoginPage)
|
|
mux.HandleFunc("POST /admin/login", admin.Login)
|
|
mux.HandleFunc("POST /admin/logout", admin.Logout)
|
|
mux.HandleFunc("GET /admin/{$}", admin.Dashboard)
|
|
mux.HandleFunc("GET /admin/products", admin.ProductList)
|
|
mux.HandleFunc("GET /admin/products/new", admin.ProductNew)
|
|
mux.HandleFunc("POST /admin/products/save", admin.ProductSave)
|
|
mux.HandleFunc("GET /admin/products/{id}/edit", admin.ProductEdit)
|
|
mux.HandleFunc("POST /admin/products/{id}/delete", admin.ProductDelete)
|
|
mux.HandleFunc("POST /admin/products/{id}/images/{imageId}/delete", admin.ImageDelete)
|
|
mux.HandleFunc("GET /admin/categories", admin.CategoryList)
|
|
mux.HandleFunc("POST /admin/categories", admin.CategoryCreate)
|
|
mux.HandleFunc("POST /admin/categories/{id}/delete", admin.CategoryDelete)
|
|
mux.HandleFunc("GET /admin/orders", admin.OrderList)
|
|
mux.HandleFunc("POST /admin/orders/{id}/status", admin.OrderUpdateStatus)
|
|
|
|
addr := ":" + getEnv("APP_PORT", "8080")
|
|
srv := &http.Server{
|
|
Addr: addr,
|
|
Handler: middleware.TrustProxy(mux),
|
|
ReadTimeout: 15 * time.Second,
|
|
WriteTimeout: 60 * time.Second,
|
|
IdleTimeout: 60 * time.Second,
|
|
}
|
|
|
|
go func() {
|
|
log.Printf("Shop %s listening on %s", version.Version, addr)
|
|
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Fatalf("listen: %v", err)
|
|
}
|
|
}()
|
|
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
<-quit
|
|
|
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
_ = srv.Shutdown(shutdownCtx)
|
|
}
|
|
|
|
func getEnv(key, fallback string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|