From 1c8c39eb2cbe945c458db56988096f44ed0c6e74 Mon Sep 17 00:00:00 2001 From: dsantoli Date: Tue, 7 May 2024 13:21:27 -0400 Subject: [PATCH] Add Project5 --- .../__pycache__/passwords.cpython-312.pyc | Bin 0 -> 1711 bytes Project5/__pycache__/quotes.cpython-312.pyc | Bin 0 -> 9927 bytes Project5/app.log | 32 +++ Project5/create-quotes-db.py | 26 ++ Project5/passwords.py | 30 +++ Project5/quotes.py | 223 ++++++++++++++++++ Project5/start.sh | 8 + Project5/static/css/styles.css | 111 +++++++++ Project5/templates/add_quote.html | 54 +++++ Project5/templates/edit_quote.html | 55 +++++ Project5/templates/login.html | 48 ++++ Project5/templates/quotes.html | 73 ++++++ Project5/templates/register.html | 44 ++++ 13 files changed, 704 insertions(+) create mode 100644 Project5/__pycache__/passwords.cpython-312.pyc create mode 100644 Project5/__pycache__/quotes.cpython-312.pyc create mode 100644 Project5/app.log create mode 100644 Project5/create-quotes-db.py create mode 100644 Project5/passwords.py create mode 100644 Project5/quotes.py create mode 100644 Project5/start.sh create mode 100644 Project5/static/css/styles.css create mode 100644 Project5/templates/add_quote.html create mode 100644 Project5/templates/edit_quote.html create mode 100644 Project5/templates/login.html create mode 100644 Project5/templates/quotes.html create mode 100644 Project5/templates/register.html diff --git a/Project5/__pycache__/passwords.cpython-312.pyc b/Project5/__pycache__/passwords.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f8228a6740426bf3371470dc4c7102b06f48b931 GIT binary patch literal 1711 zcmah}K~Eb;6rS0gwN1AM3dyFVRxv0Ati)D<1X5H1DWr!InM0^jQA;bcyI>pawRVVZAn2w+sgB^(RBW^PhzM)_U+ zekezpp$m)6a&XCoJgc?p!tdgq(D1$cRB#!U@g@XwatrBMI`MIW9rmKRcF$_9Wx+>^ zWij_oYsa&^id0CMl<~6g5XGdVi(W?o5W_BBJ(t$)<@nuLn@e(Lw%`V=bU`=sZcxjZ zS${8B$GUviBmEeX^Cg-V{iPY!RuxLuB>4Ke_HMRA;QLt%h z?tXGXeK0?B??J5tWPj;J_eXVkqB?tYt#^lPRSuO~j&f`F zQC+!Hoj>mC*-mUFc6#ew!_~PXrSDL==_ohrO1wIMBwv3zTa%+T5_!N=KQW>*h0+I+xi$P<=Vg$4p_pA=4 zI$1PeF{-&&Y5FT@*`>}|T@2UF)D@<#f}(6hcsHY#0;b!pWejcA=YsVf1ldV+5)_mj z>Uv}A+e0PcD2d&Tx-$O1b*;TW>d2!tGHSgGDKz-`!urVz`v(}?$o31`Dq{*Jw1O(Q zRm?K-3TOK>zmBNz8T#%b%5TIQP=2v>fzA6Ky90Rl zB(^(LkBmB`r#k;+;aKi?(ovVA&t@EX&>@4&CqGU6+U>{@heVF$o~Hvlz57?{^4Rka z4&*6^OtIL|&eZ6BdM)q%rC*o8(4}F|B_4PGl(i#9P>n)uCbs}PnU!nF_C=B0I tBH_N%PJ(ZrwoCXPKIuf{?Z=x3V$VwweL?zPlD5Z#KO|2iM6UDP{{r+@b!h+q literal 0 HcmV?d00001 diff --git a/Project5/__pycache__/quotes.cpython-312.pyc b/Project5/__pycache__/quotes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37494fdddffc66884c80b9de775f900aaf546717 GIT binary patch literal 9927 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", methods=["GET"]) +def get_edit(id=None): + session_id = request.cookies.get("session_id", None) + if not session_id: + response = redirect("/login") + return response + if id: + # open the quotes collection + quotes_collection = quotes_db.quotes_collection + # get the item + data = quotes_collection.find_one({"_id": ObjectId(id)}) + data["id"] = str(data["_id"]) + return render_template("edit_quote.html", data=data) + # return to the quotes page + return redirect("/quotes") + + +@app.route("/edit", methods=["POST"]) +def post_edit(): + session_id = request.cookies.get("session_id", None) + if not session_id: + response = redirect("/login") + return response + _id = request.form.get("_id", None) + text = request.form.get("text", "") + author = request.form.get("author", "") + if _id: + # open the quotes collection + quotes_collection = quotes_db.quotes_collection + # update the values in this particular record + values = {"$set": {"text": text, "author": author}} + data = quotes_collection.update_one({"_id": ObjectId(_id)}, values) + # do a redirect('....') + return redirect("/quotes") + + +@app.route("/delete", methods=["GET"]) + +@app.route("/delete/", methods=["GET"]) +def get_delete(id=None): + session_id = request.cookies.get("session_id", None) + if not session_id: + response = redirect("/login") + return response + if id: + # open the quotes collection + quotes_collection = quotes_db.quotes_collection + # delete the item + quotes_collection.delete_one({"_id": ObjectId(id)}) + # return to the quotes page + return redirect("/quotes") + +# ADDED ROUTE FOR REGISTER +@app.route("/register", methods=["GET", "POST"]) +def register(): + if request.method == "POST": + app.logger.info("register button hit") + username = request.form["username"] + password = request.form["password"] + # Check if the username is already taken + if user_collection.find_one({"user": username}): + flash("Username already taken. Please choose a different username.", "error") + return redirect("/register") + # Hash the password before storing it + hashed_password, salt = hash_password(password) + # Store the username, hashed password, and salt in the user collection + user_data = {"user": username, "hashed_password": hashed_password, "salt": salt} + user_collection.insert_one(user_data) + flash("Registration successful. Please log in.", "success") + + # Log all entries in the user collection to the log file + app.logger.info("All entries in the user collection:") + for entry in user_collection.find(): + app.logger.info(entry) + + return redirect("/login") + return render_template("register.html") \ No newline at end of file diff --git a/Project5/start.sh b/Project5/start.sh new file mode 100644 index 0000000..7627930 --- /dev/null +++ b/Project5/start.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# Set environment variables +export FLASK_APP=quotes.py +export FLASK_ENV=development + +# Start the Flask development server +python -m flask run diff --git a/Project5/static/css/styles.css b/Project5/static/css/styles.css new file mode 100644 index 0000000..c69a21d --- /dev/null +++ b/Project5/static/css/styles.css @@ -0,0 +1,111 @@ +/* styles.css */ +body { + font-family: Arial, sans-serif; + background-color: #f4f4f4; + margin: 0; + padding: 0; +} + +.container { + max-width: 400px; + margin: 50px auto; + padding: 20px; + background-color: #fff; + border-radius: 5px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +h1 { + text-align: center; + margin-bottom: 20px; + color: #333; +} + +label { + display: block; + margin-bottom: 5px; + font-weight: bold; + color: #555; +} + +input[type="text"], +input[type="password"], +button { + width: 100%; + padding: 10px; + margin-bottom: 10px; + border: 1px solid #ccc; + border-radius: 3px; +} + +button { + background-color: #007bff; + color: #fff; + border: none; + cursor: pointer; +} + +button:hover { + background-color: #0056b3; +} + +a { + display: block; + text-align: center; + margin-top: 20px; + color: #007bff; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +.login-links, .register-link { + text-align: center; + margin-top: 20px; +} + +.login-links, .register-link p { + display: inline; + margin-right: 10px; +} + +.login-links, .register-link a { + color: #007bff; + text-decoration: none; +} + +.login-links, .register-link a:hover { + text-decoration: underline; +} + + +/* stying for flash messages */ +.flash-message { + padding: 10px; + margin-bottom: 10px; + border-radius: 5px; + color: white; + font-weight: bold; + width: 100%; + text-align: center; + transition: opacity 0.5s ease-in-out; +} + +.flash-error { + background-color: #dc3545; +} + +.flash-success { + background-color: #28a745; +} + +.fade-out { + animation: fadeOut 10s ease-in-out forwards; +} + +@keyframes fadeOut { + 0% { opacity: 1; } + 100% { opacity: 0; } +} \ No newline at end of file diff --git a/Project5/templates/add_quote.html b/Project5/templates/add_quote.html new file mode 100644 index 0000000..939ec5c --- /dev/null +++ b/Project5/templates/add_quote.html @@ -0,0 +1,54 @@ + + + + + + + Add a Quote + + + + +
+

Add a Quote

+
+
+ + +
+
+ + +
+ + Cancel +
+
+ + \ No newline at end of file diff --git a/Project5/templates/edit_quote.html b/Project5/templates/edit_quote.html new file mode 100644 index 0000000..2607101 --- /dev/null +++ b/Project5/templates/edit_quote.html @@ -0,0 +1,55 @@ + + + + + + + Edit Quote + + + + +
+

Edit this Quote

+
+ +
+ + +
+
+ + +
+ + Cancel +
+
+ + \ No newline at end of file diff --git a/Project5/templates/login.html b/Project5/templates/login.html new file mode 100644 index 0000000..c4d4880 --- /dev/null +++ b/Project5/templates/login.html @@ -0,0 +1,48 @@ + + + + + + + + Login + + + + + {% with messages = get_flashed_messages() %} + {% if messages %} +
+
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+
+ + {% endif %} + {% endwith %} +
+

Login

+
+ + + + + +
+ +
+ + + \ No newline at end of file diff --git a/Project5/templates/quotes.html b/Project5/templates/quotes.html new file mode 100644 index 0000000..cc34634 --- /dev/null +++ b/Project5/templates/quotes.html @@ -0,0 +1,73 @@ + + + + + + + Quotes + + + + + +
+

Quotes

+ + + + + + + + + + + {% for item in data %} + + + + + + + {% endfor %} + +
OwnerQuoteAuthorActions
{{ item["owner"] }}{{ item["text"] }}{{ item["author"] }} + edit + delete +
+ +
+

User: {{ user }} (Logout)

+
+ + \ No newline at end of file diff --git a/Project5/templates/register.html b/Project5/templates/register.html new file mode 100644 index 0000000..8bf058b --- /dev/null +++ b/Project5/templates/register.html @@ -0,0 +1,44 @@ + + + + + + + Register + + + + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
+ {% for category, message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+ + {% endif %} + {% endwith %} +
+

Register

+
+ + + + + +
+ +
+ + \ No newline at end of file