diff --git a/auction/__init__.py b/auction/__init__.py index 97c6ef0..a16a04c 100644 --- a/auction/__init__.py +++ b/auction/__init__.py @@ -7,33 +7,34 @@ db = SQLAlchemy() # defines a new database DB_NAME = "database.db" def app(): # creates and initialises a flask app - application = Flask(__name__) # initializes the app - application.secret_key = "password" # encrypts cookies and session data for the website + + app = Flask(__name__) # initializes the app + app.secret_key = "password" # encrypts cookies and session data for the website # stores sqlite database in the current directory - application.config["SQLALCHEMY_DATABASE_URI"] = f'sqlite:///{DB_NAME}' - db.init_app(application) # initialises database with the application + app.config["SQLALCHEMY_DATABASE_URI"] = f'sqlite:///{DB_NAME}' + db.init_app(app) # initialises database with the app # sets where uploaded images are saved - application.config["IMAGE_UPLOADS"] = "/home/codio/workspace/auction/static/images" + app.config["IMAGE_UPLOADS"] = "/home/codio/workspace/auction/static/images" from .routes import routes # imports the routes from the route file - application.register_blueprint(routes, url_prefix="/") + app.register_blueprint(routes, url_prefix="/") - from .database_models import User, Item # imports the database classes from the database_models file - create_db(application) + from .database_models import Item, User # imports the database classes from the database_models file + create_db(app) login_manager = LoginManager() login_manager.login_view = "routes.login" - login_manager.init_app(application) + login_manager.init_app(app) @login_manager.user_loader def load_user(id): # tells user how to find a user return User.query.get(int(id)) # looks for primary key, checking against the id passed - return application + return app -def create_db(application): +def create_db(app): # checks if the database exists already, creating it if not - if not path.exists("auction/" + DB_NAME): # determines if database.db is a path in the directory - db.create_all(app=application) # creates the database \ No newline at end of file + #if not path.exists("auction/" + DB_NAME): # determines if database.db is a path in the directory + db.create_all(app=app) # creates the database \ No newline at end of file diff --git a/auction/database.db b/auction/database.db index 3998f5c..d2f376c 100644 Binary files a/auction/database.db and b/auction/database.db differ diff --git a/auction/database_models.py b/auction/database_models.py index d8bcdb4..02ed66f 100644 --- a/auction/database_models.py +++ b/auction/database_models.py @@ -6,13 +6,15 @@ class Item(db.Model): # class that stores info about each item on the system item_id = db.Column(db.Integer, primary_key=True) # primary key id number item_name = db.Column(db.String(150)) description = db.Column(db.String(500)) - start_bid = db.Column(db.Integer) + price = db.Column(db.Integer) + current_bid = db.Column(db.Integer, default=0) item_image = db.Column(db.Text()) - - date_only = db.Column(db.Date, server_default=func.date()) # just the date the item was made - date = db.Column(db.DateTime(timezone=True), server_default=func.now()) # defaults the datetime to now + + date = db.Column(db.DateTime, server_default=func.now()) # defaults the datetime to now + auction_end = db.Column(db.DateTime) sold = db.Column(db.Boolean(), default=False) + sold_to = db.Column(db.Integer, default=0) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) # must pass a valid id of an existing user to this object, 1 to many class User(db.Model, UserMixin): # creates each user in the database @@ -21,6 +23,4 @@ class User(db.Model, UserMixin): # creates each user in the database phone = db.Column(db.Integer) password = db.Column(db.String(150)) username = db.Column(db.String(150)) - items = db.relationship('Item') # a list of all the items a user owns - -#current_bid = db.Column(db.Integer) \ No newline at end of file + items = db.relationship('Item') # a list of all the items a user owns \ No newline at end of file diff --git a/auction/routes.py b/auction/routes.py index 45ae17f..6290396 100644 --- a/auction/routes.py +++ b/auction/routes.py @@ -6,6 +6,8 @@ from werkzeug.utils import secure_filename # allows me to change the uploaded fi from . import db from flask_login import login_user, login_required, logout_user, current_user # login management modules import os +from datetime import datetime, timedelta +import smtplib routes = Blueprint("routes", __name__) # blueprint allows splitting up routes over several files @@ -14,17 +16,20 @@ routes = Blueprint("routes", __name__) # blueprint allows splitting up routes ov UPLOAD_FOLDER = "/home/codio/workspace/auction/static/images" ALLOWED_EXTENSIONS = set(['jpg']) + @routes.route("/", methods=['GET', 'POST']) -@login_required # requires the user to be logged in to access +#@login_required # requires the user to be logged in to access def home_page(): items = Item.query.all() # gets all rows of items users = User.query.all() # gets all rows of items - return render_template("home_page.html", items=items, user=current_user, users=users, extensions=ALLOWED_EXTENSIONS) # sends items to the html and keeps track of login status + dt = datetime.now() + return render_template("home_page.html", items=items, user=current_user, users=users, dt=dt) # sends items to the html and keeps track of login status + @routes.route("/login", methods=['GET', 'POST']) def login(): # users can login to the website using an existing account if request.method == 'POST': - email = request.form.get("email") + email = request.form.get("email") # gets values from form password = request.form.get("password") user = User.query.filter_by(email = email).first() # checks all the users with the email entered @@ -34,12 +39,13 @@ def login(): # users can login to the website using an existing account login_user(user, remember=True) # remembers the user is logged while the web server is using return redirect(url_for('routes.home_page')) # redirects the user to the home page else: - flash("Password incorrect", category="warning") + flash("Password incorrect", category="warning") # shows a warning else: flash("Account does not exist", category="warning") return render_template("login.html", user=current_user) + @routes.route("/register", methods=['GET', 'POST']) def register(): # users can register for a new account, saves new user to the database if request.method == 'POST': @@ -71,18 +77,20 @@ def register(): # users can register for a new account, saves new user to the da return render_template("register.html", user=current_user) + @routes.route("/logout") @login_required -def logout(): +def logout(): # allows users to logout logout_user() # remembers that the user has logged out flash("You are now logged out.", category="success") - return redirect(url_for("routes.login")) # redirects user back to the login page + return redirect(url_for("routes.home_page")) # redirects user back to the login page + -def allowed_file(filename): +def allowed_file(filename): # checks the image uploaded is of the write extension return '.' in filename and \ filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS -# ********adds to the database even with the wrong extension, since it needs to commit to get user id************* + @routes.route("/sell", methods=['GET', 'POST']) @login_required def sell(): # user can enter information about an item they would like to add to the home page in order to sell @@ -91,10 +99,14 @@ def sell(): # user can enter information about an item they would like to add to item_name = item_name.capitalize() # capitalizes name description = request.form.get("description") description = description.capitalize() - start_bid = request.form.get("start_bid") - + price = request.form.get("price") + + dt = datetime.now() + td = timedelta(days=3) + auction_end = dt + td # gets the auction end time, set to 3 days in the future + #creates a new Item object - new_item = Item(item_name=item_name, description=description, start_bid=start_bid, user_id=current_user.id) + new_item = Item(item_name=item_name, description=description, price=price, auction_end=auction_end, user_id=current_user.id) db.session.add(new_item) db.session.commit() # commits the new item to the database @@ -120,13 +132,16 @@ def sell(): # user can enter information about an item they would like to add to return render_template("sell.html", user=current_user) + @routes.route("/myitems", methods=['GET', 'POST']) @login_required def my_items(): # shows items the user has for put sale length = len(current_user.items) # how many items the user has for sale + dt = datetime.now() # gets the current date and time + if length > 0: - return render_template("my_items.html", user=current_user) # shows the user their items - else: + return render_template("my_items.html", user=current_user, dt=dt) # shows the user their items + else: # if the user has no items for sale return render_template("no_items.html", user=current_user) # tells the user they have nothing for sale @@ -136,12 +151,23 @@ def item_info(item_id): # route shows users a dedicated page for each item, with user = current_user users = User.query.all() # gets all users item = Item.query.filter_by(item_id=item_id).first() # finds the item the user clicked ons information - return render_template("item.html", user=current_user, users=users, item=item) + dt = datetime.now() + + # if statements show different html depending on if the item is marked as sold, expired, or still for sale + if item.sold == True: + return render_template("item_sold.html", user=current_user, users=users, item=item) + + elif dt > item.auction_end: + return render_template("item_expired.html", user=current_user, users=users, item=item) + + elif item.sold == False: + return render_template("item.html", user=current_user, users=users, item=item) + @routes.route("/delete/", methods=['GET', 'POST']) @login_required def item_delete(item_id): # allows a user to delete their item from the website - user=current_user + user = current_user item = Item.query.filter_by(item_id=item_id).first() # finds the item they clicked on # prevents another user deleting items they don't own @@ -149,12 +175,14 @@ def item_delete(item_id): # allows a user to delete their item from the website Item.query.filter_by(item_id=item_id).delete() # deletes the item db.session.commit() flash("Item deleted", category="success") + return redirect(url_for('routes.my_items')) else: flash("Unauthorised user", category="warning") # tells the user if they try to delete someone elses item return redirect(url_for('routes.home_page')) # redirects to the home page + @routes.route("/sold/", methods=['GET', 'POST']) @login_required def sold(item_id): # allows a user to mark an item as sold @@ -167,6 +195,54 @@ def sold(item_id): # allows a user to mark an item as sold db.session.commit() else: - flash("Unauthorised user", category="warning") # tells the user if they try to delete someone elses item + flash("Unauthorised user", category="warning") # tells the user if they try to mark someone elses item + return redirect(url_for('routes.home_page')) # redirects to the home page + + winner = User.query.filter_by(id=item.sold_to).first() + if item.sold_to > 0: + notify_winner(winner, item) # sends an email to the winner + return redirect(url_for('routes.my_items')) # redirects to the home page + + +@routes.route("/bid/", methods=['GET', 'POST']) +@login_required +def bid(item_id): # allows a user to bid on an item + user = current_user + item = Item.query.filter_by(item_id=item_id).first() + + if item.sold_to == 0: # if this is the first bid + new_bid = request.form.get("new_bid") # gets the bid from the form + item.current_bid = new_bid # sets the values in the database = to the new values + item.sold_to = user.id + db.session.commit() # updates the database + + else: # if the item has been bid on before + outbid_user = User.query.filter_by(id=item.sold_to).first() + notify_outbid(outbid_user, item) # emails the person being outbid + new_bid = request.form.get("new_bid") # gets the bid from the form + item.current_bid = new_bid # sets the values in the database = to the new values + item.sold_to = user.id + db.session.commit() + + return redirect(url_for('routes.item_info', item_id=item.item_id)) # redirects to the home page + + +def notify_winner(winner, item): # emails a user if they win an auction + message = "you have won the "+item.item_name+" auction!!" # not allowing me to send an email with a link in it, coming in blank + winner_email = winner.email + send_email("pythonflaskemail@gmail.com", "josephlees79@gmail.com", message) # changed reciever to reduce spam when testing + + +def notify_outbid(user, item): # emails a user if they are outbid + message = "you have been outbid on the "+item.item_name+" auction!" # wont allow me to put a link in the email + outbid_email = user.email + send_email("pythonflaskemail@gmail.com", "josephlees79@gmail.com", message) + - return redirect(url_for('routes.my_items')) # redirects to the home page \ No newline at end of file +def send_email(sender, reciever, message): # sends the email using smtplib module + password = "Python150*" + + server = smtplib.SMTP("smtp.gmail.com", 587) + server.starttls() + server.login(sender, password) + server.sendmail(sender, "josephlees79@gmail.com", message) \ No newline at end of file diff --git a/auction/static/images/2.jpg b/auction/static/images/2.jpg index db38c8d..bb0a51e 100644 Binary files a/auction/static/images/2.jpg and b/auction/static/images/2.jpg differ diff --git a/auction/static/images/4.jpg b/auction/static/images/4.jpg index bb0a51e..777eab6 100644 Binary files a/auction/static/images/4.jpg and b/auction/static/images/4.jpg differ diff --git a/auction/templates/home_page.html b/auction/templates/home_page.html index c706c20..a8c7e05 100644 --- a/auction/templates/home_page.html +++ b/auction/templates/home_page.html @@ -8,28 +8,38 @@
{% for item in items %} - {% if item.sold == False %} -
+ {% if item.sold == False %} + {% if dt < item.auction_end %} +
- -
+ +
- - -
-
{{item.item_name}}
-
£{{item.start_bid}}
+ + +
+
{{item.item_name}}
- {% for user in users %} - {% if user.id == item.user_id%} -

