diff --git a/backend/README.md b/backend/README.md index 0fc2bd1..07ea60b 100644 --- a/backend/README.md +++ b/backend/README.md @@ -16,6 +16,7 @@ pip install flask-sqlalchemy pip install flask-migrate pip install flask-login pip install email-validator +pip install pydenticon ... pip freeze > requirements.txt ``` diff --git a/backend/app/models.py b/backend/app/models.py index 36cbb11..36c70a5 100644 --- a/backend/app/models.py +++ b/backend/app/models.py @@ -1,9 +1,12 @@ +import os from datetime import datetime, timezone from typing import Optional import sqlalchemy as sa import sqlalchemy.orm as so -from app import db, login from werkzeug.security import generate_password_hash, check_password_hash +import pydenticon, hashlib, base64 + +from app import db, login from flask_login import UserMixin class User(UserMixin, db.Model): @@ -17,6 +20,33 @@ class User(UserMixin, db.Model): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) + def gen_avatar(self, write_png=True): + foreground = [ "rgb(45,79,255)", + "rgb(254,180,44)", + "rgb(226,121,234)", + "rgb(30,179,253)", + "rgb(232,77,65)", + "rgb(49,203,115)", + "rgb(141,69,170)" ] + background = "rgb(22,22,22)" + + digest = hashlib.md5(self.email.lower().encode('utf-8')).hexdigest() + basedir = os.path.abspath(os.path.dirname(__file__)) + pngloc = os.path.join(basedir, 'usercontent', 'identicon', str(digest) + '.png') + icongen = pydenticon.Generator(5, 5, digest=hashlib.md5, foreground=foreground, background=background) + pngicon = icongen.generate(self.email, 120, 120, padding=(10, 10, 10, 10), inverted=False, output_format="png") + if write_png: + pngfile = open(pngloc, "wb") + pngfile.write(pngicon) + pngfile.close() + else: + return str(base64.b64encode(pngicon))[2:-1] + def avatar(self): + digest = hashlib.md5(self.email.lower().encode('utf-8')).hexdigest() + basedir = os.path.abspath(os.path.dirname(__file__)) + pngloc = os.path.join(basedir, 'usercontent', 'identicon', digest + '.png') + return pngloc + def __repr__(self): return ''.format(self.username) diff --git a/backend/app/routes.py b/backend/app/routes.py index 72d750a..e301aaf 100644 --- a/backend/app/routes.py +++ b/backend/app/routes.py @@ -57,8 +57,17 @@ def register(): user.set_password(form.password.data) db.session.add(user) db.session.commit() + user.gen_avatar() flash('User has been created.') return redirect(url_for('login')) return render_template('register.html', title='Register', form=form) - +@app.route('/user/') +@login_required +def user(username): + user = db.first_or_404(sa.select(User).where(User.username == username)) + posts = [ + {'author': user, 'body': 'Test1'}, + {'author': user, 'body': 'Test2?'} + ] + return render_template('user.html', user=user, posts=posts) diff --git a/backend/app/templates/_post.html b/backend/app/templates/_post.html new file mode 100644 index 0000000..424bfc2 --- /dev/null +++ b/backend/app/templates/_post.html @@ -0,0 +1,6 @@ + + + + + +
{{ post.author.username }} says:
{{ post.body }}
diff --git a/backend/app/templates/base.html b/backend/app/templates/base.html index e83424e..1c5890a 100644 --- a/backend/app/templates/base.html +++ b/backend/app/templates/base.html @@ -15,6 +15,7 @@ {% if current_user.is_anonymous %} login {% else %} + Profile logout {% endif %} diff --git a/backend/app/templates/user.html b/backend/app/templates/user.html new file mode 100644 index 0000000..508579a --- /dev/null +++ b/backend/app/templates/user.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} + +{% block content %} + + + + + +

User: {{ user.username }}

+
+ {% for post in posts %} + {% include '_post.html' %} + {% endfor %} +{% endblock %} + diff --git a/backend/app/usercontent/identicon/39466ff4e782fc398fed2c3b21d53ba2.png b/backend/app/usercontent/identicon/39466ff4e782fc398fed2c3b21d53ba2.png new file mode 100644 index 0000000..0e771b0 Binary files /dev/null and b/backend/app/usercontent/identicon/39466ff4e782fc398fed2c3b21d53ba2.png differ diff --git a/backend/app/usercontent/identicon/686fed96bd36dc9ba0c0434036031942.png b/backend/app/usercontent/identicon/686fed96bd36dc9ba0c0434036031942.png new file mode 100644 index 0000000..88c2f58 Binary files /dev/null and b/backend/app/usercontent/identicon/686fed96bd36dc9ba0c0434036031942.png differ diff --git a/backend/app/usercontent/identicon/7a651a7bab949a73092e21ad0bd2f4a8.png b/backend/app/usercontent/identicon/7a651a7bab949a73092e21ad0bd2f4a8.png new file mode 100644 index 0000000..20f3c73 Binary files /dev/null and b/backend/app/usercontent/identicon/7a651a7bab949a73092e21ad0bd2f4a8.png differ diff --git a/backend/requirements.txt b/backend/requirements.txt index 98e3753..5020423 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -14,6 +14,8 @@ itsdangerous==2.2.0 Jinja2==3.1.4 Mako==1.3.5 MarkupSafe==2.1.5 +pillow==10.4.0 +pydenticon==0.3.1 python-dotenv==1.0.1 SQLAlchemy==2.0.31 typing_extensions==4.12.2