Files
elysium/cmd/server/main.go
2025-01-03 21:34:48 +03:00

330 lines
8.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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))
}