diff --git a/app/forms.py b/app/forms.py index 299e943..da32ce2 100644 --- a/app/forms.py +++ b/app/forms.py @@ -1,6 +1,8 @@ from flask_wtf import FlaskForm -from wtforms import StringField, PasswordField, BooleanField, SubmitField -from wtforms.validators import ValidationError, DataRequired, Email, EqualTo +from wtforms import StringField, PasswordField, BooleanField, SubmitField, \ + TextAreaField +from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, \ + Length from app.models import User @@ -28,3 +30,9 @@ class RegistrationForm(FlaskForm): user = User.query.filter_by(email=email.data).first() 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('Submit') diff --git a/app/models.py b/app/models.py index e5abb24..3520110 100644 --- a/app/models.py +++ b/app/models.py @@ -1,4 +1,5 @@ from datetime import datetime +from hashlib import md5 from app import db, login from flask_login import UserMixin from werkzeug.security import generate_password_hash, check_password_hash @@ -10,6 +11,8 @@ class User(UserMixin, db.Model): email = db.Column(db.String(120), index=True, unique=True) password_hash = db.Column(db.String(128)) posts = db.relationship('Post', back_populates='author', lazy='dynamic') + about_me = db.Column(db.String(140)) + last_seen = db.Column(db.DateTime, default=datetime.utcnow) def __repr__(self): return ''.format(self.username) @@ -20,6 +23,10 @@ class User(UserMixin, db.Model): def check_password(self, password): return check_password_hash(self.password_hash, password) + def avatar(self, size): + digest = md5(self.email.lower().encode('utf-8')).hexdigest() + return f'https://www.gravatar.com/avatar/{digest}?d=identicon&s={size}' + @login.user_loader def load_user(id): diff --git a/app/routes.py b/app/routes.py index 96689df..76a502f 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,11 +1,19 @@ +from datetime import datetime from flask import render_template, flash, redirect, url_for, request from flask_login import login_user, logout_user, current_user, login_required from werkzeug.urls import url_parse from app import app, db -from app.forms import LoginForm, RegistrationForm +from app.forms import LoginForm, RegistrationForm, EditProfileForm from app.models import User +@app.before_request +def before_request(): + if current_user.is_authenticated: + current_user.last_seen = datetime.utcnow() + db.session.commit() + + @app.route('/') @app.route('/index') @login_required @@ -60,3 +68,31 @@ def register(): flash('Congratulations, you are now a registered user!') return redirect(url_for('login')) return render_template('register.html', title='Register', form=form) + + +@app.route('/user/') +@login_required +def user(username): + user = User.query.filter_by(username=username).first_or_404() + posts = [ + {'author': user, 'body': 'Test post #1'}, + {'author': user, 'body': 'Test post #2'} + ] + 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('Your 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) diff --git a/app/templates/_post.html b/app/templates/_post.html new file mode 100644 index 0000000..d020426 --- /dev/null +++ b/app/templates/_post.html @@ -0,0 +1,6 @@ + + + + + +
{{ post.author.username }} says:
{{ post.body }}
diff --git a/app/templates/base.html b/app/templates/base.html index 496ea6d..f787db1 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -14,6 +14,7 @@ {% if current_user.is_anonymous %} Login {% else %} + Profile Logout {% endif %} diff --git a/app/templates/edit_profile.html b/app/templates/edit_profile.html new file mode 100644 index 0000000..e2471ac --- /dev/null +++ b/app/templates/edit_profile.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block content %} +

Edit Profile

+
+ {{ form.hidden_tag() }} +

+ {{ form.username.label }}
+ {{ form.username(size=32) }}
+ {% for error in form.username.errors %} + [{{ error }}] + {% endfor %} +

+

+ {{ form.about_me.label }}
+ {{ form.about_me(cols=50, rows=4) }}
+ {% for error in form.about_me.errors %} + [{{ error }}] + {% endfor %} +

+

{{ form.submit() }}

+
+{% endblock %} diff --git a/app/templates/user.html b/app/templates/user.html new file mode 100644 index 0000000..5bacb4e --- /dev/null +++ b/app/templates/user.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} + +{% block content %} + + + + + +
+

User: {{ user.username }}

+ {% if user.about_me %}

{{ user.about_me }}

{% endif %} + {% if user.last_seen %}

Last seen on: {{ user.last_seen }}

{% endif %} + {% if user == current_user %} +

Edit your profile

+ {% endif %} +
+
+ {% for post in posts %} + {% include '_post.html' %} + {% endfor %} +{% endblock %} diff --git a/migrations/versions/37f06a334dbf_new_fields_in_user_model.py b/migrations/versions/37f06a334dbf_new_fields_in_user_model.py new file mode 100644 index 0000000..d633a5b --- /dev/null +++ b/migrations/versions/37f06a334dbf_new_fields_in_user_model.py @@ -0,0 +1,34 @@ +"""new fields in user model + +Revision ID: 37f06a334dbf +Revises: 780739b227a7 +Create Date: 2017-09-14 10:54:13.865401 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '37f06a334dbf' +down_revision = '780739b227a7' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('user', schema=None) as batch_op: + batch_op.add_column(sa.Column('about_me', sa.String(length=140), nullable=True)) + batch_op.add_column(sa.Column('last_seen', sa.DateTime(), nullable=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_column('last_seen') + batch_op.drop_column('about_me') + + # ### end Alembic commands ###