Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5746bc9
adding entries handlers and a docker file
Avnermond12344 Dec 4, 2025
c04b00d
adding mock database, SCHEME.rd and a dockerfile
Avnermond12344 Dec 9, 2025
b80975e
adapting the structure of equipment list
Avnermond12344 Dec 9, 2025
407e5d7
adding struct for users
Avnermond12344 Dec 26, 2025
a7bea4a
adding mock data for users & carts
Avnermond12344 Dec 26, 2025
2df1df3
adding login & shopping cart handlers
Avnermond12344 Dec 26, 2025
512ca78
fixing minor bug
Avnermond12344 Dec 26, 2025
abf34ea
Merge branch 'main' of https://github.com/Motzklist/Back-End
Avnermond12344 Dec 30, 2025
a89aee0
Merge branch 'main' of https://github.com/Motzklist/Back-End
Avnermond12344 Jan 7, 2026
e5ea087
adding API for the DB
Avnermond12344 Jan 7, 2026
470f6bf
adding getUsernameFromUserID function
Avnermond12344 Jan 7, 2026
d151079
slight modifications
Avnermond12344 Jan 7, 2026
1e0bb9a
removing timestamp
Avnermond12344 Jan 7, 2026
f2ae997
modifing main.go so it supports the new API file
Avnermond12344 Jan 7, 2026
ca6cc24
modulating the main file
Avnermond12344 Jan 7, 2026
077a932
Refactor DB methods to use actual database queries
roishm Jan 7, 2026
4398c62
Merge pull request #1 from roishm/patch-1
Avnermond12344 Jan 7, 2026
b805658
Merge branch 'main' of https://github.com/Avnermond12344/api-gateway-…
Avnermond12344 Jan 7, 2026
97bdccd
Adding a DB initialization
Avnermond12344 Jan 14, 2026
2de5701
updating the go.mod
Avnermond12344 Jan 14, 2026
65ee997
updating Dockefile
Avnermond12344 Jan 14, 2026
3a376ff
rebuilding the init function
Avnermond12344 Jan 14, 2026
3141955
adding a TODO
Avnermond12344 Jan 27, 2026
891d300
adding payment handlers, and env file and modifications to main.go
Avnermond12344 May 11, 2026
88e2c1c
adding 'Price' field to Equipment
Avnermond12344 May 12, 2026
5382a72
updating getCatItemsFromApply to price field
Avnermond12344 May 12, 2026
6b9379a
adding 'Price' field to the mock_db
Avnermond12344 May 13, 2026
04a2600
adding support for purchase history
Avnermond12344 May 20, 2026
cabe03d
Merge remote-tracking branch 'origin/feature/payment-history' into pa…
NoamBenShimon May 27, 2026
8e4bd49
Align with new DB schema and rebrand to motzklist-backend
NoamBenShimon May 28, 2026
ea66c09
Merge remote-tracking branch 'origin/feature/payment-history' into fe…
NoamBenShimon May 28, 2026
2d0401e
fix: update session cookie name to 'sessionid' for consistency
NoamBenShimon May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
.env
.idea/
.exe
*.exe
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Use the official Go image to compile the application
FROM golang:1.25-alpine AS builder
LABEL authors="avner"

# Set the working directory for building
WORKDIR /app
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
BINARY_NAME=motzklist-api-gateway
BINARY_NAME=motzklist-backend
BUILD_DIR=./build

# Default command: runs the server (using '.' to include all files in package)
Expand Down
124 changes: 112 additions & 12 deletions db_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package main

