package handlers import ( "html/template" "log" "net/http" "strconv" "shop/internal/auth" "shop/internal/models" "shop/internal/repository" "shop/internal/upload" ) type AdminHandler struct { repo *repository.AdminRepository products *repository.ProductRepository stats *repository.StatsRepository storage *upload.Storage session *auth.Session templates *template.Template } type adminLayoutData struct { Title string Email string Active string Content template.HTML } type adminLoginData struct { Title string Error string Email string } type adminDashboardData struct { Title string Email string ProductCount int CategoryCount int TotalVisits int64 TodayVisits int Categories []models.Category Products []models.Product } type adminProductsData struct { Title string Email string Products []models.Product } type adminProductFormData struct { Title string Email string Product models.Product IsNew bool Error string } func NewAdminHandler( adminRepo *repository.AdminRepository, productRepo *repository.ProductRepository, statsRepo *repository.StatsRepository, storage *upload.Storage, session *auth.Session, templates *template.Template, ) *AdminHandler { return &AdminHandler{ repo: adminRepo, products: productRepo, stats: statsRepo, storage: storage, session: session, templates: templates, } } func (h *AdminHandler) requireAuth(w http.ResponseWriter, r *http.Request) (string, bool) { email, ok := h.session.FromRequest(r) if !ok { http.Redirect(w, r, "/admin/login", http.StatusSeeOther) return "", false } return email, true } func (h *AdminHandler) render(w http.ResponseWriter, name string, data any) { w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := h.templates.ExecuteTemplate(w, name, data); err != nil { log.Printf("render %s: %v", name, err) } } func (h *AdminHandler) LoginPage(w http.ResponseWriter, r *http.Request) { if email, ok := h.session.FromRequest(r); ok && email != "" { http.Redirect(w, r, "/admin/", http.StatusSeeOther) return } h.render(w, "admin_login.html", adminLoginData{Title: "Вход в админку"}) } func (h *AdminHandler) Login(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { http.Error(w, "Bad Request", http.StatusBadRequest) return } email := r.FormValue("email") password := r.FormValue("password") ok, err := h.repo.Authenticate(r.Context(), email, password) if err != nil { log.Printf("admin auth: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } if !ok { h.renderLoginError(w, email, "Неверный email или пароль") return } token, err := h.session.Create(email) if err != nil { log.Printf("session: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } h.session.SetCookie(w, r, token) http.Redirect(w, r, "/admin/", http.StatusSeeOther) } func (h *AdminHandler) Logout(w http.ResponseWriter, r *http.Request) { h.session.ClearCookie(w, r) http.Redirect(w, r, "/admin/login", http.StatusSeeOther) } func (h *AdminHandler) Dashboard(w http.ResponseWriter, r *http.Request) { email, ok := h.requireAuth(w, r) if !ok { return } ctx := r.Context() products, err := h.products.All(ctx) if err != nil { log.Printf("admin products: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } categories, err := h.products.Categories(ctx) if err != nil { log.Printf("admin categories: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } stats, err := h.stats.Get(ctx) if err != nil { log.Printf("admin stats: %v", err) } h.render(w, "admin_dashboard.html", adminDashboardData{ Title: "Админ-панель", Email: email, ProductCount: len(products), CategoryCount: len(categories), TotalVisits: stats.TotalVisits, TodayVisits: stats.TodayVisits, Categories: categories, Products: products, }) } func (h *AdminHandler) renderLoginError(w http.ResponseWriter, email, msg string) { data := adminLoginData{Title: "Вход в админку", Error: msg, Email: email} w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(http.StatusUnauthorized) _ = h.templates.ExecuteTemplate(w, "admin_login.html", data) } func parseProductID(r *http.Request) (int, error) { return strconv.Atoi(r.PathValue("id")) }