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 | » | |||
|
12 | ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))} | |||
|
13 | » | |||
|
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 | controller='feed', action='atom', |
|
261 | controller='feed', action='atom', | |
262 | conditions=dict(function=check_repo)) |
|
262 | conditions=dict(function=check_repo)) | |
263 |
|
263 | |||
|
264 | #========================================================================== | |||
264 | #REPOSITORY ROUTES |
|
265 | # REPOSITORY ROUTES | |
|
266 | #========================================================================== | |||
265 | rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}', |
|
267 | rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}', | |
266 | controller='changeset', revision='tip', |
|
268 | controller='changeset', revision='tip', | |
267 | conditions=dict(function=check_repo)) |
|
269 | conditions=dict(function=check_repo)) | |
@@ -336,4 +338,7 def make_map(config): | |||||
336 | controller='settings', action='fork', |
|
338 | controller='settings', action='fork', | |
337 | conditions=dict(function=check_repo)) |
|
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 | return rmap |
|
344 | return rmap |
@@ -487,12 +487,19 class UserFollowing(Base): | |||||
487 | user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) |
|
487 | user_id = Column("user_id", Integer(), ForeignKey('users.user_id'), nullable=False, unique=None, default=None) | |
488 | follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) |
|
488 | follows_repo_id = Column("follows_repository_id", Integer(), ForeignKey('repositories.repo_id'), nullable=True, unique=None, default=None) | |
489 | follows_user_id = Column("follows_user_id", Integer(), ForeignKey('users.user_id'), nullable=True, unique=None, default=None) |
|
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 | user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') |
|
492 | user = relationship('User', primaryjoin='User.user_id==UserFollowing.user_id') | |
492 |
|
493 | |||
493 | follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') |
|
494 | follows_user = relationship('User', primaryjoin='User.user_id==UserFollowing.follows_user_id') | |
494 | follows_repository = relationship('Repository', order_by='Repository.repo_name') |
|
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 | class CacheInvalidation(Base): |
|
503 | class CacheInvalidation(Base): | |
497 | __tablename__ = 'cache_invalidation' |
|
504 | __tablename__ = 'cache_invalidation' | |
498 | __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True}) |
|
505 | __table_args__ = (UniqueConstraint('cache_key'), {'useexisting':True}) |
@@ -290,7 +290,7 | |||||
290 | </li> |
|
290 | </li> | |
291 |
|
291 | |||
292 | <li> |
|
292 | <li> | |
293 |
<a title="${_('Followers')}" href=" |
|
293 | <a title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}"> | |
294 | <span class="icon_short"> |
|
294 | <span class="icon_short"> | |
295 | <img src="${h.url("/images/icons/heart.png")}" alt="${_('Followers')}" /> |
|
295 | <img src="${h.url("/images/icons/heart.png")}" alt="${_('Followers')}" /> | |
296 | </span> |
|
296 | </span> |
General Comments 0
You need to be logged in to leave comments.
Login now