1 Commits

Author SHA1 Message Date
Anton Kamalov
e5633c9f12 Database module 2025-01-03 19:28:07 +00:00
6 changed files with 112 additions and 330 deletions

2
.gitignore vendored
View File

@@ -1,2 +1,2 @@
config/dbconfig.yaml
.codegpt

View File

@@ -1,329 +0,0 @@
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))
}

12
config/INSTRUCTIONS.md Normal file
View File

@@ -0,0 +1,12 @@
# Example for dbconfig.yaml
```yaml
user: "user"
password: "password"
dbname: "test"
sslmode: "disable"
hostname: "localhost"
```
We use Postgres v. 16
You need to create own yaml file

85
database/database.go Normal file
View File

@@ -0,0 +1,85 @@
package database
import (
"fmt"
"log"
"os"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
yaml "gopkg.in/yaml.v2"
)
type Conf struct {
User string `yaml:"user"`
DBname string `yaml:"dbname"`
SSLMode string `yaml:"sslmode"`
Password string `yaml:"password"`
Host string `yaml:"hostname"`
}
func LoadConfig(path string) (*Conf, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
var config Conf
err = yaml.Unmarshal(data, &config)
if err != nil {
return nil, err
}
return &config, nil
}
func CheckError(err error) bool {
if err != nil {
log.Fatalln(err)
return false
}
return true
}
func Test_connection() {
config, err := LoadConfig("config/config.yaml")
if err != nil {
log.Fatalln("Failed to load config:", err)
}
dsn := fmt.Sprintf("user=%s dbname=%s sslmode=%s password=%s host=%s",
config.User, config.DBname, config.SSLMode, config.Password, config.Host)
db, err := sqlx.Connect("postgres", dsn)
if err != nil {
log.Fatalln(err)
}
defer db.Close()
// Test the connection to the database
if err := db.Ping(); err != nil {
log.Fatal(err)
} else {
log.Println("Successfully Connected")
}
}
func Insert_Data(query string) bool {
config, err := LoadConfig("config/config.yaml")
if err != nil {
log.Fatalln("Failed to load config:", err)
return false
}
dsn := fmt.Sprintf("user=%s dbname=%s sslmode=%s password=%s host=%s",
config.User, config.DBname, config.SSLMode, config.Password, config.Host)
db, err := sqlx.Open("postgres", dsn)
if !CheckError(err) {
return false
}
defer db.Close()
_, e := db.Exec(query)
return CheckError(e)
}

6
go.mod
View File

@@ -1,3 +1,9 @@
module market
go 1.18
require (
github.com/jmoiron/sqlx v1.4.0
github.com/lib/pq v1.10.9
gopkg.in/yaml.v2 v2.4.0
)

8
go.sum
View File

@@ -6,5 +6,13 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=