Added by {{user.username}} on {{item.date_only}}

+ + {% if item.current_bid == 0 %} +
£{{item.price}}
+ {% else%} +
Current bid: £{{item.current_bid}}
{% endif %} - {% endfor %} - More information + + {% for user in users %} + {% if user.id == item.user_id%} +

Added by {{user.username}} on {{item.date.strftime("%d/%m/%Y")}}

+ {% endif %} + {% endfor %} + + + More information +
-
+ {% endif %} {% endif %} {% endfor %}
diff --git a/auction/templates/my_items.html b/auction/templates/my_items.html index fcbb3af..5ffca24 100644 --- a/auction/templates/my_items.html +++ b/auction/templates/my_items.html @@ -24,8 +24,8 @@ but just displays the items the current user has up for sale -->
{{item.item_name}} Sold
-
£{{item.start_bid}}
-

Added on {{item.date_only}}

+
Sold for: £{{item.current_bid}}
+

Added on {{item.date.strftime("%d/%m/%Y")}}

+ + {% elif dt > item.auction_end %} + +
{{item.item_name}} Expired
+ {% if item.current_bid > 0 %} +

Mark as sold to continue

+ Mark as sold + + {% elif item.current_bid == 0 %} +

Item did not sell

+ Delete item + {% endif %} {% else %}
{{item.item_name}}
-
£{{item.start_bid}}
-

Added on {{item.date_only}}

+ + {% if item.current_bid == 0 %} +
£{{item.price}}
+ {% else%} +
Current bid: £{{item.current_bid}}
+ {% endif %} + +

Added on {{item.date.strftime("%d/%m/%Y")}}

- +
£
- +