Skip to content
Snippets Groups Projects
Commit eea38ef2 authored by Arnav Jain's avatar Arnav Jain
Browse files

Final Submission for Coursework

parent f5b1f128
Branches
No related tags found
No related merge requests found
Showing
with 365 additions and 3 deletions
# CM1102-DynamicWebsite-Coursework
# CM1102 Spring Coursework
......@@ -15,14 +15,14 @@ Already a pro? Just edit this README.md and make it your own. Want to make it ea
```
cd existing_repo
git remote add origin https://git.cardiff.ac.uk/c22115526/cm1102-dynamicwebsite-coursework.git
git remote add origin https://git.cardiff.ac.uk/c22115526/cm1102-spring-coursework.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://git.cardiff.ac.uk/c22115526/cm1102-dynamicwebsite-coursework/-/settings/integrations)
- [ ] [Set up project integrations](https://git.cardiff.ac.uk/c22115526/cm1102-spring-coursework/-/settings/integrations)
## Collaborate with your team
......
File added
from flask import Flask, render_template, request, session, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import IntegerField, StringField, SubmitField
from wtforms.validators import DataRequired, Length, NumberRange, Regexp, ValidationError
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
import re
app = Flask(__name__)
app.config['SECRET_KEY'] = 'top secret!'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.sqlite3'
bootstrap = Bootstrap(app)
db = SQLAlchemy(app)
class Technology(db.Model):
__tablename__ = 'technologies'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(16), index=True, unique=True)
price = db.Column(db.Integer)
description = db.Column(db.Text)
enviroment=db.Column(db.Text)
image = db.Column(db.String(64))
class BasketItem(db.Model):
__tablename__ = 'basket_items'
id = db.Column(db.Integer, primary_key=True)
technology_id = db.Column(db.Integer, db.ForeignKey('technologies.id'))
quantity = db.Column(db.Integer)
class OpinionForm(FlaskForm):
opinion = IntegerField('Quantity', validators=[DataRequired(), NumberRange(min=1)])
submit = SubmitField('Submit')
@app.route('/')
def galleryPage():
# Sorting function
sort = request.args.get('sort', 'name')
order = request.args.get('order', 'asc')
if sort not in ['name', 'price', 'environment']:
sort = 'name'
if order not in ['asc', 'desc']:
order = 'asc'
else:
if order == 'asc':
#Ascending sorting by name
techs = Technology.query.order_by(getattr(Technology, sort).asc()).all()
else:
#Descending sorting by name
techs = Technology.query.order_by(getattr(Technology, sort).desc()).all()
form = OpinionForm()
return render_template('index.html', technologies=techs, form=form, sort=sort, order=order)
#Basic Gallery Page, used in testing
# @app.route('/')
# def galleryPage():
# techs = Technology.query.all()
# form = OpinionForm()
# return render_template('index.html', technologies = techs, form=form)
@app.route('/add-item/<int:techId>', methods=['POST'])
def addItemFromHomePage(techId):
form = OpinionForm()
technology = Technology.query.get(techId)
if technology is None:
return "Technology not found", 404
if form.validate_on_submit():
# tp Check if the'basket' is in the session
if 'basket' in session:
basket = session['basket']
else:
basket = []
# adding an item to the basket
basket.append({'techId': techId, 'opinion': form.opinion.data})
session['basket'] = basket
return redirect(url_for('view_basket'))
return render_template('index.html', technology=technology, form=form)
@app.route('/tech/<int:techId>', methods=['GET', 'POST'])
def singleProductPage(techId):
form = OpinionForm()
technology = Technology.query.get(techId)
if technology is None:
return "Technology not found", 404
if form.validate_on_submit():
# to Check if the'basket' is in the session
if 'basket' in session:
basket = session['basket']
else:
basket = []
# adding an item to the basket
basket.append({'techId': techId, 'opinion': form.opinion.data})
session['basket'] = basket
return redirect(url_for('view_basket'))
return render_template('SingleTech.html', technology=technology, form=form)
# Logic for View and Delete items from Basket
@app.route('/basket', methods=['GET', 'POST'])
def view_basket():
if request.method == 'POST':
# Check if 'delete_item' form field is present in the request
if 'delete_item' in request.form:
# Get the index of the item to delete from the form data
index_to_delete = int(request.form['delete_item'])
# Remove the item from the session basket list
if 'basket' in session:
basket = session['basket']
if 0 <= index_to_delete < len(basket):
del basket[index_to_delete]
session['basket'] = basket
total_price=0
basket_contents = []
if 'basket' in session:
for idx, item in enumerate(session['basket']):
tech = Technology.query.get(item['techId'])
if tech:
quantity = int(item['opinion'])
basket_contents.append({'technology': tech, 'opinion': item['opinion'], 'index': idx})
total_price += tech.price * quantity
return render_template('basket.html', basket=basket_contents, total_price=total_price)
# ORIGINAL code for view_basket()
# @app.route('/basket', methods=['GET', 'POST'])
# def view_basket():
# if request.method == 'POST':
# pass
# basket_contents = []
# if 'basket' in session:
# for item in session['basket']:
# tech = Technology.query.get(item['techId'])
# if tech:
# basket_contents.append({'technology': tech, 'opinion': item['opinion']})
# return render_template('basket.html', basket=basket_contents)
class PaymentForm(FlaskForm):
credit_card_number = StringField('Credit/Debit Card Number', validators=[
DataRequired(),
Regexp(r'^[\d\s-]*$', message="Only digits, spaces, and dashes are allowed in the credit card number"),
Regexp(r'^(?:\d[ -]*?){16}$', message="The card number must contain exactly 16 digits")
])
name_on_card = StringField('Name on Card', validators=[DataRequired()])
expiration_date = StringField('Expiry Date (MMYY)', validators=[
DataRequired(),
Regexp(r'^\d{4}$', message="Expiration date must be exactly 4 digits (MMYY)")
])
cvv = StringField('CVV', validators=[
DataRequired(),
Regexp(r'^\d{3}$', message="CVV must be exactly 3 digits")
])
submit = SubmitField('Confirm Payment')
@app.route('/payment', methods=['GET', 'POST'])
def payment_page():
form = PaymentForm()
total_price = 0
if 'basket' in session:
for item in session['basket']:
tech = Technology.query.get(item['techId'])
if tech:
total_price += tech.price * int(item['opinion']) # Calculate total price
if form.validate_on_submit():
# Here you would normally handle payment processing
return render_template('payment_complete.html', total_price=total_price)
return render_template('payment.html', form=form, total_price=total_price)
# return render_template('payment.html', total_price=total_price)
@app.context_processor
def inject_basket():
basket_contents = session.get('basket', [])
return dict(basket=basket_contents)
# CODE FOR SESSIONS
# @app.route('/',methods=['GET','POST'])
# def main_page():
# # if there is no list of comments in session, create an empty list to store them
# if 'comments' not in session:
# print("New session",flush=True)
# session['comments'] = []
# # if form is submitted, add comment to session data
# form = CommentForm()
# if form.validate_on_submit():
# session['comments'] += [form.comment.data]
# return render_template('index.html',form=form,comments = session['comments'])
if __name__ == '__main__':
app.run(debug=True,port=5000)
'''Script to populate the database with some initial data.
In reality you would probably create a separate editor or a tool for importing data from elsewhere,
but for CM1102 we'll just use this script to populate the database.'''
from ListItems import app, db, Technology
technologies = [
{ "id": "1", "name": "BMW M4 Competition", "price": "80000", "description": "A high-performance sports coupe blending BMW's luxury with race-track-ready capabilities and a twin-turbocharged engine.", "enviroment": "CO2 emissions are 228g/km", "image": "bmwm4.jpg"},
{ "id": "2","name": "Tesla Model S Plaid", "price": "99000", "description": "An all-electric sedan setting benchmarks with its unparalleled acceleration, range, and advanced technology features.", "enviroment": "CO2 emissions are 18g/km","image": "tesla.jpg" },
{ "id": "3", "name": "Audi RS5 Coupe", "price": "74000", "description": "A sleek, aggressive coupe offering a harmonious mix of performance, comfort, and cutting-edge tech with its powerful V6 engine.", "enviroment": "CO2 emissions are 208g/km","image": "audirs5.jpg"},
{ "id": "4","name": "Mercedes C63 AMG", "price": "98000", "description": "A luxury sports sedan that combines the elegance of Mercedes-Benz with a powerful V8 engine for an exhilarating driving experience.", "enviroment": "CO2 emissions are 192g/km","image": "merecedesc63.jpg"},
{ "id": "5","name": "Jaguar F-Type", "price": "60000", "description": "A quintessentially British sports car that offers a perfect blend of performance, design, and refinement with a range of potent engines.", "enviroment": "CO2 emissions are 192g/km", "image": "jaguar.jpg" },
{ "id": "6","name": "Alfa Romeo Giulia Quadrifoglio", "price": "78000", "description": "An Italian masterpiece that stands out with its striking design, superb handling, and a ferocious twin-turbocharged V6 engine.", "enviroment": "CO2 emissions are 229g/km", "image": "alfaromeo.jpg"}
]
# Bear in mind this script does NOT run the app
# instead we use app.app_context() which Flask provides to allow us to use the app's configuration and extensions
with app.app_context():
db.create_all() # creates the empty tables
for tech in technologies:
newTech = Technology(id=tech["id"], name=tech["name"], price=tech["price"], description=tech["description"], enviroment=tech["enviroment"], image=tech["image"])
db.session.add(newTech)
db.session.commit()
File added
File added
File added
app4/static/alfaromeo.jpg

44.7 KiB

app4/static/audirs5.jpg

161 KiB

app4/static/bmwm4.jpg

193 KiB

app4/static/css_image.jpg

44.2 KiB

app4/static/html_image.jpg

3.13 KiB

app4/static/jaguar.jpg

475 KiB

app4/static/logo.jpg

11 KiB

app4/static/merecedesc63.jpg

814 KiB

app4/static/picture.jpg

1.12 MiB

.item-image-index {
height: 200px;
object-fit: contain;
width: 100%;
}
.item-image-individual {
height: 450px;
object-fit: contain;
width: 450px;
}
h1 {
text-align: center;
}
nav {
background-color :antiquewhite;
}
h3 {
text-align: center;
padding: 10px;
font-size: medium;
}
footer{
background-color: antiquewhite;
font-size: large;
}
body{
background-color: azure;
}
.sort-dropdown {
margin: 20px 0;
padding: 10px;
background-color:antiquewhite ;
border-radius: 5px;
}
.sort-dropdown label {
margin-right: 10px;
font-weight: bold;
}
.sort-dropdown select {
padding: 5px 10px;
border-radius: 5px;
border: 1px solid #ccc; /* Light grey border */
}
.total-basket {
display: flex;
justify-content: center;
align-items: center;
font-size: large;
}
.proceed-payment{
display: flex;
justify-content: center;
align-items: center;
}
/* .payment-form{
display: flex;
justify-content: center;
align-items: center;
} */
.payment-form {
width: 300px;
margin: auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
background-color: #f9f9f9;
}
.payment-form div {
margin-bottom: 10px;
}
.payment-form label {
font-weight: bold;
}
.payment-form input[type="text"],
.payment-form input[type="number"] {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
.payment-form .btn-primary {
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
border-radius: 4px;
}
.payment-form .errors {
color: red;
font-size: small;
list-style: none;
padding-left: 0;
}
app4/static/tesla.jpg

200 KiB

app4/static/tesla2.jpg

209 KiB

File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment