diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..e0cc78f06b30360d46f13d386fa3f27794c54a36 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +**/__pycache__ +**/.venv +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/bin +**/charts +**/docker-compose* +**/compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..26d33521af10bcc7fd8cea344038eaaeb78d0ef5 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/Flask.iml b/.idea/Flask.iml new file mode 100644 index 0000000000000000000000000000000000000000..f5d457693c58f177895a768759e7220d8299a336 --- /dev/null +++ b/.idea/Flask.iml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="PYTHON_MODULE" version="4"> + <component name="NewModuleRootManager"> + <content url="file://$MODULE_DIR$"> + <excludeFolder url="file://$MODULE_DIR$/.venv" /> + </content> + <orderEntry type="jdk" jdkName="Python 3.10 (Flask)" jdkType="Python SDK" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> + <component name="PyDocumentationSettings"> + <option name="format" value="PLAIN" /> + <option name="myDocStringFormat" value="Plain" /> + </component> +</module> \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..105ce2da2d6447d11dfe32bfb846c3d5b199fc99 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ +<component name="InspectionProjectProfileManager"> + <settings> + <option name="USE_PROJECT_PROFILE" value="false" /> + <version value="1.0" /> + </settings> +</component> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..bbe7b365d42ea46c621f795d43f29f93ff10119f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (Flask)" project-jdk-type="Python SDK" /> +</project> \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..71b84bca86f60d5d8a35db47a8f077e0cf2de41f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/Flask.iml" filepath="$PROJECT_DIR$/.idea/Flask.iml" /> + </modules> + </component> +</project> \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..35eb1ddfbbc029bcab630581847471d7f238ec53 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="" vcs="Git" /> + </component> +</project> \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..68bf174870fd950031c7088641521fd2edbab836 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,25 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python Debugger: Flask", + "type": "debugpy", + "request": "launch", + "module": "flask", + "env": { + "FLASK_APP": "app\\__init__.py", + "FLASK_DEBUG": "1" + }, + "args": [ + "run", + "--no-debugger", + "--no-reload" + ], + "jinja": true, + "autoStartBrowser": false + } + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 4f38856b2a7bd850fa0e38e7a65872bd92a6482c..ed092382bbf13387f018c1ded75670d15dba156f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,26 @@ -FROM python:3.10-alpine AS builder +# For more information, please refer to https://aka.ms/vscode-docker-python +FROM python:3-slim -COPY . /flask -WORKDIR ./flask +EXPOSE 5000 -RUN pip3 install --no-cache-dir -r requirements.txt +# Keeps Python from generating .pyc files in the container +ENV PYTHONDONTWRITEBYTECODE=1 + +# Turns off buffering for easier container logging +ENV PYTHONUNBUFFERED=1 + +# Install pip requirements +COPY requirements.txt . +RUN python -m pip install -r requirements.txt + +WORKDIR /app +COPY . /app + +# Creates a non-root user with an explicit UID and adds permission to access the /app folder +# For more info, please refer to https://aka.ms/vscode-docker-python-configure-containers +RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app +USER appuser + +# During debugging, this entry point will be overridden. For more information, please refer to https://aka.ms/vscode-docker-python-debug +CMD ["flask", "run", "--host=0.0.0.0", "--port=5000"] -ENV USE_RELOADER=true -ENV FLASK_APP=app:create_app -CMD ["flask", "run", "--host=0.0.0.0", "--port=5000"] \ No newline at end of file diff --git a/app/profile/routes.py b/app/profile/routes.py index 353072ab9601357c1dc3af7922a26acd298306a2..63f67bb4963029ffbb8c60a8ca4a528de1c7d8bd 100644 --- a/app/profile/routes.py +++ b/app/profile/routes.py @@ -1,38 +1,51 @@ #https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login#step-1-installing-packages from flask import Blueprint, render_template, redirect, url_for, request, flash from app.profile import bp -from werkzeug.security import generate_password_hash, check_password_hash +from werkzeug.security import check_password_hash from app.models import User from app import db from flask_login import login_user, logout_user, login_required, current_user +from app.logger import auth_logger @bp.route('/signup') def signup(): - return render_template(url_for('profile.signup')) + return render_template('profile/signup.html') @bp.route('/signup', methods=['POST']) def signup_post(): - email = request.form.get('email') - username = request.form.get('name') - password = request.form.get('password') + form_data = { + 'email': request.form.get('email'), + 'username': request.form.get('username'), + 'password': request.form.get('password') + } - user = User.query.filter_by(email=email).first() + user = User.query.filter_by(email=form_data['email']).first() if user: return redirect(url_for('profile.signup')) - new_user = User.create_user(username=username, email=email, password=password) + try: + if not form_data['username'] or not form_data['email'] or not form_data['password']: + raise ValueError("Missing required fields: Email, Username, Password") + new_user = User.create_user(username=form_data['username'], email=form_data['email'], password=form_data['password']) + except ValueError as e: + auth_logger.error("Unable to create user, full error was: " + str(e)) + flash('Missing required fields') + return redirect(url_for('profile.signup')) db.session.add(new_user) db.session.commit() - return redirect(url_for('profile.login')) + # Log the user in automatically + login_user(new_user) + + return redirect(url_for('profile.index')) @bp.route('/login', methods=['POST']) def login_post(): email = request.form.get('email') password = request.form.get('password') - remember = True if request.form.get('remember') else False # If checkbox for user is ticked + remember = True if request.form.get('remember') else False # Change to boolean value depending if tickbox is selected user = User.query.filter_by(email=email).first() diff --git a/app/static/base.css b/app/static/base.css index fa23b772afbe97ae1ea88983c8b6f1d1bc074cbc..008b2e0d62339674cb5aa2f197002e7fe1a499ab 100644 --- a/app/static/base.css +++ b/app/static/base.css @@ -82,8 +82,38 @@ body { background-color: #90AEAD; } +/** +Form styling options +*/ + +.form_box_30 { + position: relative; + width: 100%; + max-width: 400px; /* Maximum width for larger screens */ + margin: auto; + vertical-align: middle; + padding: 15px; /* Add some padding */ +} + +@media (max-width: 600px) { + .form_box_30 { + width: 90%; /* Adjust width for smaller screens */ + } +} + +.background_1 { + border-radius: 25px; + background: #90AEAD; + padding: 50px; + color: #FBE9D0; + background-image: linear-gradient(to bottom right, #4169e1, #89CFF0); +} +.form-check-input:checked { + color: #FBE9D0; + background: #FBE9D0; +} /* HEX codes for colours used through out website don't delete */ diff --git a/app/templates/profile/login.html b/app/templates/profile/login.html index 2fb3775b99e98bcec744ce7c4ee98eb2ca34409a..130d7ef05531ea889a4da4f1c931e4406cfef4b3 100644 --- a/app/templates/profile/login.html +++ b/app/templates/profile/login.html @@ -1,28 +1,29 @@ {% extends 'base.html' %} {% block content %} <div class="column is-4 is-offset-4"> - <h3 class="title">Login</h3> - <div class="box"> - <form method="POST" action="{{ url_for ('profile.login_post')}}"> - <div class="field"> - <div class="control"> - <input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus=""> + <div id="login-box" class="form_box_30"> + <h3 style="margin-top:30px; text-align:center">Login</h3> + <div class="background_1"> + <form method="POST" action="{{ url_for('profile.login_post') }}"> + <div class="mb-3"> + <label class="form-label" autofocus="">Username</label> + <input type="text" class="form-control" name="username"> </div> - </div> - - <div class="field"> - <div class="control"> - <input class="input is-large" type="password" name="password" placeholder="Your Password"> + <div class="mb-3"> + <label class="form-label">Email address</label> + <input type="email" class="form-control" name="email"> </div> - </div> - <div class="field"> - <label class="checkbox"> - <input type="checkbox" name="remember"> - Remember me - </label> - </div> - <button class="button is-block is-info is-large is-fullwidth">Login</button> - </form> + <div class="mb-3"> + <label for="exampleInputPassword1" class="form-label">Password</label> + <input type="password" class="form-control" name="password"> + </div> + <div class="mb-3 form-check"> + <input type="checkbox" class="form-check-input" id="remember" name="remember"> + <label class="form-check-label" for="remember">Remember me</label> + </div> + <button type="submit" class="btn btn-primary">Log In</button> + </form> + </div> </div> </div> {% endblock %} \ No newline at end of file diff --git a/app/templates/profile/signup.html b/app/templates/profile/signup.html index 8966ed18d057b3f3d271006143304db8a90c78ec..a7ef4e83f04fd94c80ebb7a1ea37f26cb82dfaaf 100644 --- a/app/templates/profile/signup.html +++ b/app/templates/profile/signup.html @@ -1,30 +1,27 @@ {% extends 'base.html' %} {% block content %} -<div class="column is-4 is-offset-4"> - <h3 class="title">Sign Up</h3> - <div class="box"> - <form method="POST" action="/signup"> - <div class="field"> - <div class="control"> - <input class="input is-large" type="email" name="email" placeholder="Email" autofocus=""> - </div> + <div class="form_box_30 background_1"> + <h3 style="margin-top:30px">Sign Up</h3> + <form method="POST" action="{{ url_for('profile.signup_post') }}"> + <div class="mb-3"> + <label class="form-label" autofocus="">Username</label> + <input type="username" class="form-control" name="username"> </div> - - <div class="field"> - <div class="control"> - <input class="input is-large" type="text" name="name" placeholder="Name" autofocus=""> - </div> + <div class="mb-3"> + <label class="form-label">Email address</label> + <input type="email" class="form-control" name="email"> </div> - - <div class="field"> - <div class="control"> - <input class="input is-large" type="password" name="password" placeholder="Password"> - </div> + <div class="mb-3"> + <label class="form-label">Password</label> + <input type="password" class="form-control" name="password"> </div> - - <button class="button is-block is-info is-large is-fullwidth">Sign Up</button> - </form> + <div class="mb-3 form-check"> + <input type="checkbox" class="form-check-input" id="remember" name="remember"> + <label class="form-check-label" for="remember">Remember me</label> + </div> + <button type="submit" class="btn btn-primary">Log In</button> + </form> </div> -</div> + {% endblock %} \ No newline at end of file diff --git a/app/uploads/listing_images/2.jpg b/app/uploads/listing_images/2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0a1c1206a55aa6127782399d2eb8bfb401f7029 Binary files /dev/null and b/app/uploads/listing_images/2.jpg differ diff --git a/docker-compose.debug.yml b/docker-compose.debug.yml new file mode 100644 index 0000000000000000000000000000000000000000..37266e1587647cb918710f1eefd82e3dc78016d1 --- /dev/null +++ b/docker-compose.debug.yml @@ -0,0 +1,43 @@ +version: '3.4' + +services: + flask: + image: flask + build: + context: . + dockerfile: ./Dockerfile + command: ["sh", "-c", "pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 -m flask run --no-debugger --no-reload --host 0.0.0.0 --port 5000"] + ports: + - 5000:5000 + - 5678:5678 + depends_on: + - database + networks: + - network + environment: + DEVELOPMENT_MODE: ${DEVELOPMENT_MODE} + DATABASE_HOST: ${DATABASE_HOST} + DATABASE_USER: ${DATABASE_USER} + DATABASE_PASSWORD: ${DATABASE_PASSWORD} + DATABASE_NAME: ${DATABASE_NAME} + FLASK_APP: app\__init__.py + database: + image: mysql:8.0 + ports: + - '3306:3306' + environment: + MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD} + MYSQL_DATABASE: ${DATABASE_NAME} + MYSQL_USER: ${DATABASE_USER} + MYSQL_PASSWORD: ${DATABASE_PASSWORD} + volumes: + - mysql_data:/var/lib/mysql + networks: + - network + +volumes: + mysql_data: + +networks: + network: + driver: bridge diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..f028cec80dd4b1a1560548f1b6dffecc0a5bff3a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3.4' + +services: + flask: + image: flask + build: + context: . + dockerfile: ./Dockerfile + ports: + - 5000:5000 diff --git a/requirements.txt b/requirements.txt index 4f3f85f1d8d7d5ec772e492d7f01d8d5e6bdf228..619304637acfffb56b3620f7b5474dc948294fc8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ pymysql python-dotenv jinja2 cryptography -flask-login \ No newline at end of file +flask-login +debugpy \ No newline at end of file