mgt c6 checkpoint 2.2

This commit is contained in:
finn 2024-08-03 04:59:05 -07:00
parent cdebe081c3
commit 2b122f6ab2
11 changed files with 100 additions and 55 deletions

View File

@ -28,6 +28,13 @@ flask db upgrade
flask db downgrade [base]
flask db upgrade
full reset?
rm app.db
rm -r migrations
flask db init
flask db migrate
flask db upgrade
```
## build notes:

View File

@ -1,6 +1,6 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, ValidationError, Email, EqualTo
from wtforms import StringField, PasswordField, BooleanField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, ValidationError, Email, EqualTo, Length
import sqlalchemy as sa
from app import db
from app.models import User
@ -27,3 +27,8 @@ class RegistrationForm(FlaskForm):
user = db.session.scalar(sa.select(User).where(User.email == email.data))
if user is not None:
raise ValidationError('Please use a different email address.')
class EditProfileForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
about_me = TextAreaField('About me', validators=[Length(min=0, max=140)])
submit = SubmitField('Update')

View File

@ -15,6 +15,8 @@ class User(UserMixin, db.Model):
email: so.Mapped[str] = so.mapped_column(sa.String(120), index=True, unique=True)
password_hash: so.Mapped[Optional[str]] = so.mapped_column(sa.String(256))
posts: so.WriteOnlyMapped['Post'] = so.relationship(back_populates='author')
about_me: so.Mapped[Optional[str]] = so.mapped_column(sa.String(140))
last_seen: so.Mapped[Optional[datetime]] = so.mapped_column(default=lambda: datetime.now(timezone.utc))
def set_password(self, password):
self.password_hash = generate_password_hash(password)
@ -41,7 +43,7 @@ class User(UserMixin, db.Model):
pngfile.close()
else:
return str(base64.b64encode(pngicon))[2:-1]
def avatar(self):
def avatar_path(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')

View File

@ -1,9 +1,11 @@
from flask import render_template, flash, redirect, url_for, request
from urllib.parse import urlsplit
from datetime import datetime, timezone
from app import app, db
from app.forms import LoginForm, RegistrationForm
from flask_login import current_user, login_user, logout_user, login_required
from app.forms import LoginForm, RegistrationForm, EditProfileForm
import sqlalchemy as sa
from flask_login import current_user, login_user, logout_user, login_required
from app.models import User
@app.route('/')
@ -25,6 +27,12 @@ def index():
#return posts;
return render_template('index.html', title='Home', posts=posts)
@app.before_request
def before_request():
if current_user.is_authenticated:
current_user.last_seen = datetime.now(timezone.utc)
db.session.commit()
@app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
@ -57,7 +65,7 @@ def register():
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
user.gen_avatar()
#user.gen_avatar()
flash('User has been created.')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)
@ -71,3 +79,19 @@ def user(username):
{'author': user, 'body': 'Test2?'}
]
return render_template('user.html', user=user, posts=posts)
@app.route('/edit_profile', methods=['GET', 'POST'])
@login_required
def edit_profile():
form = EditProfileForm()
if form.validate_on_submit():
current_user.username = form.username.data
current_user.about_me = form.about_me.data
db.session.commit()
flash('Profile changes have been saved.')
return redirect(url_for('edit_profile'))
elif request.method == 'GET':
form.username.data = current_user.username
form.about_me.data = current_user.about_me()
return render_template('edit_profile.html', title='Edit Profile', form=form)

View File

@ -0,0 +1,24 @@
{% extends "base.html" %}
{% block content %}
<h1>Edit Profile</h1>
<form action="" method="post">
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}
{{ form.username(size=32) }}
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.about_me.label }}
{{ form.about_me(cols=50, rows=4) }}
{% for error in form.about_me.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>{{ form.submit }}</p>
</form>
{% endblock %}

View File

@ -4,9 +4,16 @@
<table>
<tr valign="top">
<td><img src="data:image/png;base64,{{ user.gen_avatar(write_png=False) }}"></td>
<td><h1>User: {{ user.username }}</h1></td>
<td>
<h1>User: {{ user.username }}</h1>
{% if user.about_me %}<p>{{ user.about_me }}</p>{% endif %}
{% if user.last_seen %}<p>Last activity:{{ user.last_seen }}</p>{% endif %}
</td>
</tr>
</table>
{% if user == current_user() %}
<p><a href="{{ url_for('edit_profile') }}">Edit Profile</a></p>
{% endif %}
<hr>
{% for post in posts %}
{% include '_post.html' %}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 B

View File

@ -1,8 +1,8 @@
"""posts table
"""empty message
Revision ID: 938ae2fee021
Revises: e42cf202d424
Create Date: 2024-08-01 06:11:07.414657
Revision ID: 1a0e4f823e90
Revises:
Create Date: 2024-08-03 04:56:53.822820
"""
from alembic import op
@ -10,14 +10,27 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '938ae2fee021'
down_revision = 'e42cf202d424'
revision = '1a0e4f823e90'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=64), nullable=False),
sa.Column('email', sa.String(length=120), nullable=False),
sa.Column('password_hash', sa.String(length=256), nullable=True),
sa.Column('about_me', sa.String(length=140), nullable=True),
sa.Column('last_seen', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.create_index(batch_op.f('ix_user_email'), ['email'], unique=True)
batch_op.create_index(batch_op.f('ix_user_username'), ['username'], unique=True)
op.create_table('post',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('body', sa.String(length=140), nullable=False),
@ -40,4 +53,9 @@ def downgrade():
batch_op.drop_index(batch_op.f('ix_post_timestamp'))
op.drop_table('post')
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.drop_index(batch_op.f('ix_user_username'))
batch_op.drop_index(batch_op.f('ix_user_email'))
op.drop_table('user')
# ### end Alembic commands ###

View File

@ -1,42 +0,0 @@
"""users table
Revision ID: e42cf202d424
Revises:
Create Date: 2024-08-01 05:46:32.176166
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'e42cf202d424'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=64), nullable=False),
sa.Column('email', sa.String(length=120), nullable=False),
sa.Column('password_hash', sa.String(length=256), nullable=True),
sa.PrimaryKeyConstraint('id')
)
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.create_index(batch_op.f('ix_user_email'), ['email'], unique=True)
batch_op.create_index(batch_op.f('ix_user_username'), ['username'], unique=True)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.drop_index(batch_op.f('ix_user_username'))
batch_op.drop_index(batch_op.f('ix_user_email'))
op.drop_table('user')
# ### end Alembic commands ###