Movie Website for Final Group Project of CSCI 4230U Advanced Web Development Fall 2025.
- Hamza Hassan (100788913)
- Abdullah Mohammed (100784442)
The platform allows users to browse movies, view showtimes, and book tickets, while administrators can manage the movie catalogue and oversee bookings.
The application is built using Flask, and SQLAlchemy for the backend, and HTML, CSS, and JS for the frontend. Users authenticate using secure password hashing with salts and a server-side pepper, and JWT tokens manage authorization for protected endpoints. Admin-only functionality ensures that only authenticated administrators can create, edit, and remove movies from the system.
The site integrates with the OMDb API (https://www.omdbapi.com/) to fetch movie details and posters dynamically, Ollama for an AI chatbot and a Stripe placeholder for future payment integration.
The goal of the project was to design a clean, maintainable, and scalable movie booking system demonstrating the backend knowledge and skills learned in the course.
Additionally, since the presentation, we have added an AI chatbot that you can ask questions about the movies being shown. Admin can search/add/remove movies to the database, which the homepage uses to show movie listings. Finally admin can remove users and modify/remove bookings.
Before running or developing the application, ensure the following are installed:
- Python 3.10+
- Ollama (for chatbot)
- pip (Python package manager)
- Virtual environment support (
venv) - Git
- Docker (for containerized deployment)
All required Python packages are listed in requirements.txt.
You can install them using:
pip install -r requirements.txt
The project relies on database credentials, API keys, and secret keys stored in .env.
A template is provided at .env.example.
python -m .venv venv
source .venv/bin/activate # macOS / Linux
.venv\Scripts\activate # Windows
pip install -r requirements.txt
cp .env.example .env
Fill in:
SECRET_KEY=...
JWT_SECRET_KEY=...
PEPPER=...
DATABASE_URL=sqlite:///database.db
STRIPE_SECRET_KEY=
TICKET_PRICE_CENTS=1300
This is for the chatbot to work.
ollama pull gemma3:1b
ollama serve
This creates:
- An admin user
- Initial set of movies
python seed.py
python app.py
Your app is now running at: http://localhost:5000
Docker does all the above steps for you.
docker build -t movie-website .
docker run --env-file .env -p 5000:5000 -v "$(pwd)/instance:/app/instance" movie-website
Your app is now running at: http://localhost:5000
From the project directory and while in a virtual environment, run:
pytest -q
- Admin username: admin
Admin password: Admin123! - The website is also deployed: https://www.moviewebsite.ca/
- Unfortunately, we could not get Ollama working with the deployment site, but the chatbot does work when run locally.
- Flask (routing, server-side rendering)
- SQLAlchemy ORM for database modelling
- Marshmallow for validation schemas
- JWT for secure authentication
- bcrypt for password hashing
- HTML5 + Jinja templates
- CSS
- JavaScript
- SQLite
- OMDb API for movie data and posters
- Ollama for AI chatbot
- Stripe for payments
- Pytest for unit testing
- SeleniumBase for e2e testing
This endpoint just renders the register HTML page.
Body:
{
"user": "string",
"password": "string",
"role": "string"
}
The role part is optional, if you do not include it, the default will be just the ‘user’ role.
The endpoint will return either 2 things:
- 409 if the username already exists
- 201 with JSON output:
{"message": "User registered successfully"} - indicating a successful account creation
This endpoint will render the login page and clear any JWT tokens saved (if any).
Body:
{
"username": "string",
"password": "string"
}
If successful it will return:
{
"message": "Successful login",
"token": "<jwt_token>"
}
Otherwise it will return:
- 404: User not found
- 401: Invalid Password
User will need a valid admin token to access this endpoint.
Will return JSON dictionary that looks like:
{
"Bookings": [
`{`
`"id": "int",`
`"movie_title": "string",`
`"show_date": "string",`
`"showtime": "string",`
`"quantity": "int",`
`"booked_by": "string",`
`"created_at": "string"`
`}`
]
}
It will return all bookings created by all users.
This creates a booking. This endpoint requires a valid token.
Body:
{
"movie_title": "string",
"show_date": "string",
"showtime": "string",
"quantity": "int"
}
Response:
- 201 returns booking payload
- 400 for validation errors
- 500 on DB error
User will need a token for this endpoint.
Body:
Same booking fields as POST /api/bookings.
Returns:
- Creates Stripe Checkout Session; returns:
{"checkout_url": "string"} - 400 validation errors
- 401 unauthenticated
- 500 if Stripe not configured/fails
User will need a valid admin token.
Body JSON: any of date, showtime, quantity:
{
"time": "string",
"available": "int",
"quantity": "string"
}
Updates booking and preserves the original booked_by.
Returns:
- updated booking payload
- 400 validation errors
- 403 unauthorized
- 404 not found
- 500 DB error
User will need a valid token.
Returns:
{
"message": "Booking cancelled successfully",
"booking_id": "int"
}
or
- 401 unauthenticated
- 403 unauthorized
- 404 not found
- 500 on DB error
Will need a valid admin token.
Returns:
{"users": [ { "id": int, "username": "string", "role": "string" } ]}
or 403 if not admin.
Will need valid admin token. Deletes user and their bookings.
Returns:
{
"message": "User deleted successfully",
"user_id": int,
"deleted_bookings": int
}
or
- 403 unauthorized users
- 404 not found
- 500 on DB error
If session_id provided, fetches Stripe session, saves booking from metadata, renders HTML success page.
Renders HTML cancel page.
Stripe webhook receiver. Expects STRIPE_WEBHOOK_SECRET.
On checkout, returns empty 200/400/500.
Renders the main home page of the website. (A valid session token is required.)
Returns:
HTML page showing a list of all movies currently stored in the database.
This endpoint powers messaging with the AI chatbot on the homepage. (A valid session token is required.)
Body JSON:
{
"message": "string"
}
Returns:
{
"reply": "string"
}
Errors:
- 400 — Missing JSON body
- 400 — Empty message provided
Displays the full movie detail page. (A valid session token is required.)
- Retrieves the movie from the local database by IMDb ID
- Queries OMDB API to fetch full details
- Combines DB + OMDB data into a single object
Returns:
- HTML page
movie.htmlwith full movie details - 404 if the movie does not exist
Loads the booking page for the selected movie. (A valid session token is required.)
- Pulls movie from the database
- Displays available showtimes
- Renders the booking form
Returns:
- HTML page
booking.html(empty booking form) - Injects today, showtimes, and the movie data
Loads the booking edit page. (A valid session token is required.)
Only admins may edit any booking; otherwise, the user is redirected away.
Returns:
- HTML page
booking.html - Pre-filled booking data including date, showtime, and quantity
- Movie information
Errors:
- 404 — Booking not found
- Redirect if unauthorized
Shows all bookings made by the logged-in user. (A valid session token is required.)
- Fetches all bookings for the current user
- Sorts them newest-first
- Builds a JSON-friendly booking payload for frontend use
Returns:
- HTML page
bookings.html
Admin dashboard page. (A valid session token is required.)
Only admin users can access this page; otherwise, the user is redirected away.
Returns:
HTML dashboard showing users and bookings.
Movie management panel for admins. (A valid session token is required.)
Only admin users can access this page.
Returns:
- HTML page listing all movies in the system
- Injects the current week date for expiration scheduling
Provides OMDB search results for admins when adding movies. (A valid session token is required.)
Only admin users can access this page.
q (required query): The movie search string
Returns:
{
"results": [
`{`
`"Title": "...",`
`"Year": "...",`
`"Poster": "...",`
`"imdbID": "..."`
`}`
]
}
Errors:
- 403 — Unauthorized (not admin)
- 400 — Missing search query
Adds a new movie to the database. (A valid session token is required.)
Only admin users can access this page.
Body:
{
"imdb_id": "string",
"title": "string",
"year": "string",
"poster": "string",
"expiration": "YYYY-MM-DD (optional)"
}
Returns:
{"message": "Movie added"}on success- If the movie already exists:
{"message": "Movie already added"}
Errors:
- 403 — Unauthorized user
Removes a movie from the database. (A valid session token is required.)
Only admin users can access this page.
Body:
{"imdb_id": "string"}
Returns:
{"message": "Movie removed"}
Errors:
- 403 — Unauthorized user
Our chosen architecture for this project was MVC. Our models is the database. Our View is the HTML with Jinja. And the controller is the flask backend.
Deployment to a cloud platform or a general-purpose server & Documentation of the deployment process
The project includes:
The app can be deployed on any machine that has Python installed.
This method is used during development and the demonstration.
Steps:
python -m .venv venv
source .venv/bin/activate
pip install -r requirements.txt
python app.py
Docker provides a clean and isolated environment that ensures consistent deployment regardless of the host machine.
Build the image:
docker build -t movie-website .
Run the container:
docker run -p 5000:5000 --env-file .env -v "$(pwd)/instance:/app/instance" movie-website
This containerized deployment simulates how the application would run in a production environment, even though the project is not hosted online.
These are the steps that I did to deploy our website using Amazon EC2
Went to AWS website and created an EC2 instance. Once I did that, I got a ssh file that I downloaded
I used this ssh file to get into the EC2 instance in my terminal using the command:
ssh -i kpName.pem ubuntu@PUBLIC_IP
In the EC2 instance terminal I installed Docker, Git, and nginx using the command:
sudo apt install -y docker.io nginx git
I then pulled our git repo onto the EC2 terminal using:
Git pull https://github.com/HamzaHassan02/CSCI4230U-Movie_Website.git
Then we built our docker image and ran it using these commands:
docker build -t movie-website .
docker run --env-file .env -p 5000:5000 -v \ "$(pwd)/instance:/app/instance" movie-website
I went to the DNS settings of the website that I bought the domain off of(squarespace domains) and pointed it’s dns to our instance of EC2
I used certbot to get a certificate for this website and made it secure (HTTPS)
Added a github action script that would deploy the website automatically once you pushed to the main branch
The repository includes multiple GitHub Actions workflow located in:
.github/workflows/
There are a couple workflows:
This will open Pull Requests for outdated dependencies
This will find security vulnerabilities in this app.
This will run just the unit tests of this app.
This will run the end to end tests of this app.
This provides continuous integration support without deploying to production, and ensures code.