comparison rhodecode/controllers/journal.py @ 1512:bf263968da47

merge beta in stable branch
author Marcin Kuzminski <marcin@python-works.com>
date Fri, 07 Oct 2011 01:08:50 +0200
parents a3b2b4b4e440 c6b811f11c94
children 82a88013a3fd
comparison
equal deleted inserted replaced
1329:e058df3ff2b4 1512:bf263968da47
2 """ 2 """
3 rhodecode.controllers.journal 3 rhodecode.controllers.journal
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 Journal controller for pylons 6 Journal controller for pylons
7 7
8 :created_on: Nov 21, 2010 8 :created_on: Nov 21, 2010
9 :author: marcink 9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com> 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details. 11 :license: GPLv3, see COPYING for more details.
12 """ 12 """
13 # This program is free software: you can redistribute it and/or modify 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 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 15 # the Free Software Foundation, either version 3 of the License, or
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details. 21 # GNU General Public License for more details.
22 # 22 #
23 # You should have received a copy of the GNU General Public License 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/>. 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26 import logging 25 import logging
27 import traceback
28
29 from pylons import request, response, session, tmpl_context as c, url
30 from paste.httpexceptions import HTTPInternalServerError, HTTPBadRequest
31 26
32 from sqlalchemy import or_ 27 from sqlalchemy import or_
33 28 from sqlalchemy.orm import joinedload, make_transient
29 from webhelpers.paginate import Page
30 from itertools import groupby
31
32 from paste.httpexceptions import HTTPBadRequest
33 from pylons import request, tmpl_context as c, response, url
34 from pylons.i18n.translation import _
35 from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
36
37 import rhodecode.lib.helpers as h
34 from rhodecode.lib.auth import LoginRequired, NotAnonymous 38 from rhodecode.lib.auth import LoginRequired, NotAnonymous
35 from rhodecode.lib.base import BaseController, render 39 from rhodecode.lib.base import BaseController, render
36 from rhodecode.lib.helpers import get_token
37 from rhodecode.model.db import UserLog, UserFollowing 40 from rhodecode.model.db import UserLog, UserFollowing
38 from rhodecode.model.scm import ScmModel
39 41
40 log = logging.getLogger(__name__) 42 log = logging.getLogger(__name__)
41 43
44
42 class JournalController(BaseController): 45 class JournalController(BaseController):
43 46
47 def __before__(self):
48 super(JournalController, self).__before__()
49 self.rhodecode_user = self.rhodecode_user
50 self.title = _('%s public journal %s feed') % (c.rhodecode_name, '%s')
51 self.language = 'en-us'
52 self.ttl = "5"
53 self.feed_nr = 20
44 54
45 @LoginRequired() 55 @LoginRequired()
46 @NotAnonymous() 56 @NotAnonymous()
47 def __before__(self):
48 super(JournalController, self).__before__()
49
50 def index(self): 57 def index(self):
51 # Return a rendered template 58 # Return a rendered template
52 59 p = int(request.params.get('page', 1))
53 c.following = self.sa.query(UserFollowing)\ 60
54 .filter(UserFollowing.user_id == c.rhodecode_user.user_id).all() 61 c.following = self.sa.query(UserFollowing)\
55 62 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
56 repo_ids = [x.follows_repository.repo_id for x in c.following 63 .options(joinedload(UserFollowing.follows_repository))\
64 .all()
65
66 journal = self._get_journal_data(c.following)
67
68 c.journal_pager = Page(journal, page=p, items_per_page=20)
69
70 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
71
72 c.journal_data = render('journal/journal_data.html')
73 if request.environ.get('HTTP_X_PARTIAL_XHR'):
74 return c.journal_data
75 return render('journal/journal.html')
76
77 def _get_daily_aggregate(self, journal):
78 groups = []
79 for k, g in groupby(journal, lambda x: x.action_as_day):
80 user_group = []
81 for k2, g2 in groupby(list(g), lambda x: x.user.email):
82 l = list(g2)
83 user_group.append((l[0].user, l))
84
85 groups.append((k, user_group,))
86
87 return groups
88
89 def _get_journal_data(self, following_repos):
90 repo_ids = [x.follows_repository.repo_id for x in following_repos
57 if x.follows_repository is not None] 91 if x.follows_repository is not None]
58 user_ids = [x.follows_user.user_id for x in c.following 92 user_ids = [x.follows_user.user_id for x in following_repos
59 if x.follows_user is not None] 93 if x.follows_user is not None]
60 94
61 c.journal = self.sa.query(UserLog)\ 95 filtering_criterion = None
62 .filter(or_( 96
63 UserLog.repository_id.in_(repo_ids), 97 if repo_ids and user_ids:
64 UserLog.user_id.in_(user_ids), 98 filtering_criterion = or_(UserLog.repository_id.in_(repo_ids),
65 ))\ 99 UserLog.user_id.in_(user_ids))
66 .order_by(UserLog.action_date.desc())\ 100 if repo_ids and not user_ids:
67 .limit(20)\ 101 filtering_criterion = UserLog.repository_id.in_(repo_ids)
68 .all() 102 if not repo_ids and user_ids:
69 return render('/journal.html') 103 filtering_criterion = UserLog.user_id.in_(user_ids)
70 104 if filtering_criterion is not None:
105 journal = self.sa.query(UserLog)\
106 .options(joinedload(UserLog.user))\
107 .options(joinedload(UserLog.repository))\
108 .filter(filtering_criterion)\
109 .order_by(UserLog.action_date.desc())
110 else:
111 journal = []
112
113 return journal
114
115 @LoginRequired()
116 @NotAnonymous()
71 def toggle_following(self): 117 def toggle_following(self):
72 118 cur_token = request.POST.get('auth_token')
73 if request.POST.get('auth_token') == get_token(): 119 token = h.get_token()
74 scm_model = ScmModel() 120 if cur_token == token:
75 121
76 user_id = request.POST.get('follows_user_id') 122 user_id = request.POST.get('follows_user_id')
77 if user_id: 123 if user_id:
78 try: 124 try:
79 scm_model.toggle_following_user(user_id, 125 self.scm_model.toggle_following_user(user_id,
80 c.rhodecode_user.user_id) 126 self.rhodecode_user.user_id)
81 return 'ok' 127 return 'ok'
82 except: 128 except:
83 log.error(traceback.format_exc()) 129 raise HTTPBadRequest()
84 raise HTTPInternalServerError()
85 130
86 repo_id = request.POST.get('follows_repo_id') 131 repo_id = request.POST.get('follows_repo_id')
87 if repo_id: 132 if repo_id:
88 try: 133 try:
89 scm_model.toggle_following_repo(repo_id, 134 self.scm_model.toggle_following_repo(repo_id,
90 c.rhodecode_user.user_id) 135 self.rhodecode_user.user_id)
91 return 'ok' 136 return 'ok'
92 except: 137 except:
93 log.error(traceback.format_exc()) 138 raise HTTPBadRequest()
94 raise HTTPInternalServerError() 139
95 140 log.debug('token mismatch %s vs %s', cur_token, token)
96
97
98 raise HTTPBadRequest() 141 raise HTTPBadRequest()
142
143 @LoginRequired()
144 def public_journal(self):
145 # Return a rendered template
146 p = int(request.params.get('page', 1))
147
148 c.following = self.sa.query(UserFollowing)\
149 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
150 .options(joinedload(UserFollowing.follows_repository))\
151 .all()
152
153 journal = self._get_journal_data(c.following)
154
155 c.journal_pager = Page(journal, page=p, items_per_page=20)
156
157 c.journal_day_aggreagate = self._get_daily_aggregate(c.journal_pager)
158
159 c.journal_data = render('journal/journal_data.html')
160 if request.environ.get('HTTP_X_PARTIAL_XHR'):
161 return c.journal_data
162 return render('journal/public_journal.html')
163
164 @LoginRequired(api_access=True)
165 def public_journal_atom(self):
166 """
167 Produce an atom-1.0 feed via feedgenerator module
168 """
169 c.following = self.sa.query(UserFollowing)\
170 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
171 .options(joinedload(UserFollowing.follows_repository))\
172 .all()
173
174 journal = self._get_journal_data(c.following)
175
176 feed = Atom1Feed(title=self.title % 'atom',
177 link=url('public_journal_atom', qualified=True),
178 description=_('Public journal'),
179 language=self.language,
180 ttl=self.ttl)
181
182 for entry in journal[:self.feed_nr]:
183 #tmpl = h.action_parser(entry)[0]
184 action, action_extra = h.action_parser(entry, feed=True)
185 title = "%s - %s %s" % (entry.user.short_contact, action,
186 entry.repository.repo_name)
187 desc = action_extra()
188 feed.add_item(title=title,
189 pubdate=entry.action_date,
190 link=url('', qualified=True),
191 author_email=entry.user.email,
192 author_name=entry.user.full_contact,
193 description=desc)
194
195 response.content_type = feed.mime_type
196 return feed.writeString('utf-8')
197
198 @LoginRequired(api_access=True)
199 def public_journal_rss(self):
200 """
201 Produce an rss2 feed via feedgenerator module
202 """
203 c.following = self.sa.query(UserFollowing)\
204 .filter(UserFollowing.user_id == self.rhodecode_user.user_id)\
205 .options(joinedload(UserFollowing.follows_repository))\
206 .all()
207
208 journal = self._get_journal_data(c.following)
209
210 feed = Rss201rev2Feed(title=self.title % 'rss',
211 link=url('public_journal_rss', qualified=True),
212 description=_('Public journal'),
213 language=self.language,
214 ttl=self.ttl)
215
216 for entry in journal[:self.feed_nr]:
217 #tmpl = h.action_parser(entry)[0]
218 action, action_extra = h.action_parser(entry, feed=True)
219 title = "%s - %s %s" % (entry.user.short_contact, action,
220 entry.repository.repo_name)
221 desc = action_extra()
222 feed.add_item(title=title,
223 pubdate=entry.action_date,
224 link=url('', qualified=True),
225 author_email=entry.user.email,
226 author_name=entry.user.full_contact,
227 description=desc)
228
229 response.content_type = feed.mime_type
230 return feed.writeString('utf-8')