followers
This commit is contained in:
		
							parent
							
								
									8c091d7add
								
							
						
					
					
						commit
						47e65873a9
					
				|  | @ -4,6 +4,11 @@ from app import db | ||||||
| ROLE_USER = 0 | ROLE_USER = 0 | ||||||
| ROLE_ADMIN = 1 | ROLE_ADMIN = 1 | ||||||
| 
 | 
 | ||||||
|  | followers = db.Table('followers', | ||||||
|  |     db.Column('follower_id', db.Integer, db.ForeignKey('user.id')), | ||||||
|  |     db.Column('followed_id', db.Integer, db.ForeignKey('user.id')) | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| class User(db.Model): | class User(db.Model): | ||||||
|     id = db.Column(db.Integer, primary_key = True) |     id = db.Column(db.Integer, primary_key = True) | ||||||
|     nickname = db.Column(db.String(64), unique = True) |     nickname = db.Column(db.String(64), unique = True) | ||||||
|  | @ -12,6 +17,12 @@ class User(db.Model): | ||||||
|     posts = db.relationship('Post', backref = 'author', lazy = 'dynamic') |     posts = db.relationship('Post', backref = 'author', lazy = 'dynamic') | ||||||
|     about_me = db.Column(db.String(140)) |     about_me = db.Column(db.String(140)) | ||||||
|     last_seen = db.Column(db.DateTime) |     last_seen = db.Column(db.DateTime) | ||||||
|  |     followed = db.relationship('User',  | ||||||
|  |         secondary = followers,  | ||||||
|  |         primaryjoin = (followers.c.follower_id == id),  | ||||||
|  |         secondaryjoin = (followers.c.followed_id == id),  | ||||||
|  |         backref = db.backref('followers', lazy = 'dynamic'),  | ||||||
|  |         lazy = 'dynamic') | ||||||
| 
 | 
 | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def make_unique_nickname(nickname): |     def make_unique_nickname(nickname): | ||||||
|  | @ -40,6 +51,22 @@ class User(db.Model): | ||||||
|     def avatar(self, size): |     def avatar(self, size): | ||||||
|         return 'http://www.gravatar.com/avatar/' + md5(self.email).hexdigest() + '?d=mm&s=' + str(size) |         return 'http://www.gravatar.com/avatar/' + md5(self.email).hexdigest() + '?d=mm&s=' + str(size) | ||||||
|          |          | ||||||
|  |     def follow(self, user): | ||||||
|  |         if not self.is_following(user): | ||||||
|  |             self.followed.append(user) | ||||||
|  |             return self | ||||||
|  |              | ||||||
|  |     def unfollow(self, user): | ||||||
|  |         if self.is_following(user): | ||||||
|  |             self.followed.remove(user) | ||||||
|  |             return self | ||||||
|  |              | ||||||
|  |     def is_following(self, user): | ||||||
|  |         return self.followed.filter(followers.c.followed_id == user.id).count() > 0 | ||||||
|  | 
 | ||||||
|  |     def followed_posts(self): | ||||||
|  |         return Post.query.join(followers, (followers.c.followed_id == Post.user_id)).filter(followers.c.follower_id == self.id).order_by(Post.timestamp.desc()) | ||||||
|  |          | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return '<User %r>' % (self.nickname)     |         return '<User %r>' % (self.nickname)     | ||||||
|          |          | ||||||
|  |  | ||||||
|  | @ -9,7 +9,15 @@ | ||||||
|             <h1>User: {{user.nickname}}</h1> |             <h1>User: {{user.nickname}}</h1> | ||||||
|             {% if user.about_me %}<p>{{user.about_me}}</p>{% endif %} |             {% if user.about_me %}<p>{{user.about_me}}</p>{% endif %} | ||||||
|             {% if user.last_seen %}<p><i>Last seen on: {{user.last_seen}}</i></p>{% endif %} |             {% if user.last_seen %}<p><i>Last seen on: {{user.last_seen}}</i></p>{% endif %} | ||||||
|             {% if user.id == g.user.id %}<p><a href="{{url_for('edit')}}">Edit</a></p>{% endif %} |             <p>{{user.followers.count()}} followers |  | ||||||
|  |             {% if user.id == g.user.id %} | ||||||
|  |                 <a href="{{url_for('edit')}}">Edit your profile</a> | ||||||
|  |             {% elif not g.user.is_following(user) %} | ||||||
|  |                 <a href="{{url_for('follow', nickname = user.nickname)}}">Follow</a> | ||||||
|  |             {% else %} | ||||||
|  |                 <a href="{{url_for('unfollow', nickname = user.nickname)}}">Unfollow</a> | ||||||
|  |             {% endif %} | ||||||
|  |             </p> | ||||||
|         </td> |         </td> | ||||||
|     </tr> |     </tr> | ||||||
| </table> | </table> | ||||||
|  |  | ||||||
							
								
								
									
										32
									
								
								app/views.py
								
								
								
								
							
							
						
						
									
										32
									
								
								app/views.py
								
								
								
								
							|  | @ -73,6 +73,9 @@ def after_login(resp): | ||||||
|         user = User(nickname = nickname, email = resp.email, role = ROLE_USER) |         user = User(nickname = nickname, email = resp.email, role = ROLE_USER) | ||||||
|         db.session.add(user) |         db.session.add(user) | ||||||
|         db.session.commit() |         db.session.commit() | ||||||
|  |         # make the user follow him/herself | ||||||
|  |         db.session.add(user.follow(user)) | ||||||
|  |         db.session.commit() | ||||||
|     remember_me = False |     remember_me = False | ||||||
|     if 'remember_me' in session: |     if 'remember_me' in session: | ||||||
|         remember_me = session['remember_me'] |         remember_me = session['remember_me'] | ||||||
|  | @ -117,3 +120,32 @@ def edit(): | ||||||
|     return render_template('edit.html', |     return render_template('edit.html', | ||||||
|         form = form) |         form = form) | ||||||
| 
 | 
 | ||||||
|  | @app.route('/follow/<nickname>') | ||||||
|  | def follow(nickname): | ||||||
|  |     user = User.query.filter_by(nickname = nickname).first() | ||||||
|  |     if user == None: | ||||||
|  |         flash('User ' + nickname + ' not found.') | ||||||
|  |         return redirect(url_for('index')) | ||||||
|  |     u = g.user.follow(user) | ||||||
|  |     if u is None: | ||||||
|  |         flash('Cannot follow ' + nickname + '.') | ||||||
|  |         return redirect(url_for('user', nickname = nickname)) | ||||||
|  |     db.session.add(u) | ||||||
|  |     db.session.commit() | ||||||
|  |     flash('You are now following ' + nickname + '!') | ||||||
|  |     return redirect(url_for('user', nickname = nickname)) | ||||||
|  | 
 | ||||||
|  | @app.route('/unfollow/<nickname>') | ||||||
|  | def unfollow(nickname): | ||||||
|  |     user = User.query.filter_by(nickname = nickname).first() | ||||||
|  |     if user == None: | ||||||
|  |         flash('User ' + nickname + ' not found.') | ||||||
|  |         return redirect(url_for('index')) | ||||||
|  |     u = g.user.unfollow(user) | ||||||
|  |     if u is None: | ||||||
|  |         flash('Cannot unfollow ' + nickname + '.') | ||||||
|  |         return redirect(url_for('user', nickname = nickname)) | ||||||
|  |     db.session.add(u) | ||||||
|  |     db.session.commit() | ||||||
|  |     flash('You have stopped following ' + nickname + '.') | ||||||
|  |     return redirect(url_for('user', nickname = nickname)) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,26 @@ | ||||||
|  | from sqlalchemy import * | ||||||
|  | from migrate import * | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | from migrate.changeset import schema | ||||||
|  | pre_meta = MetaData() | ||||||
|  | post_meta = MetaData() | ||||||
|  | followers = Table('followers', post_meta, | ||||||
|  |     Column('follower_id', Integer), | ||||||
|  |     Column('followed_id', Integer), | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def upgrade(migrate_engine): | ||||||
|  |     # Upgrade operations go here. Don't create your own engine; bind | ||||||
|  |     # migrate_engine to your metadata | ||||||
|  |     pre_meta.bind = migrate_engine | ||||||
|  |     post_meta.bind = migrate_engine | ||||||
|  |     post_meta.tables['followers'].create() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def downgrade(migrate_engine): | ||||||
|  |     # Operations to reverse the above upgrade go here. | ||||||
|  |     pre_meta.bind = migrate_engine | ||||||
|  |     post_meta.bind = migrate_engine | ||||||
|  |     post_meta.tables['followers'].drop() | ||||||
							
								
								
									
										77
									
								
								tests.py
								
								
								
								
							
							
						
						
									
										77
									
								
								tests.py
								
								
								
								
							|  | @ -1,10 +1,11 @@ | ||||||
| #!flask/bin/python | #!flask/bin/python | ||||||
| import os | import os | ||||||
| import unittest | import unittest | ||||||
|  | from datetime import datetime, timedelta | ||||||
| 
 | 
 | ||||||
| from config import basedir | from config import basedir | ||||||
| from app import app, db | from app import app, db | ||||||
| from app.models import User | from app.models import User, Post | ||||||
| 
 | 
 | ||||||
| class TestCase(unittest.TestCase): | class TestCase(unittest.TestCase): | ||||||
|     def setUp(self): |     def setUp(self): | ||||||
|  | @ -14,6 +15,7 @@ class TestCase(unittest.TestCase): | ||||||
|         db.create_all() |         db.create_all() | ||||||
|          |          | ||||||
|     def tearDown(self): |     def tearDown(self): | ||||||
|  |         db.session.remove() | ||||||
|         db.drop_all() |         db.drop_all() | ||||||
| 
 | 
 | ||||||
|     def test_avatar(self): |     def test_avatar(self): | ||||||
|  | @ -38,5 +40,78 @@ class TestCase(unittest.TestCase): | ||||||
|         assert nickname2 != 'john' |         assert nickname2 != 'john' | ||||||
|         assert nickname2 != nickname |         assert nickname2 != nickname | ||||||
|          |          | ||||||
|  |     def test_follow(self): | ||||||
|  |         u1 = User(nickname = 'john', email = 'john@example.com') | ||||||
|  |         u2 = User(nickname = 'susan', email = 'susan@example.com') | ||||||
|  |         db.session.add(u1) | ||||||
|  |         db.session.add(u2) | ||||||
|  |         db.session.commit() | ||||||
|  |         assert u1.unfollow(u2) == None | ||||||
|  |         u = u1.follow(u2) | ||||||
|  |         db.session.add(u) | ||||||
|  |         db.session.commit() | ||||||
|  |         assert u1.follow(u2) == None | ||||||
|  |         assert u1.is_following(u2) | ||||||
|  |         assert u1.followed.count() == 1 | ||||||
|  |         assert u1.followed.first().nickname == 'susan' | ||||||
|  |         assert u2.followers.count() == 1 | ||||||
|  |         assert u2.followers.first().nickname == 'john' | ||||||
|  |         u = u1.unfollow(u2) | ||||||
|  |         assert u != None | ||||||
|  |         db.session.add(u) | ||||||
|  |         db.session.commit() | ||||||
|  |         assert u1.is_following(u2) == False | ||||||
|  |         assert u1.followed.count() == 0 | ||||||
|  |         assert u2.followers.count() == 0 | ||||||
|  |          | ||||||
|  |         def test_follow_posts(self): | ||||||
|  |             # make four users | ||||||
|  |             u1 = User(nickname = 'john', email = 'john@example.com') | ||||||
|  |             u2 = User(nickname = 'susan', email = 'susan@example.com') | ||||||
|  |             u3 = User(nickname = 'mary', email = 'mary@example.com') | ||||||
|  |             u4 = User(nickname = 'david', email = 'david@example.com') | ||||||
|  |             db.session.add(u1) | ||||||
|  |             db.session.add(u2) | ||||||
|  |             db.session.add(u3) | ||||||
|  |             db.session.add(u4) | ||||||
|  |             # make four posts | ||||||
|  |             utcnow = datetime.utcnow() | ||||||
|  |             p1 = Post(body = "post from john", author = u1, timestamp = utcnow + timedelta(seconds = 1)) | ||||||
|  |             p2 = Post(body = "post from susan", author = u2, timestamp = utcnow + timedelta(seconds = 2)) | ||||||
|  |             p3 = Post(body = "post from mary", author = u3, timestamp = utcnow + timedelta(seconds = 3)) | ||||||
|  |             p4 = Post(body = "post from david", author = u4, timestamp = utcnow + timedelta(seconds = 4)) | ||||||
|  |             db.session.add(p1) | ||||||
|  |             db.session.add(p2) | ||||||
|  |             db.session.add(p3) | ||||||
|  |             db.session.add(p4) | ||||||
|  |             db.session.commit() | ||||||
|  |             # setup the followers | ||||||
|  |             u1.follow(u1) # john follows himself | ||||||
|  |             u1.follow(u2) # john follows susan | ||||||
|  |             u1.follow(u4) # john follows david | ||||||
|  |             u2.follow(u2) # susan follows herself | ||||||
|  |             u2.follow(u3) # susan follows mary | ||||||
|  |             u3.follow(u3) # mary follows herself | ||||||
|  |             u3.follow(u4) # mary follows david | ||||||
|  |             u4.follow(u4) # david follows himself | ||||||
|  |             db.session.add(u1) | ||||||
|  |             db.session.add(u2) | ||||||
|  |             db.session.add(u3) | ||||||
|  |             db.session.add(u4) | ||||||
|  |             db.session.commit() | ||||||
|  |             # check the followed posts of each user | ||||||
|  |             f1 = u1.followed_posts().all() | ||||||
|  |             f2 = u2.followed_posts().all() | ||||||
|  |             f3 = u3.followed_posts().all() | ||||||
|  |             f4 = u4.followed_posts().all() | ||||||
|  |             assert len(f1) == 3 | ||||||
|  |             assert len(f2) == 2 | ||||||
|  |             assert len(f3) == 2 | ||||||
|  |             assert len(f4) == 1 | ||||||
|  |             assert f1 == [p4, p2, p1] | ||||||
|  |             assert f2 == [p3, p2] | ||||||
|  |             assert f3 == [p4, p3] | ||||||
|  |             assert f4 == [p4] | ||||||
|  |          | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     unittest.main() |     unittest.main() | ||||||
		Loading…
	
		Reference in New Issue