Skip to content

Commit 6837b08

Browse files
Chapter 10: User profiles (10a)
1 parent 0fe030b commit 6837b08

File tree

7 files changed

+103
-7
lines changed

7 files changed

+103
-7
lines changed

app/auth/views.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111

1212
@auth.before_app_request
1313
def before_request():
14-
if current_user.is_authenticated \
15-
and not current_user.confirmed \
16-
and request.endpoint \
17-
and request.blueprint != 'auth' \
18-
and request.endpoint != 'static':
19-
return redirect(url_for('auth.unconfirmed'))
14+
if current_user.is_authenticated:
15+
current_user.ping()
16+
if not current_user.confirmed \
17+
and request.endpoint \
18+
and request.blueprint != 'auth' \
19+
and request.endpoint != 'static':
20+
return redirect(url_for('auth.unconfirmed'))
2021

2122

2223
@auth.route('/unconfirmed')

app/main/views.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
from flask import render_template
1+
from flask import render_template, abort
22
from . import main
3+
from ..models import User
34

45

56
@main.route('/')
67
def index():
78
return render_template('index.html')
9+
10+
11+
@main.route('/user/<username>')
12+
def user(username):
13+
user = User.query.filter_by(username=username).first_or_404()
14+
return render_template('user.html', user=user)

app/models.py

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from datetime import datetime
12
from werkzeug.security import generate_password_hash, check_password_hash
23
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
34
from flask import current_app
@@ -74,6 +75,11 @@ class User(UserMixin, db.Model):
7475
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
7576
password_hash = db.Column(db.String(128))
7677
confirmed = db.Column(db.Boolean, default=False)
78+
name = db.Column(db.String(64))
79+
location = db.Column(db.String(64))
80+
about_me = db.Column(db.Text())
81+
member_since = db.Column(db.DateTime(), default=datetime.utcnow)
82+
last_seen = db.Column(db.DateTime(), default=datetime.utcnow)
7783

7884
def __init__(self, **kwargs):
7985
super(User, self).__init__(**kwargs)
@@ -156,6 +162,10 @@ def can(self, perm):
156162
def is_administrator(self):
157163
return self.can(Permission.ADMIN)
158164

165+
def ping(self):
166+
self.last_seen = datetime.utcnow()
167+
db.session.add(self)
168+
159169
def __repr__(self):
160170
return '<User %r>' % self.username
161171

app/templates/base.html

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
<div class="navbar-collapse collapse">
2424
<ul class="nav navbar-nav">
2525
<li><a href="{{ url_for('main.index') }}">Home</a></li>
26+
{% if current_user.is_authenticated %}
27+
<li><a href="{{ url_for('main.user', username=current_user.username) }}">Profile</a></li>
28+
{% endif %}
2629
</ul>
2730
<ul class="nav navbar-nav navbar-right">
2831
{% if current_user.is_authenticated %}

app/templates/user.html

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{% extends "base.html" %}
2+
3+
{% block title %}Flasky - {{ user.username }}{% endblock %}
4+
5+
{% block page_content %}
6+
<div class="page-header">
7+
<h1>{{ user.username }}</h1>
8+
{% if user.name or user.location %}
9+
<p>
10+
{% if user.name %}{{ user.name }}{% endif %}
11+
{% if user.location %}
12+
from <a href="http://maps.google.com/?q={{ user.location }}">{{ user.location }}</a>
13+
{% endif %}
14+
</p>
15+
{% endif %}
16+
{% if current_user.is_administrator() %}
17+
<p><a href="mailto:{{ user.email }}">{{ user.email }}</a></p>
18+
{% endif %}
19+
{% if user.about_me %}<p>{{ user.about_me }}</p>{% endif %}
20+
<p>Member since {{ moment(user.member_since).format('L') }}. Last seen {{ moment(user.last_seen).fromNow() }}.</p>
21+
</div>
22+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""user information
2+
3+
Revision ID: d66f086b258
4+
Revises: 56ed7d33de8d
5+
Create Date: 2013-12-29 23:50:49.566954
6+
7+
"""
8+
9+
# revision identifiers, used by Alembic.
10+
revision = 'd66f086b258'
11+
down_revision = '56ed7d33de8d'
12+
13+
from alembic import op
14+
import sqlalchemy as sa
15+
16+
17+
def upgrade():
18+
### commands auto generated by Alembic - please adjust! ###
19+
op.add_column('users', sa.Column('about_me', sa.Text(), nullable=True))
20+
op.add_column('users', sa.Column('last_seen', sa.DateTime(), nullable=True))
21+
op.add_column('users', sa.Column('location', sa.String(length=64), nullable=True))
22+
op.add_column('users', sa.Column('member_since', sa.DateTime(), nullable=True))
23+
op.add_column('users', sa.Column('name', sa.String(length=64), nullable=True))
24+
### end Alembic commands ###
25+
26+
27+
def downgrade():
28+
### commands auto generated by Alembic - please adjust! ###
29+
op.drop_column('users', 'name')
30+
op.drop_column('users', 'member_since')
31+
op.drop_column('users', 'location')
32+
op.drop_column('users', 'last_seen')
33+
op.drop_column('users', 'about_me')
34+
### end Alembic commands ###

tests/test_user_model.py

+19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import unittest
22
import time
3+
from datetime import datetime
34
from app import create_app, db
45
from app.models import User, AnonymousUser, Role, Permission
56

@@ -137,3 +138,21 @@ def test_anonymous_user(self):
137138
self.assertFalse(u.can(Permission.WRITE))
138139
self.assertFalse(u.can(Permission.MODERATE))
139140
self.assertFalse(u.can(Permission.ADMIN))
141+
142+
def test_timestamps(self):
143+
u = User(password='cat')
144+
db.session.add(u)
145+
db.session.commit()
146+
self.assertTrue(
147+
(datetime.utcnow() - u.member_since).total_seconds() < 3)
148+
self.assertTrue(
149+
(datetime.utcnow() - u.last_seen).total_seconds() < 3)
150+
151+
def test_ping(self):
152+
u = User(password='cat')
153+
db.session.add(u)
154+
db.session.commit()
155+
time.sleep(2)
156+
last_seen_before = u.last_seen
157+
u.ping()
158+
self.assertTrue(u.last_seen > last_seen_before)

0 commit comments

Comments
 (0)