import (
"database/sql"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"strconv"
"time"
Expand Down Expand Up @@ -153,7 +155,7 @@ func getCartByUserID(userID string) []CartEntry {
var cart []CartEntry
queryEntry := `
SELECT ce.ceid, g.gid, g.gname, s.sid, s.sname
FROM cartEntry ce
FROM cart_entry ce
JOIN grade g ON ce.gid = g.gid
JOIN school s ON g.sid = s.sid
WHERE ce.uid = $1
Expand Down Expand Up @@ -186,10 +188,10 @@ func getCartItemsFromApply(ceidStr string) []Equipment {
ceid, _ := strconv.Atoi(ceidStr)

query := `
SELECT e.eid, e.ename, e.price, COUNT(a.eid) as qty
FROM apply a
JOIN equipment e ON a.eid = e.eid
WHERE a.ceid = $1
SELECT e.eid, e.ename, e.price, COUNT(ci.eid) as qty
FROM cart_item ci
JOIN equipment e ON ci.eid = e.eid
WHERE ci.ceid = $1
GROUP BY e.eid, e.ename, e.price
`
rows, err := DB.Query(query, ceid)
Expand Down Expand Up @@ -219,7 +221,7 @@ func saveCart(userID string, cart []CartEntry) error {
return fmt.Errorf("starting transaction: %w", err)
}

_, err = tx.Exec("DELETE FROM cartEntry WHERE uid = $1", uid)
_, err = tx.Exec("DELETE FROM cart_entry WHERE uid = $1", uid)
if err != nil {
tx.Rollback()
log.Println("Error clearing old cart:", err)
Expand All @@ -230,22 +232,22 @@ func saveCart(userID string, cart []CartEntry) error {
var newCeid int
gid, _ := strconv.Atoi(entry.Grade.ID)

err := tx.QueryRow("INSERT INTO cartEntry (gid, uid) VALUES ($1, $2) RETURNING ceid", gid, uid).Scan(&newCeid)
err := tx.QueryRow("INSERT INTO cart_entry (gid, uid) VALUES ($1, $2) RETURNING ceid", gid, uid).Scan(&newCeid)
if err != nil {
tx.Rollback()
log.Println("Error inserting cartEntry:", err)
return fmt.Errorf("inserting cartEntry: %w", err)
log.Println("Error inserting cart_entry:", err)
return fmt.Errorf("inserting cart_entry: %w", err)
}

for _, item := range entry.Items {
eid, _ := strconv.Atoi(item.ID)

for i := 0; i < item.Quantity; i++ {
_, err := tx.Exec("INSERT INTO apply (ceid, eid) VALUES ($1, $2)", newCeid, eid)
_, err := tx.Exec("INSERT INTO cart_item (ceid, eid) VALUES ($1, $2)", newCeid, eid)
if err != nil {
tx.Rollback()
log.Println("Error inserting to apply:", err)
return fmt.Errorf("inserting to apply: %w", err)
log.Println("Error inserting to cart_item:", err)
return fmt.Errorf("inserting to cart_item: %w", err)
}
}
}
Expand All @@ -257,3 +259,101 @@ func saveCart(userID string, cart []CartEntry) error {
}
return nil
}

// NEW - adding purchase history
func getUserOrderHistory(userID string) []Order {
log.Println("Got to getUserOrderHistory function")
uid, _ := strconv.Atoi(userID)
var orders []Order

queryOrders := `
SELECT oid, gid, purchase_date, total_amount
FROM orders
WHERE uid = $1
ORDER BY purchase_date DESC;
`
rows, err := DB.Query(queryOrders, uid)
if err != nil {
log.Println("Error getting orders history:", err)
return []Order{}
}
defer rows.Close()

for rows.Next() {
var o Order
var t time.Time

if err := rows.Scan(&o.ID, &o.GradeID, &t, &o.TotalAmount); err != nil {
log.Println("Error scanning order row:", err)
continue
}

o.PurchaseDate = t.Format("2006-01-02 15:04:05")

o.Items = getOrderItems(o.ID)

orders = append(orders, o)
}

return orders
}

func getOrderItems(orderID string) []OrderItem {
oid, _ := strconv.Atoi(orderID)
var items []OrderItem

queryItems := `
SELECT
e.ename,
oi.quantity,
oi.price_at_purchase,
(oi.quantity * oi.price_at_purchase) as total_item_cost
FROM order_item oi
JOIN equipment e ON oi.eid = e.eid
WHERE oi.oid = $1;
`
rows, err := DB.Query(queryItems, oid)
if err != nil {
log.Println("Error getting order items:", err)
return []OrderItem{}
}
defer rows.Close()

for rows.Next() {
var item OrderItem

if err := rows.Scan(&item.EquipmentName, &item.Quantity, &item.Price, &item.TotalPrice); err != nil {
log.Println("Error scanning order item row:", err)
continue
}
items = append(items, item)
}

return items
}

func getOrderHistoryHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
JSONError(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

cookie, err := r.Cookie("sessionid")
if err != nil {
JSONError(w, "Unauthorized", http.StatusUnauthorized)
return
}

userID, exists := sessions[cookie.Value]
if !exists {
JSONError(w, "Unauthorized", http.StatusUnauthorized)
return
}

history := getUserOrderHistory(userID)

w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(history); err != nil {
log.Printf("Failed to encode history response: %v", err)
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module api-gateway-avner
module motzklist-backend

go 1.25.4

Expand Down
21 changes: 18 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,28 @@ func JSONError(w http.ResponseWriter, err string, code int) {
}
}

// =====NEW=====
// login
type User struct {
UserID string `json:"userid"`
Username string `json:"username"`
Password string `json:"password"`
}

// NEW - adding purchase history
type OrderItem struct {
EquipmentName string `json:"equipment_name"`
Quantity int `json:"quantity"`
Price float64 `json:"price"`
TotalPrice float64 `json:"total_price"`
}

type Order struct {
ID string `json:"order_id"`
GradeID string `json:"grade_id"`
PurchaseDate string `json:"purchase_date"`
TotalAmount float64 `json:"total_amount"`
Items []OrderItem `json:"items"`
}

func enableCORS(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
Expand Down Expand Up @@ -108,6 +122,7 @@ func main() {
http.HandleFunc("/api/logout", enableCORS(logoutHandler))
http.HandleFunc("/api/cart", enableCORS(getPostCartHandler))
http.HandleFunc("/api/create-checkout-session", enableCORS(CreateCheckoutSession))
http.HandleFunc("/api/history", enableCORS(getOrderHistoryHandler))

// Start the API Gateway server
port := "8080" // Changed port to string without colon for easier fmt use
Expand All @@ -122,4 +137,4 @@ func main() {

// Use the formatted address to listen
log.Fatal(http.ListenAndServe(serverAddr, nil))
}
}
25 changes: 11 additions & 14 deletions mock_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,21 +84,19 @@ var MockUsers = []User{
// CartEntry structure for frontend compatibility
// (matches what the frontend expects)
type CartEntry struct {
ID string `json:"id"`
Timestamp int64 `json:"timestamp"`
School School `json:"school"`
Grade Grade `json:"grade"`
Items []Equipment `json:"items"`
ID string `json:"id"`
School School `json:"school"`
Grade Grade `json:"grade"`
Items []Equipment `json:"items"`
}

// data for cart
var MockCarts = map[string][]CartEntry{
"1": {
{
ID: "cart-1",
Timestamp: 1700000000,
School: School{ID: "1", Name: "Ben Gurion"},
Grade: Grade{ID: "9", Name: "9th Grade"},
ID: "cart-1",
School: School{ID: "1", Name: "Ben Gurion"},
Grade: Grade{ID: "9", Name: "9th Grade"},
Items: []Equipment{
{ID: "101", Name: "Notebook", Quantity: 2},
{ID: "102", Name: "Engineering Calculator", Quantity: 1},
Expand All @@ -108,15 +106,14 @@ var MockCarts = map[string][]CartEntry{
},
"2": {
{
ID: "cart-2",
Timestamp: 1700000001,
School: School{ID: "2", Name: "ORT"},
Grade: Grade{ID: "12", Name: "12th Grade"},
ID: "cart-2",
School: School{ID: "2", Name: "ORT"},
Grade: Grade{ID: "12", Name: "12th Grade"},
Items: []Equipment{
{ID: "201", Name: "Laptop (Required)", Quantity: 1},
{ID: "202", Name: "Engineering Calculator", Quantity: 1},
{ID: "203", Name: "Physics Textbook - Beginners", Quantity: 1},
},
},
},
}
}
Loading