Mercurial > kallithea
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') |