This commit is contained in:
User
2025-01-03 21:26:43 +03:00
parent 55afc6215f
commit 387fcae36b
34 changed files with 23138 additions and 2 deletions

329
main.go Normal file
View File

@@ -0,0 +1,329 @@
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(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Products</title>
<style>
body { font-family: Arial, sans-serif; }
table { width: 50%; border-collapse: collapse; margin: 20px 0; }
th, td { padding: 8px 12px; text-align: left; border: 1px solid #ddd; }
h1 { text-align: center; }
</style>
</head>
<body>
<h1>Products</h1>
<table>
<tr>
<th>Product ID</th>
<th>Name</th>
<th>Price</th>
<th>Action</th>
</tr>
{{range .Products}}
<tr>
<td>{{.ID}}</td>
<td>{{.Name}}</td>
<td>{{.Price}}</td>
<td>
<a href="/edit/{{.ID}}">Edit</a> |
<a href="/delete/{{.ID}}">Delete</a>
</td>
</tr>
{{end}}
</table>
<h2>Add a New Product</h2>
<form action="/add" method="POST">
<label for="name">Product Name:</label>
<input type="text" name="name" required><br><br>
<label for="price">Price:</label>
<input type="number" step="0.01" name="price" required><br><br>
<button type="submit">Add Product</button>
</form>
<h2>Cart</h2>
<table>
<tr>
<th>Product ID</th>
<th>Quantity</th>
</tr>
{{range .Cart}}
<tr>
<td>{{.ProductID}}</td>
<td>{{.Quantity}}</td>
</tr>
{{end}}
</table>
</body>
</html>
`)
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 := `<html><body>
<h1>Edit Product</h1>
<form action="/edit/{{.ID}}" method="POST">
<label for="name">Product Name:</label>
<input type="text" name="name" value="{{.Name}}" required><br><br>
<label for="price">Price:</label>
<input type="text" name="price" value="{{.Price}}" required><br><br>
<button type="submit">Save Changes</button>
</form>
</body></html>`
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))
}