package main
import (
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"
"strconv"
"sync"
)
type Product struct {
ID int `json:"id"`
Name string `json:"name"`
Price float64 `json:"price"`
}
var (
products []Product
mu sync.Mutex // Для безопасного доступа к списку продуктов
nextID int = 1 // Для автоматической генерации ID
)
// Структура для передачи данных в шаблон
type PageData struct {
Products []Product
Cart []CartItem
}
type CartItem struct {
ProductID int `json:"product_id"`
UserID int `json:"user_id"`
Quantity int `json:"quantity"`
CreatedID int `json:"created_id"`
}
// Получение корзины из cookies
func GetCartFromCookie(r *http.Request) ([]CartItem, error) {
// Read the cookie
cookie, err := r.Cookie("cart")
if err != nil {
if err == http.ErrNoCookie {
// If no cookie, return an empty cart
return []CartItem{}, nil
}
return nil, fmt.Errorf("failed to read cart cookie: %w", err)
}
// Check if the cookie value looks like JSON
var cart []CartItem
err = json.Unmarshal([]byte(cookie.Value), &cart)
if err != nil {
log.Println("Invalid cart cookie value, resetting cart.")
return []CartItem{}, nil // Reset to an empty cart on error
}
return cart, nil
}
// Сохранение корзины в cookies
func SetCartCookie(w http.ResponseWriter, cart []CartItem) error {
cartJSON, err := json.Marshal(cart)
if err != nil {
return fmt.Errorf("failed to serialize cart: %w", err)
}
// Устанавливаем cookie с корзиной
http.SetCookie(w, &http.Cookie{
Name: "cart",
Value: string(cartJSON),
Path: "/",
})
return nil
}
func renderTemplate(w http.ResponseWriter, r *http.Request, cart []CartItem) {
tmpl, err := template.New("index").Parse(`
Products
Products
| Product ID |
Name |
Price |
Action |
{{range .Products}}
| {{.ID}} |
{{.Name}} |
{{.Price}} |
Edit |
Delete
|
{{end}}
Add a New Product
Cart
| Product ID |
Quantity |
{{range .Cart}}
| {{.ProductID}} |
{{.Quantity}} |
{{end}}
`)
if err != nil {
log.Println("Error parsing template:", err)
http.Error(w, "Error parsing template", http.StatusInternalServerError)
return
}
// Передаем данные продукта и корзины в шаблон
data := PageData{
Products: products,
Cart: cart,
}
err = tmpl.Execute(w, data)
if err != nil {
log.Println("Error executing template:", err)
http.Error(w, "Error executing template", http.StatusInternalServerError)
return
}
}
func AddProduct(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
// Получаем данные из формы
name := r.FormValue("name")
price := r.FormValue("price")
// Преобразуем цену в float
var priceFloat float64
_, err := fmt.Sscanf(price, "%f", &priceFloat)
if err != nil {
http.Error(w, "Invalid price", http.StatusBadRequest)
return
}
// Создаем новый продукт
mu.Lock()
product := Product{
ID: nextID,
Name: name,
Price: priceFloat,
}
nextID++
products = append(products, product)
mu.Unlock()
// Перенаправляем пользователя на главную страницу после добавления продукта
http.Redirect(w, r, "/", http.StatusFound)
return
}
// Получаем корзину из cookies
cart, err := GetCartFromCookie(r)
if err != nil {
http.Error(w, fmt.Sprintf("Error reading cart: %v", err), http.StatusInternalServerError)
return
}
// Отображаем шаблон с обновленным списком продуктов и корзиной
renderTemplate(w, r, cart)
}
func EditProduct(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Path[len("/edit/"):]
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, "Invalid product ID", http.StatusBadRequest)
return
}
// Ищем продукт по ID
var product *Product
for i := range products {
if products[i].ID == id {
product = &products[i]
break
}
}
if product == nil {
http.Error(w, "Product not found", http.StatusNotFound)
return
}
if r.Method == http.MethodPost {
// Обновляем детали продукта
product.Name = r.FormValue("name")
price := r.FormValue("price")
var priceFloat float64
_, err := fmt.Sscanf(price, "%f", &priceFloat)
if err != nil {
http.Error(w, "Invalid price", http.StatusBadRequest)
return
}
product.Price = priceFloat
// Перенаправляем на главную страницу
http.Redirect(w, r, "/", http.StatusFound)
return
}
// Получаем корзину из cookies
// cart, err := GetCartFromCookie(r)
// if err != nil {
// http.Error(w, fmt.Sprintf("Error reading cart: %v", err), http.StatusInternalServerError)
// return
// }
// Отображаем форму редактирования продукта
tmpl := `
Edit Product
`
tmplParsed, err := template.New("edit").Parse(tmpl)
if err != nil {
http.Error(w, "Error parsing template", http.StatusInternalServerError)
return
}
// Передаем данные продукта в шаблон
tmplParsed.Execute(w, product)
}
func DeleteProduct(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Path[len("/delete/"):]
id, err := strconv.Atoi(idStr)
if err != nil {
http.Error(w, "Invalid product ID", http.StatusBadRequest)
return
}
// Находим индекс продукта для удаления
mu.Lock()
defer mu.Unlock()
for i, product := range products {
if product.ID == id {
// Удаляем продукт из списка
products = append(products[:i], products[i+1:]...)
break
}
}
// Получаем корзину из cookies
cart, err := GetCartFromCookie(r)
if err != nil {
http.Error(w, fmt.Sprintf("Error reading cart: %v", err), http.StatusInternalServerError)
return
}
// Сохраняем обновленную корзину в cookies (если необходимо)
err = SetCartCookie(w, cart)
if err != nil {
http.Error(w, fmt.Sprintf("Error setting cart cookie: %v", err), http.StatusInternalServerError)
return
}
// Перенаправляем на главную страницу
http.Redirect(w, r, "/", http.StatusFound)
}
func main() {
// Обработчики маршрутов
http.HandleFunc("/add", AddProduct)
http.HandleFunc("/edit/", EditProduct)
http.HandleFunc("/delete/", DeleteProduct)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Получаем корзину из cookies
cart, err := GetCartFromCookie(r)
if err != nil {
http.Error(w, fmt.Sprintf("Error reading cart: %v", err), http.StatusInternalServerError)
return
}
// Отображаем шаблон с корзиной
renderTemplate(w, r, cart)
})
log.Println("Server is running on http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}