Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
154 changes: 0 additions & 154 deletions .github/workflows/test-oauth.yml

This file was deleted.

58 changes: 58 additions & 0 deletions backend/routes/api.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,66 @@

from flask import Blueprint, jsonify, request
from flask_login import login_required, current_user

api_bp = Blueprint('api', __name__)

from datetime import datetime, timezone
bookings_db = [] # In-memory mock for bookings

# --- Booking Endpoints ---
@api_bp.route('/bookings/', methods=['POST'])
def create_booking():
data = request.get_json() or {}
required = ["station_id", "user_id", "start_time", "end_time"]
if not all(k in data for k in required):
return jsonify({"error": "Missing booking data"}), 400
try:
start = datetime.fromisoformat(data["start_time"].replace("Z", "+00:00"))
end = datetime.fromisoformat(data["end_time"].replace("Z", "+00:00"))
except Exception:
return jsonify({"error": "Invalid date format"}), 400
# Check for overlap
for b in bookings_db:
if b["station_id"] == data["station_id"] and not (end <= b["start_time"] or start >= b["end_time"]):
return jsonify({"error": "Booking time overlaps with existing booking"}), 409
booking_id = len(bookings_db) + 1
booking = {
"booking_id": booking_id,
"station_id": data["station_id"],
"user_id": data["user_id"],
"start_time": start,
"end_time": end,
"status": "confirmed"
}
bookings_db.append(booking)
return jsonify({"booking_id": booking_id, "status": "confirmed"}), 201

@api_bp.route('/stations/<int:station_id>/availability')
def station_availability(station_id):
date_str = request.args.get("date")
if not date_str:
return jsonify({"error": "Missing date parameter"}), 400
try:
date = datetime.fromisoformat(date_str)
except Exception:
return jsonify({"error": "Invalid date format"}), 400
# Mock: 8am-8pm, 1hr slots, remove slots with bookings
slots = [
(date.replace(hour=h, minute=0, second=0, microsecond=0, tzinfo=timezone.utc),
date.replace(hour=h+1, minute=0, second=0, microsecond=0, tzinfo=timezone.utc))
for h in range(8, 20)
]
available = []
for start, end in slots:
overlap = False
for b in bookings_db:
if b["station_id"] == station_id and not (end <= b["start_time"] or start >= b["end_time"]):
overlap = True
break
if not overlap:
available.append({"start": start.isoformat(), "end": end.isoformat()})
return jsonify({"available_slots": available})

@api_bp.route('/health')
def health_check():
"""Health check endpoint"""
Expand Down
53 changes: 53 additions & 0 deletions backend/tests/test_booking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import pytest

def test_create_booking(client):
"""Should create a booking for a station with valid data"""
booking_data = {
"station_id": 1,
"user_id": 1,
"start_time": "2025-08-10T10:00:00Z",
"end_time": "2025-08-10T12:00:00Z"
}
response = client.post('/api/bookings/', json=booking_data)
assert response.status_code == 201
data = response.get_json()
assert "booking_id" in data
assert data["status"] == "confirmed"

def test_booking_conflict(client):
"""Should return 409 if booking time overlaps with existing booking"""
# First booking
booking_data = {
"station_id": 1,
"user_id": 1,
"start_time": "2025-08-10T10:00:00Z",
"end_time": "2025-08-10T12:00:00Z"
}
client.post('/api/bookings/', json=booking_data)
# Overlapping booking
conflict_data = {
"station_id": 1,
"user_id": 2,
"start_time": "2025-08-10T11:00:00Z",
"end_time": "2025-08-10T13:00:00Z"
}
response = client.post('/api/bookings/', json=conflict_data)
assert response.status_code == 409
data = response.get_json()
assert "error" in data
assert "overlap" in data["error"].lower()

def test_booking_availability(client):
"""Should return available time slots for a station"""
response = client.get('/api/stations/1/availability?date=2025-08-10')
assert response.status_code == 200
data = response.get_json()
assert "available_slots" in data
assert isinstance(data["available_slots"], list)

def test_invalid_booking_data(client):
"""Should return 400 for invalid booking data"""
response = client.post('/api/bookings/', json={})
assert response.status_code == 400
data = response.get_json()
assert "error" in data
12 changes: 12 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,17 @@
"@testing-library/jest-dom": "^6.6.4",
"@testing-library/react": "^16.3.0",
"react-scripts": "^5.0.1"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
20 changes: 20 additions & 0 deletions start_all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash
# Launch both backend (Flask) and frontend (React) servers for ChargeBnB

# Start backend
cd backend
source venv/bin/activate
export FLASK_APP=run.py
export FLASK_ENV=development
flask run &
BACKEND_PID=$!
cd ..

# Start frontend
cd frontend
npm start &
FRONTEND_PID=$!
cd ..

# Wait for both to exit
wait $BACKEND_PID $FRONTEND_PID