Show More
@@ -0,0 +1,59 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | # This program is free software: you can redistribute it and/or modify | |||
|
3 | # it under the terms of the GNU General Public License as published by | |||
|
4 | # the Free Software Foundation, either version 3 of the License, or | |||
|
5 | # (at your option) any later version. | |||
|
6 | # | |||
|
7 | # This program is distributed in the hope that it will be useful, | |||
|
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
10 | # GNU General Public License for more details. | |||
|
11 | # | |||
|
12 | # You should have received a copy of the GNU General Public License | |||
|
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
14 | ||||
|
15 | """ | |||
|
16 | kallithea.lib.feeds | |||
|
17 | ~~~~~~~~~~~~~~~~~~~ | |||
|
18 | ||||
|
19 | Shared code for providing RSS and ATOM feeds. | |||
|
20 | """ | |||
|
21 | ||||
|
22 | import datetime | |||
|
23 | import re | |||
|
24 | ||||
|
25 | from webhelpers import feedgenerator | |||
|
26 | ||||
|
27 | ||||
|
28 | language = 'en-us' | |||
|
29 | ttl = "5" | |||
|
30 | ||||
|
31 | class _Feeder(object): | |||
|
32 | ||||
|
33 | content_type = None | |||
|
34 | feed_factory = None # a webhelpers.feedgenerator | |||
|
35 | ||||
|
36 | @classmethod | |||
|
37 | def render(cls, header, entries): | |||
|
38 | feed = cls.feed_factory( | |||
|
39 | language=language, | |||
|
40 | ttl=ttl, # rss only | |||
|
41 | **header | |||
|
42 | ) | |||
|
43 | for e in entries: | |||
|
44 | feed.add_item(**e) | |||
|
45 | return feed.writeString('utf-8') | |||
|
46 | ||||
|
47 | ||||
|
48 | class AtomFeed(_Feeder): | |||
|
49 | ||||
|
50 | content_type = 'application/atom+xml' | |||
|
51 | ||||
|
52 | feed_factory = feedgenerator.Atom1Feed | |||
|
53 | ||||
|
54 | ||||
|
55 | class RssFeed(_Feeder): | |||
|
56 | ||||
|
57 | content_type = 'application/rss+xml' | |||
|
58 | ||||
|
59 | feed_factory = feedgenerator.Rss201rev2Feed |
@@ -32,9 +32,9 b' from beaker.cache import cache_region' | |||||
32 | from tg import response |
|
32 | from tg import response | |
33 | from tg import tmpl_context as c |
|
33 | from tg import tmpl_context as c | |
34 | from tg.i18n import ugettext as _ |
|
34 | from tg.i18n import ugettext as _ | |
35 | from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed |
|
|||
36 |
|
35 | |||
37 | from kallithea import CONFIG |
|
36 | from kallithea import CONFIG | |
|
37 | from kallithea.lib import feeds | |||
38 | from kallithea.lib import helpers as h |
|
38 | from kallithea.lib import helpers as h | |
39 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired |
|
39 | from kallithea.lib.auth import HasRepoPermissionLevelDecorator, LoginRequired | |
40 | from kallithea.lib.base import BaseRepoController |
|
40 | from kallithea.lib.base import BaseRepoController | |
@@ -45,10 +45,6 b' from kallithea.lib.utils2 import safe_in' | |||||
45 | log = logging.getLogger(__name__) |
|
45 | log = logging.getLogger(__name__) | |
46 |
|
46 | |||
47 |
|
47 | |||
48 | language = 'en-us' |
|
|||
49 | ttl = "5" |
|
|||
50 |
|
||||
51 |
|
||||
52 | class FeedController(BaseRepoController): |
|
48 | class FeedController(BaseRepoController): | |
53 |
|
49 | |||
54 | @LoginRequired(allow_default_user=True) |
|
50 | @LoginRequired(allow_default_user=True) | |
@@ -102,39 +98,37 b' class FeedController(BaseRepoController)' | |||||
102 | desc_msg.append('</pre>') |
|
98 | desc_msg.append('</pre>') | |
103 | return [safe_unicode(chunk) for chunk in desc_msg] |
|
99 | return [safe_unicode(chunk) for chunk in desc_msg] | |
104 |
|
100 | |||
105 |
def _feed(self, repo_name, |
|
101 | def _feed(self, repo_name, feeder): | |
106 | """Produce a simple feed""" |
|
102 | """Produce a simple feed""" | |
107 |
|
103 | |||
108 | @cache_region('long_term', '_get_feed_from_cache') |
|
104 | @cache_region('long_term', '_get_feed_from_cache') | |
109 | def _get_feed_from_cache(*_cache_keys): # parameters are not really used - only as caching key |
|
105 | def _get_feed_from_cache(*_cache_keys): # parameters are not really used - only as caching key | |
110 |
|
|
106 | header = dict( | |
111 | title=_('%s %s feed') % (c.site_name, repo_name), |
|
107 | title=_('%s %s feed') % (c.site_name, repo_name), | |
112 | link=h.canonical_url('summary_home', repo_name=repo_name), |
|
108 | link=h.canonical_url('summary_home', repo_name=repo_name), | |
113 | description=_('Changes on %s repository') % repo_name, |
|
109 | description=_('Changes on %s repository') % repo_name, | |
114 | language=language, |
|
|||
115 | ttl=ttl, # rss only |
|
|||
116 | ) |
|
110 | ) | |
117 |
|
111 | |||
118 | rss_items_per_page = safe_int(CONFIG.get('rss_items_per_page', 20)) |
|
112 | rss_items_per_page = safe_int(CONFIG.get('rss_items_per_page', 20)) | |
|
113 | entries=[] | |||
119 | for cs in reversed(list(c.db_repo_scm_instance[-rss_items_per_page:])): |
|
114 | for cs in reversed(list(c.db_repo_scm_instance[-rss_items_per_page:])): | |
120 | feed.add_item(title=self._get_title(cs), |
|
115 | entries.append(dict( | |
121 | link=h.canonical_url('changeset_home', repo_name=repo_name, |
|
116 | title=self._get_title(cs), | |
122 | revision=cs.raw_id), |
|
117 | link=h.canonical_url('changeset_home', repo_name=repo_name, revision=cs.raw_id), | |
123 |
|
|
118 | author_email=cs.author_email, | |
124 |
|
|
119 | author_name=cs.author_name, | |
125 |
|
|
120 | description=''.join(self.__get_desc(cs)), | |
126 |
|
|
121 | pubdate=cs.date, | |
127 |
|
|
122 | )) | |
|
123 | return feeder.render(header, entries) | |||
128 |
|
124 | |||
129 |
|
|
125 | response.content_type = feeder.content_type | |
130 | return feed.writeString('utf-8') |
|
126 | return _get_feed_from_cache(repo_name, feeder.__name__) | |
131 |
|
||||
132 | return _get_feed_from_cache(repo_name, kind, c.db_repo.changeset_cache.get('raw_id')) |
|
|||
133 |
|
127 | |||
134 | def atom(self, repo_name): |
|
128 | def atom(self, repo_name): | |
135 | """Produce a simple atom-1.0 feed""" |
|
129 | """Produce a simple atom-1.0 feed""" | |
136 |
return self._feed(repo_name, |
|
130 | return self._feed(repo_name, feeds.AtomFeed) | |
137 |
|
131 | |||
138 | def rss(self, repo_name): |
|
132 | def rss(self, repo_name): | |
139 |
"""Produce a |
|
133 | """Produce a simple rss2 feed""" | |
140 |
return self._feed(repo_name, |
|
134 | return self._feed(repo_name, feeds.RssFeed) |
@@ -23,7 +23,6 b' Original author and date, and relevant c' | |||||
23 | :author: marcink |
|
23 | :author: marcink | |
24 | :copyright: (c) 2013 RhodeCode GmbH, and others. |
|
24 | :copyright: (c) 2013 RhodeCode GmbH, and others. | |
25 | :license: GPLv3, see LICENSE.md for more details. |
|
25 | :license: GPLv3, see LICENSE.md for more details. | |
26 |
|
||||
27 | """ |
|
26 | """ | |
28 |
|
27 | |||
29 | import logging |
|
28 | import logging | |
@@ -35,11 +34,11 b' from sqlalchemy.orm import joinedload' | |||||
35 | from tg import request, response |
|
34 | from tg import request, response | |
36 | from tg import tmpl_context as c |
|
35 | from tg import tmpl_context as c | |
37 | from tg.i18n import ugettext as _ |
|
36 | from tg.i18n import ugettext as _ | |
38 | from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed |
|
|||
39 | from webob.exc import HTTPBadRequest |
|
37 | from webob.exc import HTTPBadRequest | |
40 |
|
38 | |||
41 | import kallithea.lib.helpers as h |
|
39 | import kallithea.lib.helpers as h | |
42 | from kallithea.controllers.admin.admin import _journal_filter |
|
40 | from kallithea.controllers.admin.admin import _journal_filter | |
|
41 | from kallithea.lib import feeds | |||
43 | from kallithea.lib.auth import LoginRequired |
|
42 | from kallithea.lib.auth import LoginRequired | |
44 | from kallithea.lib.base import BaseController, render |
|
43 | from kallithea.lib.base import BaseController, render | |
45 | from kallithea.lib.page import Page |
|
44 | from kallithea.lib.page import Page | |
@@ -104,17 +103,17 b' class JournalController(BaseController):' | |||||
104 |
|
103 | |||
105 | return journal |
|
104 | return journal | |
106 |
|
105 | |||
107 |
def _feed(self, repos, feed |
|
106 | def _feed(self, repos, feeder, link, desc): | |
|
107 | response.content_type = feeder.content_type | |||
108 | journal = self._get_journal_data(repos) |
|
108 | journal = self._get_journal_data(repos) | |
109 |
|
109 | |||
110 |
|
|
110 | header = dict( | |
111 | title=desc, |
|
111 | title=desc, | |
112 | link=link, |
|
112 | link=link, | |
113 | description=desc, |
|
113 | description=desc, | |
114 | language=language, |
|
|||
115 | ttl=ttl, |
|
|||
116 | ) |
|
114 | ) | |
117 |
|
115 | |||
|
116 | entries=[] | |||
118 | for entry in journal[:feed_nr]: |
|
117 | for entry in journal[:feed_nr]: | |
119 | user = entry.user |
|
118 | user = entry.user | |
120 | if user is None: |
|
119 | if user is None: | |
@@ -130,15 +129,16 b' class JournalController(BaseController):' | |||||
130 | _url = h.canonical_url('changelog_home', |
|
129 | _url = h.canonical_url('changelog_home', | |
131 | repo_name=entry.repository.repo_name) |
|
130 | repo_name=entry.repository.repo_name) | |
132 |
|
131 | |||
133 |
|
|
132 | entries.append(dict( | |
134 |
|
|
133 | title=title, | |
135 | link=_url or h.canonical_url(''), |
|
134 | pubdate=entry.action_date, | |
136 | author_email=user.email, |
|
135 | link=_url or h.canonical_url(''), | |
137 |
|
|
136 | author_email=user.email, | |
138 | description=action_extra()) |
|
137 | author_name=user.full_name_or_username, | |
|
138 | description=action_extra(), | |||
|
139 | )) | |||
139 |
|
140 | |||
140 | response.content_type = feed.mime_type |
|
141 | return feeder.render(header, entries) | |
141 | return feed.writeString('utf-8') |
|
|||
142 |
|
142 | |||
143 | def _atom_feed(self, repos, public=True): |
|
143 | def _atom_feed(self, repos, public=True): | |
144 | if public: |
|
144 | if public: | |
@@ -149,7 +149,7 b' class JournalController(BaseController):' | |||||
149 | link = h.canonical_url('journal_atom') |
|
149 | link = h.canonical_url('journal_atom') | |
150 | desc = '%s %s %s' % (c.site_name, _('Journal'), 'atom feed') |
|
150 | desc = '%s %s %s' % (c.site_name, _('Journal'), 'atom feed') | |
151 |
|
151 | |||
152 |
return self._feed(repos, Atom |
|
152 | return self._feed(repos, feeds.AtomFeed, link, desc) | |
153 |
|
153 | |||
154 | def _rss_feed(self, repos, public=True): |
|
154 | def _rss_feed(self, repos, public=True): | |
155 | if public: |
|
155 | if public: | |
@@ -160,7 +160,7 b' class JournalController(BaseController):' | |||||
160 | link = h.canonical_url('journal_atom') |
|
160 | link = h.canonical_url('journal_atom') | |
161 | desc = '%s %s %s' % (c.site_name, _('Journal'), 'rss feed') |
|
161 | desc = '%s %s %s' % (c.site_name, _('Journal'), 'rss feed') | |
162 |
|
162 | |||
163 |
return self._feed(repos, Rss |
|
163 | return self._feed(repos, feeds.RssFeed, link, desc) | |
164 |
|
164 | |||
165 | @LoginRequired() |
|
165 | @LoginRequired() | |
166 | def index(self): |
|
166 | def index(self): | |
@@ -192,9 +192,7 b' class JournalController(BaseController):' | |||||
192 |
|
192 | |||
193 | @LoginRequired() |
|
193 | @LoginRequired() | |
194 | def journal_atom(self): |
|
194 | def journal_atom(self): | |
195 | """ |
|
195 | """Produce a simple atom-1.0 feed""" | |
196 | Produce an atom-1.0 feed via feedgenerator module |
|
|||
197 | """ |
|
|||
198 | following = UserFollowing.query() \ |
|
196 | following = UserFollowing.query() \ | |
199 | .filter(UserFollowing.user_id == request.authuser.user_id) \ |
|
197 | .filter(UserFollowing.user_id == request.authuser.user_id) \ | |
200 | .options(joinedload(UserFollowing.follows_repository)) \ |
|
198 | .options(joinedload(UserFollowing.follows_repository)) \ | |
@@ -203,9 +201,7 b' class JournalController(BaseController):' | |||||
203 |
|
201 | |||
204 | @LoginRequired() |
|
202 | @LoginRequired() | |
205 | def journal_rss(self): |
|
203 | def journal_rss(self): | |
206 | """ |
|
204 | """Produce a simple rss2 feed""" | |
207 | Produce an rss feed via feedgenerator module |
|
|||
208 | """ |
|
|||
209 | following = UserFollowing.query() \ |
|
205 | following = UserFollowing.query() \ | |
210 | .filter(UserFollowing.user_id == request.authuser.user_id) \ |
|
206 | .filter(UserFollowing.user_id == request.authuser.user_id) \ | |
211 | .options(joinedload(UserFollowing.follows_repository)) \ |
|
207 | .options(joinedload(UserFollowing.follows_repository)) \ | |
@@ -261,9 +257,7 b' class JournalController(BaseController):' | |||||
261 |
|
257 | |||
262 | @LoginRequired(allow_default_user=True) |
|
258 | @LoginRequired(allow_default_user=True) | |
263 | def public_journal_atom(self): |
|
259 | def public_journal_atom(self): | |
264 | """ |
|
260 | """Produce a simple atom-1.0 feed""" | |
265 | Produce an atom-1.0 feed via feedgenerator module |
|
|||
266 | """ |
|
|||
267 | c.following = UserFollowing.query() \ |
|
261 | c.following = UserFollowing.query() \ | |
268 | .filter(UserFollowing.user_id == request.authuser.user_id) \ |
|
262 | .filter(UserFollowing.user_id == request.authuser.user_id) \ | |
269 | .options(joinedload(UserFollowing.follows_repository)) \ |
|
263 | .options(joinedload(UserFollowing.follows_repository)) \ | |
@@ -273,9 +267,7 b' class JournalController(BaseController):' | |||||
273 |
|
267 | |||
274 | @LoginRequired(allow_default_user=True) |
|
268 | @LoginRequired(allow_default_user=True) | |
275 | def public_journal_rss(self): |
|
269 | def public_journal_rss(self): | |
276 | """ |
|
270 | """Produce a simple rss2 feed""" | |
277 | Produce an rss2 feed via feedgenerator module |
|
|||
278 | """ |
|
|||
279 | c.following = UserFollowing.query() \ |
|
271 | c.following = UserFollowing.query() \ | |
280 | .filter(UserFollowing.user_id == request.authuser.user_id) \ |
|
272 | .filter(UserFollowing.user_id == request.authuser.user_id) \ | |
281 | .options(joinedload(UserFollowing.follows_repository)) \ |
|
273 | .options(joinedload(UserFollowing.follows_repository)) \ |
General Comments 0
You need to be logged in to leave comments.
Login now