##// END OF EJS Templates
#179 Added followers page
marcink -
r1279:cb216757 beta
parent child Browse files
Show More
@@ -0,0 +1,57
1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.controllers.followers
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 Followers controller for rhodecode
7
8 :created_on: Apr 23, 2011
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
17 #
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import logging
26
27 from pylons import tmpl_context as c, request
28
29 from rhodecode.lib.helpers import Page
30 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
31 from rhodecode.lib.base import BaseRepoController, render
32 from rhodecode.model.db import Repository, User, UserFollowing
33
34 log = logging.getLogger(__name__)
35
36
37 class FollowersController(BaseRepoController):
38
39 @LoginRequired()
40 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
41 'repository.admin')
42 def __before__(self):
43 super(FollowersController, self).__before__()
44
45 def followers(self, repo_name):
46 p = int(request.params.get('page', 1))
47 repo_id = getattr(Repository.by_repo_name(repo_name), 'repo_id')
48 d = UserFollowing.get_repo_followers(repo_id)\
49 .order_by(UserFollowing.follows_from)
50 c.followers_pager = Page(d, page=p, items_per_page=20)
51
52 c.followers_data = render('/followers/followers_data.html')
53
54 if request.params.get('partial'):
55 return c.followers_data
56
57 return render('/followers/followers.html')
@@ -0,0 +1,33
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
3
4 <%def name="title()">
5 ${c.repo_name} ${_('Followers')} - ${c.rhodecode_name}
6 </%def>
7
8
9 <%def name="breadcrumbs_links()">
10 ${h.link_to(u'Home',h.url('/'))}
11 &raquo;
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
13 &raquo;
14 ${_('followers')}
15 </%def>
16
17 <%def name="page_nav()">
18 ${self.menu('followers')}
19 </%def>
20 <%def name="main()">
21 <div class="box">
22 <!-- box / title -->
23 <div class="title">
24 ${self.breadcrumbs()}
25 </div>
26 <!-- end box / title -->
27 <div class="table">
28 <div id="followers">
29 ${c.followers_data}
30 </div>
31 </div>
32 </div>
33 </%def> No newline at end of file
@@ -0,0 +1,37
1 ## -*- coding: utf-8 -*-
2
3
4 % for f in c.followers_pager:
5 <div>
6 <div class="follower_user">
7 <div class="gravatar">
8 <img alt="gravatar" src="${h.gravatar_url(f.user.email,24)}"/>
9 </div>
10 <span style="font-size: 20px"> <b>${f.user.username}</b> (${f.user.name} ${f.user.lastname})</span>
11 </div>
12 <div style="clear:both;padding-top: 10px"></div>
13 <div class="follower_date">${_('Started following on')} - ${f.follows_from}</div>
14 <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div>
15 </div>
16 % endfor
17
18
19 <div class="pagination-wh pagination-left">
20 <script type="text/javascript">
21 var data_div = 'followers';
22 YAHOO.util.Event.onDOMReady(function(){
23 YAHOO.util.Event.addListener(
24 YUD.getElementsByClassName('pager_link'),"click",
25 function(){
26 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');
27 });
28 });
29 </script>
30
31 ${c.followers_pager.pager('$link_previous ~2~ $link_next',
32 onclick="""YAHOO.util.Connect.asyncRequest('GET','$partial_url',{
33 success:function(o){YAHOO.util.Dom.get(data_div).innerHTML=o.responseText;
34 YUE.on(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
35 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');});
36 YAHOO.util.Dom.setStyle(data_div,'opacity','1');}},null); return false;""")}
37 </div> No newline at end of file
@@ -261,7 +261,9 def make_map(config):
261 261 controller='feed', action='atom',
262 262 conditions=dict(function=check_repo))
263 263
264 #==========================================================================
264 265 #REPOSITORY ROUTES
266 #==========================================================================
265 267 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
266 268 controller='changeset', revision='tip',
267 269 conditions=dict(function=check_repo))
@@ -336,4 +338,7 def make_map(config):
336 338 controller='settings', action='fork',
337 339 conditions=dict(function=check_repo))
338 340
341 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
342 controller='followers', action='followers',
343 conditions=dict(function=check_repo))
339 344 return rmap
@@ -487,12 +487,19 class UserFollowing(Base):
487 487 user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None)
488 488 follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None)
489 489 follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None)
490 follows_from = Column('follows_from', DateTime(timezone=False), nullable=True, unique=None, default=datetime.datetime.now)
490 491
491 492 user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id')
492 493
493 494 follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id')
494 495 follows_repository = relationship('Repository', order_by='Repository.repo_name')
495 496
497
498
499 @classmethod
500 def get_repo_followers(cls, repo_id):
501 return Session.query(cls).filter(cls.follows_repo_id == repo_id)
502
496 503 class CacheInvalidation(Base):
497 504 __tablename__ = 'cache_invalidation'
498 505 __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True})
@@ -290,7 +290,7
290 290 </li>
291 291
292 292 <li>
293 <a title="${_('Followers')}" href="#">
293 <a title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
294 294 <span class="icon_short">
295 295 <img src="${h.url("/images/icons/heart.png")}" alt="${_('Followers')}" />
296 296 </span>
General Comments 0
You need to be logged in to leave comments. Login now