Skip to content
Snippets Groups Projects

changes for the cloud deployment

parent 5392a578
No related branches found
No related tags found
No related merge requests found
Showing
with 205 additions and 104 deletions
DB_HOST=database-1.cz0ucmk42cu5.us-east-1.rds.amazonaws.com
DB_PORT=3306
DB_USER=admin
DB_PASSWORD=Test#321
DB_DATABASE=cycle_connect
\ No newline at end of file
DB_PASSWORD='Test#321'
DB_DATABASE=cycle_connect
FRONT_END_PORT=8000
ADMINS_SERVICE_PORT=8001
BIKES_SERVICE_PORT=8002
RENTALS_SERVICE_PORT=8003
REVIEWS_SERVICE_PORT=8004
USERS_SERVICE_PORT=8005
BOOKING_SERVICE_PORT=8006
\ No newline at end of file
DB_HOST=database-1.cz0ucmk42cu5.us-east-1.rds.amazonaws.com
DB_PORT=3306
DB_USER=admin
DB_PASSWORD='Test#321'
DB_DATABASE=cycle_connect
FRONT_END_PORT=8000
ADMINS_SERVICE_PORT=8001
BIKES_SERVICE_PORT=8002
RENTALS_SERVICE_PORT=8003
REVIEWS_SERVICE_PORT=8004
USERS_SERVICE_PORT=8005
BOOKING_SERVICE_PORT=8006
\ No newline at end of file
annotated-types==0.6.0
anyio==4.3.0
APScheduler==3.10.4
certifi==2024.2.2
click==8.1.7
dnspython==2.6.1
......@@ -23,14 +24,16 @@ pydantic-settings==2.2.1
pydantic_core==2.16.3
python-dotenv==1.0.1
python-multipart==0.0.9
pytz==2024.1
PyYAML==6.0.1
six==1.16.0
sniffio==1.3.1
SQLAlchemy==2.0.29
starlette==0.36.3
typing_extensions==4.10.0
tzlocal==5.2
ujson==5.9.0
uvicorn==0.29.0
uvloop==0.19.0
watchfiles==0.21.0
websockets==12.0
DB_HOST=database-1.cz0ucmk42cu5.us-east-1.rds.amazonaws.com
DB_PORT=3306
DB_USER=admin
DB_PASSWORD='Test#321'
DB_DATABASE=cycle_connect
FRONT_END_PORT=8000
ADMINS_SERVICE_PORT=8001
BIKES_SERVICE_PORT=8002
RENTALS_SERVICE_PORT=8003
REVIEWS_SERVICE_PORT=8004
USERS_SERVICE_PORT=8005
BOOKING_SERVICE_PORT=8006
\ No newline at end of file
annotated-types==0.6.0
anyio==4.3.0
APScheduler==3.10.4
certifi==2024.2.2
click==8.1.7
dnspython==2.6.1
......@@ -23,13 +24,16 @@ pydantic-settings==2.2.1
pydantic_core==2.16.3
python-dotenv==1.0.1
python-multipart==0.0.9
pytz==2024.1
PyYAML==6.0.1
six==1.16.0
sniffio==1.3.1
SQLAlchemy==2.0.29
starlette==0.36.3
typing_extensions==4.10.0
tzlocal==5.2
ujson==5.9.0
uvicorn==0.29.0
uvloop==0.19.0
watchfiles==0.21.0
websockets==12.0
\ No newline at end of file
websockets==12.0
DB_HOST=database-1.cz0ucmk42cu5.us-east-1.rds.amazonaws.com
DB_PORT=3306
DB_USER=admin
DB_PASSWORD='Test#321'
DB_DATABASE=cycle_connect
FRONT_END_PORT=8000
ADMINS_SERVICE_PORT=8001
BIKES_SERVICE_PORT=8002
RENTALS_SERVICE_PORT=8003
REVIEWS_SERVICE_PORT=8004
USERS_SERVICE_PORT=8005
BOOKING_SERVICE_PORT=8006
\ No newline at end of file
......@@ -107,133 +107,108 @@ async def get_booking(booking_id: int):
@app.post("/bookings/")
async def book_bike(booking: Booking):
# Check for existing active booking for the user_id or bike_id
# Check for existing active booking for the same user or bike
cursor.execute("""
SELECT 1 FROM Bookings
WHERE (user_id = %s OR bike_id = %s) AND payment_state = 'Booked'
""", (booking.user_id, booking.bike_id))
existing_booking = cursor.fetchone()
if existing_booking:
raise HTTPException(status_code=400, detail="Already Booked")
# Fetch user details
# Fetch user details to check wallet balance
cursor.execute("SELECT wallet_balance FROM Users WHERE user_id = %s", (booking.user_id,))
user_details = cursor.fetchone()
if not user_details:
raise HTTPException(status_code=404, detail="User not found.")
wallet_balance = user_details[0]
# Fetch bike details and validate the location
raise HTTPException(status_code=404, detail="User not found")
wallet_balance = Decimal(user_details[0])
# Fetch bike details to check availability and get price per hour
cursor.execute("SELECT current_location, price_per_hour FROM Bikes WHERE bike_id = %s", (booking.bike_id,))
bike_details = cursor.fetchone()
if not bike_details:
raise HTTPException(status_code=404, detail="Bike not found.")
db_location, price_per_hour = bike_details
if booking.current_location != db_location:
raise HTTPException(status_code=400, detail="Bike not available at the specified location.")
# Calculate the amount to be blocked on the user's wallet
blocked_amount = price_per_hour * 5
# Validate wallet balance
if not bike_details or booking.location != bike_details[0]:
raise HTTPException(status_code=404, detail="Bike not available at the specified location")
price_per_hour = Decimal(bike_details[1])
# Calculate blocked amount based on the booking duration
blocked_amount = price_per_hour * Decimal(booking.duration_hours)
# Ensure user's wallet balance can cover the blocked amount
if wallet_balance < blocked_amount:
raise HTTPException(status_code=400, detail="Insufficient wallet balance.")
# Calculate new wallet balance
raise HTTPException(status_code=400, detail="Insufficient wallet balance")
# Deduct the blocked amount from user's wallet balance
new_wallet_balance = wallet_balance - blocked_amount
# Generate lock code and current time
lock_code = generate_lock_code()
# Insert the booking record
lock_code = ''.join(random.choices('0123456789', k=6)) # Generate a 6-digit lock code
start_time = datetime.now()
# Update bike status and user's wallet balance
cursor.execute("UPDATE Bikes SET status = 'booked' WHERE bike_id = %s", (booking.bike_id,))
cursor.execute("UPDATE Users SET wallet_balance = %s WHERE user_id = %s", (new_wallet_balance, booking.user_id))
# Insert a new booking record with lock code
cursor.execute("""
INSERT INTO Bookings (user_id, bike_id, location, blocked_amount, payment_state, start_time, lock_code)
VALUES (%s, %s, %s, %s, 'Booked', %s, %s)
""", (booking.user_id, booking.bike_id, booking.location, blocked_amount, start_time, lock_code))
# Update the user's wallet balance
cursor.execute("UPDATE Users SET wallet_balance = %s WHERE user_id = %s", (new_wallet_balance, booking.user_id))
db_connection.commit()
return {
"user_id": booking.user_id,
"bike_id": booking.bike_id,
"location": booking.location,
"blocked_amount": blocked_amount,
"new_wallet_balance": new_wallet_balance,
"message": "Bike booked successfully",
"new_wallet_balance": float(new_wallet_balance), # Return as float for JSON serialization
"lock_code": lock_code,
"start_time": start_time.strftime('%Y-%m-%d %H:%M:%S'),
"message": "Bike booked successfully"
"start_time": start_time.isoformat()
}
@app.put("/bookings/")
async def update_booking(update: UpdateBooking):
# Establish a database connection
db_connection = mysql.connector.connect(
host='database-1.cz0ucmk42cu5.us-east-1.rds.amazonaws.com',
port='3306',
user='admin',
password='Test#321',
database='cycle_connect'
)
cursor = db_connection.cursor()
# Check if the booking with provided booking_id, user_id, and bike_id exists
cursor.execute("""
SELECT
SELECT
B.start_time, B.blocked_amount, Bi.price_per_hour, U.wallet_balance
FROM
FROM
Bookings B
JOIN Bikes Bi ON B.bike_id = Bi.bike_id
JOIN Users U ON B.user_id = U.user_id
WHERE
WHERE
B.booking_id = %s AND B.user_id = %s AND B.bike_id = %s
""", (update.booking_id, update.user_id, update.bike_id))
booking = cursor.fetchone()
if not booking:
raise HTTPException(status_code=404, detail="No matching booking found.")
raise HTTPException(status_code=404, detail="Booking not found")
# Unpack fetched details
start_time, blocked_amount, price_per_hour, current_wallet_balance = booking
# Handle start_time type appropriately
if not isinstance(start_time, datetime):
start_time = datetime.fromisoformat(start_time)
# Calculate total runtime in hours
start_time, blocked_amount, price_per_hour, wallet_balance = booking
start_time = datetime.fromisoformat(start_time) if isinstance(start_time, str) else start_time
# Calculate the duration in hours and the final price
end_time = datetime.now()
total_runtime = (end_time - start_time).total_seconds() / 3600
# Determine final price based on total runtime
if total_runtime <= 5:
final_price = blocked_amount - (total_runtime * price_per_hour)
else:
final_price = blocked_amount
# Update wallet balance
new_wallet_balance = current_wallet_balance + final_price
# Update Booking and Users records
cursor.execute("UPDATE Bookings SET end_time = %s, payment_state = 'Ride Completed' WHERE booking_id = %s", (end_time.strftime('%Y-%m-%d %H:%M:%S'), update.booking_id))
cursor.execute("UPDATE Users SET wallet_balance = %s WHERE user_id = %s", (new_wallet_balance, update.user_id))
db_connection.commit()
db_connection.close()
duration_hours = (end_time - start_time).total_seconds() / 3600
duration_hours_decimal = Decimal(str(duration_hours)) # Convert float to Decimal via string for accuracy
final_price = Decimal(blocked_amount) - (duration_hours_decimal * Decimal(price_per_hour))
new_wallet_balance = Decimal(wallet_balance) + final_price
# Perform database updates within a transaction
try:
cursor.execute("UPDATE Bookings SET end_time = %s, payment_state = 'Ride Completed' WHERE booking_id = %s",
(end_time.strftime('%Y-%m-%d %H:%M:%S'), update.booking_id))
cursor.execute("UPDATE Users SET wallet_balance = %s WHERE user_id = %s",
(new_wallet_balance, update.user_id))
db_connection.commit()
except Exception as e:
db_connection.rollback()
raise HTTPException(status_code=500, detail=f"An error occurred: {str(e)}")
return {
"message": "Booking updated and charges applied successfully",
"booking_id": update.booking_id,
"user_id": update.user_id,
"bike_id": update.bike_id,
"end_time": end_time.strftime('%Y-%m-%d %H:%M:%S'),
"final_price": final_price,
"new_wallet_balance": new_wallet_balance,
"payment_state": "Ride Completed"
"message": "Booking updated successfully",
"details": {
"booking_id": update.booking_id,
"final_price": float(final_price), # Convert Decimal back to float for JSON serialization
"new_wallet_balance": float(new_wallet_balance),
"end_time": end_time.strftime('%Y-%m-%d %H:%M:%S')
}
}
\ No newline at end of file
annotated-types==0.6.0
anyio==4.3.0
APScheduler==3.10.4
certifi==2024.2.2
click==8.1.7
dnspython==2.6.1
......@@ -23,11 +24,14 @@ pydantic-settings==2.2.1
pydantic_core==2.16.3
python-dotenv==1.0.1
python-multipart==0.0.9
pytz==2024.1
PyYAML==6.0.1
six==1.16.0
sniffio==1.3.1
SQLAlchemy==2.0.29
starlette==0.36.3
typing_extensions==4.10.0
tzlocal==5.2
ujson==5.9.0
uvicorn==0.29.0
uvloop==0.19.0
......
......@@ -2,18 +2,24 @@ version: '3'
services:
# MySQL service
database_mysql:
image: mysql:5.7
# database_mysql:
# image: mysql:5.7
# ports:
# - "3306:3306"
# environment:
# MYSQL_ROOT_PASSWORD: root_password
# MYSQL_DATABASE: your_database
# MYSQL_USER: your_username
# MYSQL_PASSWORD: your_password
# volumes:
# - mysql_data:/var/lib/mysql
# - ./sql_files:/docker-entrypoint-initdb.d # Mount SQL files for initialization
# Frontend service
front_end_client:
build: ./front_end_client
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: your_database
MYSQL_USER: your_username
MYSQL_PASSWORD: your_password
volumes:
- mysql_data:/var/lib/mysql
- ./sql_files:/docker-entrypoint-initdb.d # Mount SQL files for initialization
- "${FRONT_END_PORT}:8000"
# Microservices definitions...
admins_service:
......@@ -51,5 +57,12 @@ services:
environment:
- SERVICE_PORT=${USERS_SERVICE_PORT}
booking_service:
build: ./booking_service
ports:
- "${BOOKING_SERVICE_PORT}:8006"
environment:
- SERVICE_PORT=${BOOKING_SERVICE_PORT}
volumes:
mysql_data:
# Use a base image
FROM nginx:alpine
# Set the working directory inside the container
WORKDIR /usr/share/nginx/html
# Copy the frontend files from the host to the container
COPY . .
# Expose port 80 to the outside world
EXPOSE 8000
# Start the nginx server when the container starts
CMD ["nginx", "-g", "daemon off;"]
\ No newline at end of file
{
"files": {
"main.css": "/static/css/main.ed59ac45.css",
"main.js": "/static/js/main.30ae2d41.js",
"static/js/453.8ab44547.chunk.js": "/static/js/453.8ab44547.chunk.js",
"static/media/backgroundImage.jpg": "/static/media/backgroundImage.068b6e260d25adc44dc3.jpg",
"index.html": "/index.html",
"main.ed59ac45.css.map": "/static/css/main.ed59ac45.css.map",
"main.30ae2d41.js.map": "/static/js/main.30ae2d41.js.map",
"453.8ab44547.chunk.js.map": "/static/js/453.8ab44547.chunk.js.map"
},
"entrypoints": [
"static/css/main.ed59ac45.css",
"static/js/main.30ae2d41.js"
]
}
\ No newline at end of file
front_end_client/city_bike.jpeg

488 KiB

front_end_client/electric_bike.jpeg

257 KiB

front_end_client/favicon.jpg

91.2 KiB

<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" type="image/jpeg" href="/favicon.jpg"><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.30ae2d41.js"></script><link href="/static/css/main.ed59ac45.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
\ No newline at end of file
front_end_client/loading-icon.gif

175 KiB

front_end_client/logo192.png

5.22 KiB

front_end_client/logo512.png

9.44 KiB

{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment