commit 8e7cefdab1edff77c4543264942e991fec58f0bb Author: The-Tysonator Date: Tue Apr 25 12:36:42 2023 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc6664a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_STORE +venv/ \ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 0000000..22e96c8 --- /dev/null +++ b/database.py @@ -0,0 +1,19 @@ +# Imports +from flask_sqlalchemy import SQLAlchemy + +# Database +database = SQLAlchemy() + +# User +class User ( database.Model ): + id = database.Column(database.Integer, primary_key = True) + username = database.Column(database.String, nullable = False, unique = True) + password = database.Column(database.String, nullable = False) + memes = database.relationship("Meme", lazy = "dynamic") + +# Meme +class Meme ( database.Model ): + id = database.Column(database.Integer, primary_key = True) + user = database.Column(database.String, database.ForeignKey("user.username"), nullable = False) + title = database.Column(database.String, nullable = False) + image = database.Column(database.String, nullable = False, unique = True) \ No newline at end of file diff --git a/db.sqlite b/db.sqlite new file mode 100644 index 0000000..c21a02d Binary files /dev/null and b/db.sqlite differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..fddd931 --- /dev/null +++ b/main.py @@ -0,0 +1,132 @@ + + + + + +from flask import Flask, render_template, request, redirect, session +from flask_bcrypt import Bcrypt +from database import database, User, Meme +import os + +app = Flask(__name__) + +app.secret_key = "secret" +app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///" + os.path.join(os.path.abspath(os.path.dirname(__file__)), 'db.sqlite') +database.init_app(app) +bcrypt = Bcrypt(app) + + +with app.app_context(): + database.create_all() + + + +def usernameValid ( username ): + # Allowed Characters + characters = "abcdefghijklmnopqrstuvwxyzABDEFGHIJKLMNOPQRSTUVWXYZ_0123456789" + + if len(username) < 4: + return False + + for char in username: + if not char in characters: + return False + + return True + +def passwordValid ( password ): + if len(password) < 1: + return False + return True + + + +@app.route("/") +def root (): + memes = database.session.execute(database.Select(Meme).order_by(Meme.id.desc())).all() + if session.get("username"): + return render_template("index.html", memes = memes, loggedIn = True) + else: + return render_template("index.html", memes = memes, loggedIn = False) + + +@app.route("/sign-up", methods = [ "GET", "POST"]) +def signUp (): + if session.get("username"): + return redirect("/") + if request.method == "GET": + return render_template("sign-up.html", loggedIn = False) + else: + if usernameValid(request.form.get("username")) and passwordValid(request.form.get("password")) and request.form.get("password") == request.form.get("repeatPassword"): + users = database.session.execute(database.select(User).filter_by(username=request.form.get("username"))).first() + if users == None: + database.session.add(User(username = request.form.get("username"), password = bcrypt.generate_password_hash(request.form.get("password")))) + database.session.commit() + return redirect("/sign-in") + return "Username taken" + else: + return "Invalid username and / or password" + + +@app.route("/sign-in", methods = [ "GET", "POST"]) +def signIn (): + if session.get("username"): + return redirect("/") + if request.method == "GET": + return render_template("sign-in.html", loggedIn = False) + else: + if usernameValid(request.form.get("username")) and passwordValid(request.form.get("password")): + print("val") + user = database.session.execute(database.select(User).filter_by(username=request.form.get("username"))).first() + if user != None: + if bcrypt.check_password_hash(user[0].password, request.form.get("password")): + session["username"] = request.form.get("username") + return redirect("/") + return render_template("sign-in.html", loggedIn = False) + +@app.route("/sign-out") +def signOut(): + if session.get("username"): + session.pop("username") + return redirect("/") + + +@app.route("/upload", methods = ["GET", "POST"]) +def upload (): + if session.get("username") == None: + return redirect("/") + if request.method == "GET": + return render_template("upload.html", loggedIn = True) + else: + + if request.files.get("image").filename.split(".")[-1] in ["png", "jpg", "jpeg", "webp"]: + + meme = database.session.execute(database.select(Meme).order_by(Meme.id.desc())).first() + if meme == None: + image_num = 1 + else: + image_num = meme[0].id + 1 + + database.session.add(Meme( user = session.get("username") ,title = request.form.get("title"), image = str(image_num) + ".png")) + database.session.commit() + request.files.get("image").save(os.path.join("./static/memes", str(image_num) + ".png")) + + + return redirect("/upload") + + return "oof" + + +@app.route("/user/") +def user ( name ): + user = database.session.execute(database.select(User).filter_by(username = name )).first() + if user != None: + memes = database.session.execute(database.select(Meme).filter_by(user=name).order_by(Meme.id.desc())).all() + if session.get("username"): + return render_template("user.html", username = user[0].username, memes = memes, loggedIn = True) + else: + return render_template("user.html", username = user[0].username, memes = memes, loggedIn = False) + else: + return "no user" + +app.run(debug=True) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e868b07 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +bcrypt==4.0.1 +click==8.1.3 +Flask==2.2.3 +Flask-Bcrypt==1.0.1 +Flask-SQLAlchemy==3.0.3 +importlib-metadata==6.6.0 +itsdangerous==2.1.2 +Jinja2==3.1.2 +MarkupSafe==2.1.2 +SQLAlchemy==2.0.10 +typing_extensions==4.5.0 +Werkzeug==2.2.3 +zipp==3.15.0 diff --git a/static/Writer-Regular.ttf b/static/Writer-Regular.ttf new file mode 100644 index 0000000..51569ff Binary files /dev/null and b/static/Writer-Regular.ttf differ diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..2636dc1 Binary files /dev/null and b/static/logo.png differ diff --git a/static/main.css b/static/main.css new file mode 100644 index 0000000..5ab0451 --- /dev/null +++ b/static/main.css @@ -0,0 +1,143 @@ + +* { + margin: 0; + padding: 0; + text-decoration: none; +} + +body { + background: rgb(33, 33, 33); +} + + +@font-face { + font-family: Writer-Regular; + src: url(/static/Writer-Regular.ttf); +} + +nav { + width: 100vw; + display: flex; + justify-content: center; + align-items: center; + background-color: rgb(17, 17, 17); +} + +.navLogo { + width: 30%; + display: flex; + justify-content: center; + align-items: center; +} +.navLinks { + width: 30%; + display: flex; + justify-content: center; + align-items: center; + + font-family: Writer-Regular; + font-size: 16px; + +} +.navLinks a { + margin: 20px; + color: white; +} + +.memes { + width: 100vw; + height: fit-content; + + display: flex; + flex-direction: column; + justify-content: start; + align-items: center; + + background: rgb(33, 33, 33); +} + + +.meme { + width: 90%; + max-width: 800px; + + display: flex; + flex-direction: column; + + + background: linear-gradient(135deg, rgba(50, 50, 50, 0.4), rgba(55, 55, 55, 0.4)); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border-radius: 20px; + border:1px solid rgba(255, 255, 255, 0.18); + box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37); + + transition: linear 0.2s; + margin: 20px; + + overflow: hidden; + + font-family: Writer-Regular; + font-size: 18px; +} + +.meme h1 { + color: white; + margin: 10px; +} + +.meme h1 a { + color: white; + text-decoration: underline; +} + +.meme img { + aspect-ratio: 1 / 1; +} + +@media screen and (max-width: 1800px) { + nav { + flex-direction: column; + } + .navLogo, .navLinks { + width: 100%; + } +} + +@media screen and (max-width: 600px) { + .navLinks { + flex-direction: column; + } +} + + +.userTitle { + width: 100vw; + background: rgb(33, 33, 33); + color: white; + font-family: Writer-Regular; + display: flex; + justify-content: center; + padding: 20px; + padding-bottom: 10px; +} + +.uploadFormDiv { + padding: 10px; + background: rgb(33, 33, 33); + display: flex; + justify-content: center; + align-items: center; +} + +.uploadFormDiv form { + display: flex; + flex-direction: column; + color: white; + width: 90%; + max-width: 600px; +} + +.uploadFormDiv form input { + padding: 10px 20px; +} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..57f0684 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,66 @@ + + + + + + + Document + + + + + + + + +
+ + {% for meme in memes %} +
+

{{ meme[0].title }} by {{ meme[0].user}}

+ +
+ {% endfor %} + +
+ + + + + + + \ No newline at end of file diff --git a/templates/sign-in.html b/templates/sign-in.html new file mode 100644 index 0000000..a86040c --- /dev/null +++ b/templates/sign-in.html @@ -0,0 +1,44 @@ + + + + + + + Document + + + + + + +

Sign In

+ +
+
+ + + +
+
+ + + \ No newline at end of file diff --git a/templates/sign-up.html b/templates/sign-up.html new file mode 100644 index 0000000..ef34f30 --- /dev/null +++ b/templates/sign-up.html @@ -0,0 +1,45 @@ + + + + + + + Document + + + + + + +

Sign Up

+ +
+
+ + + + +
+
+ + + \ No newline at end of file diff --git a/templates/upload.html b/templates/upload.html new file mode 100644 index 0000000..987ada0 --- /dev/null +++ b/templates/upload.html @@ -0,0 +1,45 @@ + + + + + + + Document + + + + + + +

Upload

+ +
+
+ + + +
+
+ + + + \ No newline at end of file diff --git a/templates/user.html b/templates/user.html new file mode 100644 index 0000000..1c77a8e --- /dev/null +++ b/templates/user.html @@ -0,0 +1,64 @@ + + + + + + + Document + + + + + + +

{{ username }}'s Memes

+ +
+ + {% for meme in memes %} +
+

{{ meme[0].title }}

+ +
+ {% endfor %} + +
+ + + + + \ No newline at end of file