GymCrowd is a gym management and workout tracking platform tailored for fitness enthusiasts. The platform enables users to log workouts, set gym crowd level preferences, and receive notifications about gym activities. With robust user authentication and real-time updates, GymCrowd ensures a personalized and secure fitness experience.
- Frontend Repository: Link to Android repo
- Backend Repository: Link to Backend repo (this)
- User Authentication: Secure user sign-up, login, token-based authentication, and logout functionality.
- Workout Tracking: Log workouts, add exercises to specific sessions, and view detailed workout histories.
- Gym Preferences: Set maximum acceptable crowd levels for gyms and customize preferences.
- Notifications: Receive notifications for updates, alerts, and gym crowd statuses.
- Real-Time Updates: Stay informed with the latest gym crowd data and activity alerts.
- Django: Backend framework for robust application logic.
- Django REST Framework (DRF): Handles API endpoints for communication with the frontend.
- PostgreSQL: Relational database for storing user, workout, and notification data.
- RESTful API Design: Provides a modular and scalable backend structure.
For Simply Viewing:
- None!
Our backend is fully deployed and available at the production base URL:
Base URL: http://34.86.153.211:8000/
You can access all endpoints specified in API Specification directly through this URL. However, if you wish to test or develop the backend locally, you can follow the instructions below to see how we set up the application on our local machines initially.
For Devs: Before running this project, ensure you have the following installed on your system:
- Python (>=3.8)
- PostgreSQL (>=13.x)
- pip (Python package manager)
- Backend: Django, Django REST Framework
- Database: PostgreSQL
-
Clone the repository:
git clone [email protected]:<YOUR_USERNAME>/GymCrowd-backend.git cd GymCrowd-backend
-
Create a
.env
file in the root directory with the following structure:DATABASE_NAME=GymCrowd DATABASE_USER=postgres DATABASE_PWD=password DATABASE_HOST=gymcrowd-db DATABASE_PORT=5432 DEBUG=True SECRET_KEY=django-insecure-key
Replace the placeholder values with your PostgreSQL database information.
-
Run the application using Docker Compose:
docker-compose up --build
Note: This step is only required if you are running PostgreSQL outside of Docker Compose.
- Download and install PostgreSQL from the official website.
- Follow the installation wizard and set up the following:
- Username: Choose a database admin username (e.g.,
postgres
). - Password: Set a strong password for the admin account.
- Port: Use the default port
5432
or customize as needed.
- Username: Choose a database admin username (e.g.,
Note: can also be done manually through pgAdmin
-
Log into the PostgreSQL terminal:
psql -U postgres
-
Create a new database:
CREATE DATABASE GymCrowd;
-
Create a new user with a password:
CREATE USER gymcrowd_user WITH PASSWORD 'your-password';
-
Grant privileges to the new user:
GRANT ALL PRIVILEGES ON DATABASE GymCrowd TO gymcrowd_user;
-
Exit the PostgreSQL terminal:
\q
To start the application, simply run
docker-compose up --build
This command will:
- Build the Docker images for the application.
- Set up the PostgreSQL database and apply migrations.
- Populate the database with initial data for gyms and exercises.
Once the application is running, you can access it at: http://127.0.0.1:8000/
Use an API client like Postman or cURL to test the API endpoints. Make sure to include appropriate headers (e.g., Authorization tokens) where required.
- User Authentication: Sign up, log in, retrieve tokens, and log out.
- Workout Management: Add workouts, track exercises, and retrieve workout history.
- Gym Preferences: Set and update gym crowd level preferences.
- Notifications: Receive notifications about gym activities and updates.
Contributors: Adeeb Khan, Arjun Maitra, Ethan Zhang
The server should return an error response for:
- POST requests, if the user does not supply one of the required fields in the body (e.g., email, password, etc.) with a status code of
400 Bad Request
. - Any request if an invalid or missing parameter is provided, with an appropriate status code and error message.
{
"error": "Your error message here"
}
POST /api/users/login/
Validates user credentials (username and password) and logs the user into the application if the credentials are valid.
{
"username": "user123",
"password": "securepassword123"
}
Status Code: 200 OK
{
"user": {
"user_id": <USER_ID>,
"username": "<USER_USERNAME>",
"name": "<USER_NAME>",
"email": "<USER_EMAIL>",
"preferences": [],
"workouts": [],
"notifications": []
},
"message": "Login successful."
}
- Status Code:
400 Bad Request
{
"error": "Username and password are required."
}
- Status Code:
401 Unauthorized
{
"error": "Invalid username or password."
}
POST /api/users/token/
Generates a token for an authenticated user. The token is used for authenticating protected API endpoints. Note that this route can also be used for user login.
{
"username": "<USER_USERNAME>",
"password": "securepassword123"
}
Status Code: 200 OK
{
"token": "<USER_TOKEN>",
"user": {
"user_id": <USER_ID>,
"username": "<USER_USERNAME>",
"name": "<USER_NAME>",
"email": "<USER_EMAIL>",
"preferences": [],
"workouts": [],
"notifications": []
}
}
- Status Code:
400 Bad Request
{
"error": "Username and password are required."
}
- Status Code:
401 Unauthorized
{
"error": "Invalid username or password."
}
POST /api/users/signup/
Allows users to create a new account by providing their name, email, username, and password. Passwords are hashed before being stored in the database.
{
"name": "<USER_NAME>",
"email": "<USER_EMAIL>",
"username": "<USER_USERNAME>",
"password": "securepassword123"
}
Status Code: 201 Created
{
"user": {
"user_id": "<USER_ID>",
"username": "<USER_USERNAME>",
"name": "<USER_NAME>",
"email": "<USER_EMAIL>",
"preferences": [],
"workouts": [],
"notifications": []
},
"message": "Account created successfully."
}
- Status Code:
400 Bad Request
Missing Fields:
{
"error": "Name, email, username, and password are required."
}
Email Already Exists:
{
"error": "An account with this email already exists."
}
Username Already Exists:
{
"error": "An account with this username already exists."
}
- Status Code:
500 Internal Server Error
{
"error": "Failed to create account: <ERROR_MESSAGE>"
}
POST /api/users/logout/
Logs the user out by deleting the authentication token associated with their account.
Authorization: Token <USER_TOKEN>
Status Code: 200 OK
{
"message": "Logout successful."
}
- Status Code:
401 Unauthorized
{
"detail": "Authentication credentials were not provided."
}
GET /api/users/preferences/
Retrieves a list of all preferences set by the authenticated user. Each preference is linked to a gym and specifies the maximum acceptable crowd level.
Authorization: Token <USER_TOKEN>
Status Code: 200 OK
{
"preferences": [
{
"preference_id": 1,
"user": 1,
"gym": 2,
"max_crowd_level": 0.8,
"created_at": "2024-11-24T18:00:00Z"
},
{
"preference_id": 2,
"user": 1,
"gym": 3,
"max_crowd_level": 0.6,
"created_at": "2024-11-25T18:00:00Z"
}
]
}
- Status Code:
403 Forbidden
{
"detail": "Authentication credentials were not provided."
}
POST /api/users/preferences/
Allows the authenticated user to create a new gym preference. This includes specifying the gym and the maximum acceptable crowd level.
Authorization: Token <USER_TOKEN>
{
"gym": 2,
"max_crowd_level": 0.8
}
Status Code: 201 Created
{
"preference_id": 1,
"user": 1,
"gym": 2,
"max_crowd_level": 0.8,
"created_at": "2024-11-24T18:00:00Z"
}
- Status Code:
400 Bad Request
{
"error": "Gym and max_crowd_level are required."
}
- Status Code:
403 Forbidden
{
"detail": "Authentication credentials were not provided."
}
PUT /api/users/preferences/<preference_id>/
Allows the authenticated user to update an existing gym preference. This includes modifying the gym or the maximum acceptable crowd level.
Authorization: Token <USER_TOKEN>
{
"gym": 3,
"max_crowd_level": 0.7
}
Status Code: 200 OK
{
"preference_id": 1,
"user": 1,
"gym": 3,
"max_crowd_level": 0.7,
"updated_at": "2024-11-25T18:30:00Z"
}
- Status Code:
400 Bad Request
{
"error": "Invalid fields provided."
}
- Status Code:
403 Forbidden
{
"detail": "Authentication credentials were not provided."
}
- Status Code:
404 Not Found
{
"error": "Preference not found."
}
DELETE /api/users/preferences/<preference_id>/
Allows the authenticated user to delete an existing gym preference.
Authorization: Token <USER_TOKEN>
Status Code: 200 OK
{
"message": "Preference deleted successfully."
}
- Status Code:
403 Forbidden
{
"detail": "Authentication credentials were not provided."
}
- Status Code:
404 Not Found
{
"error": "Preference not found."
}
GET /api/gyms/
Fetches a list of all gyms in the system, including their details and associated crowd data.
Status Code: 200 OK
{
"gyms": [
{
"gym_id": <GYM_ID>,
"name": "<GYM_NAME>",
"location": "<GYM_LOCATION>",
"type": "<GYM_TYPE>",
"crowd_data": [
{
"crowd_id": <CROWD_ID>,
"occupancy": <OCCUPANCY>,
"percentage_full": <PERCENTAGE_FULL>,
"last_updated": "<LAST_UPDATED>"
}
]
},
...
]
}
GET /api/gyms/<id>/
Fetches the details of a specific gym by its ID, including associated crowd data.
Status Code: 200 OK
{
"gym_id": <GYM_ID>,
"name": "<GYM_NAME>",
"location": "<GYM_LOCATION>",
"type": "<GYM_TYPE>",
"crowd_data": [
{
"crowd_id": <CROWD_ID>,
"occupancy": <OCCUPANCY>,
"percentage_full": <PERCENTAGE_FULL>,
"last_updated": "<LAST_UPDATED>"
}
]
}
- Status Code:
404 Not Found
{
"error": "Gym not found."
}
GET /api/gyms/crowddata/
Fetches a list of all crowd data entries in the system.
Status Code: 200 OK
{
"crowd_data": [
{
"crowd_id": <CROWD_ID>,
"gym": <GYM_ID>,
"occupancy": <OCCUPANCY>,
"percentage_full": <PERCENTAGE_FULL>,
"last_updated": "<LAST_UPDATED>"
},
...
]
}
GET /api/gyms/crowddata/<id>/
Fetches details of a specific crowd data entry by its ID.
Status Code: 200 OK
{
"crowd_id": <CROWD_ID>,
"gym": <GYM_ID>,
"occupancy": <OCCUPANCY>,
"percentage_full": <PERCENTAGE_FULL>,
"last_updated": "<LAST_UPDATED>"
}
- Status Code:
404 Not Found
{
"error": "Crowd data entry not found."
}
GET /api/workouts/exercises/
Fetches a list of all available exercises in the system.
No authentication required.
Status Code: 200 OK
{
"exercises": [
{
"exercise_id": <EXERCISE_ID>,
"name": "<EXERCISE_NAME>",
"body_part": "<BODY_PART>",
"equipment": "<EQUIPMENT>",
"gif_url": "<GIF_URL>",
"target": "<TARGET>",
"secondary_muscles": "<SECONDARY_MUSCLES>",
"instructions": "<INSTRUCTIONS>"
},
...
]
}
GET /api/workouts/exercises/<exercise_id>/
Fetches details of a specific exercise by its ID.
No authentication required.
Status Code: 200 OK
{
"exercise_id": <EXERCISE_ID>,
"name": "<EXERCISE_NAME>",
"body_part": "<BODY_PART>",
"equipment": "<EQUIPMENT>",
"gif_url": "<GIF_URL>",
"target": "<TARGET>",
"secondary_muscles": "<SECONDARY_MUSCLES>",
"instructions": "<INSTRUCTIONS>"
}
- Status Code:
404 Not Found
{
"error": "Exercise not found."
}
GET /api/workouts/
Fetches a list of all workout sessions for the authenticated user.
A token in the header.
Header:
Authorization: Token <USER_TOKEN>
Status Code: 200 OK
{
"workouts": [
{
"workout_id": <WORKOUT_ID>,
"user": <USER_ID>,
"date": "<WORKOUT_DATE>",
"created_at": "<CREATED_AT>",
"workout_exercises": [
{
"entry_id": <ENTRY_ID>,
"exercise": <EXERCISE_ID>,
"sets": <SETS>,
"reps": <REPS>,
"weight": <WEIGHT>
},
...
]
},
...
]
}
POST /api/workouts/
Creates a new workout session for the authenticated user.
A token in the header.
Header:
Authorization: Token <USER_TOKEN>
{
"date": "<WORKOUT_DATE>"
}
Status Code: 201 Created
{
"workout_id": <WORKOUT_ID>,
"user": <USER_ID>,
"date": "<WORKOUT_DATE>",
"created_at": "<CREATED_AT>",
"workout_exercises": []
}
- Status Code:
400 Bad Request
{
"error": "Invalid or missing fields in request."
}
GET /api/workouts/<workout_id>/
Fetches details of a specific workout session by its ID.
A token in the header.
Header:
Authorization: Token <USER_TOKEN>
Status Code: 200 OK
{
"workout_id": <WORKOUT_ID>,
"user": <USER_ID>,
"date": "<WORKOUT_DATE>",
"created_at": "<CREATED_AT>",
"workout_exercises": [
{
"entry_id": <ENTRY_ID>,
"exercise": <EXERCISE_ID>,
"sets": <SETS>,
"reps": <REPS>,
"weight": <WEIGHT>
},
...
]
}
- Status Code:
404 Not Found
{
"error": "Workout not found."
}
GET /api/workouts/workout-exercises/
Fetches all exercises logged in the authenticated user's workouts.
A token in the header.
Header:
Authorization: Token <USER_TOKEN>
Status Code: 200 OK
{
"workout_exercises": [
{
"entry_id": <ENTRY_ID>,
"workout": <WORKOUT_ID>,
"exercise": <EXERCISE_ID>,
"sets": <SETS>,
"reps": <REPS>,
"weight": <WEIGHT>
},
...
]
}
POST /api/workouts/workout-exercises/
Adds a new exercise entry to a specific workout session for the authenticated user.
A token in the header.
Header:
Authorization: Token <USER_TOKEN>
{
"workout": <WORKOUT_ID>,
"exercise": <EXERCISE_ID>,
"sets": <SETS>,
"reps": <REPS>,
"weight": <WEIGHT>
}
Status Code: 201 Created
{
"entry_id": <ENTRY_ID>,
"workout": <WORKOUT_ID>,
"exercise": <EXERCISE_ID>,
"sets": <SETS>,
"reps": <REPS>,
"weight": <WEIGHT>
}
- Status Code:
400 Bad Request
{
"error": "Invalid or missing fields in request."
}
- Status Code:
403 Forbidden
{
"error": "You do not have permission to add exercises to this workout."
}
GET /api/notifications/
Fetches a list of all notifications in the system.
No authentication required.
Status Code: 200 OK
{
"notifications": [
{
"notification_id": 1,
"user": 12,
"gym": 3,
"message": "Your session is confirmed.",
"sent_at": "2024-01-01T12:00:00Z"
},
...
]
}
POST /api/notifications/
Creates a new notification associated with the authenticated user.
A token in the header.
Header:
Authorization: Token <USER_TOKEN>
{
"gym": <GYM_ID>,
"message": "<NOTIFICATION_MESSAGE>"
}
Status Code: 201 Created
{
"notification_id": <NOTIFICATION_ID>,
"user": <USER_ID>,
"gym": <GYM_ID>,
"message": "<NOTIFICATION_MESSAGE>",
"sent_at": "<TIMESTAMP>"
}
- Status Code:
400 Bad Request
{
"error": "Invalid or missing fields in request."
}
GET /api/notifications/<notification_id>/
Fetches details of a specific notification by its ID.
A token in the header.
Header:
Authorization: Token <USER_TOKEN>
Status Code: 200 OK
{
"notification_id": <NOTIFICATION_ID>,
"user": <USER_ID>,
"gym": <GYM_ID>,
"message": "<NOTIFICATION_MESSAGE>",
"sent_at": "<TIMESTAMP>"
}
- Status Code:
404 Not Found
{
"error": "Notification not found."
}
GET /api/notifications/user/<user_id>/
Fetches all notifications for a specific user.
A token in the header.
Header:
Authorization: Token <USER_TOKEN>
Status Code: 200 OK
{
"notifications": [
{
"notification_id": 1,
"gym": 3,
"message": "Your session is confirmed.",
"sent_at": "2024-01-01T12:00:00Z"
},
...
]
}
- Status Code:
403 Forbidden
{
"error": "You do not have permission to view these notifications."
}
DELETE /api/notifications/<notification_id>/
Deletes a specific notification by its ID.
A token in the header.
Header:
Authorization: Token <USER_TOKEN>
Status Code: 204 No Content
- Status Code:
404 Not Found
{
"error": "Notification not found."
}