feed.py
179 lines
| 7.0 KiB
| text/x-python
|
PythonLexer
r861 | # -*- coding: utf-8 -*- | |||
""" | ||||
rhodecode.controllers.feed | ||||
~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
Feed controller for rhodecode | ||||
r1203 | ||||
r861 | :created_on: Apr 23, 2010 | |||
:author: marcink | ||||
r1824 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> | |||
r861 | :license: GPLv3, see COPYING for more details. | |||
""" | ||||
r1206 | # This program is free software: you can redistribute it and/or modify | |||
# it under the terms of the GNU General Public License as published by | ||||
# the Free Software Foundation, either version 3 of the License, or | ||||
# (at your option) any later version. | ||||
r1203 | # | |||
r547 | # This program is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
r1203 | # | |||
r547 | # You should have received a copy of the GNU General Public License | |||
r1206 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
r861 | ||||
import logging | ||||
r1045 | from pylons import url, response, tmpl_context as c | |||
r1038 | from pylons.i18n.translation import _ | |||
r862 | ||||
r3018 | from beaker.cache import cache_region, region_invalidate | |||
r2385 | from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed | |||
from rhodecode.lib import helpers as h | ||||
r862 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator | |||
r1045 | from rhodecode.lib.base import BaseRepoController | |||
r3018 | from rhodecode.lib.diffs import DiffProcessor, LimitedDiffContainer | |||
from rhodecode.model.db import CacheInvalidation | ||||
r3292 | from rhodecode.lib.utils2 import safe_int, str2bool, safe_unicode | |||
r861 | ||||
r547 | log = logging.getLogger(__name__) | |||
r1212 | ||||
r1045 | class FeedController(BaseRepoController): | |||
r861 | ||||
r1120 | @LoginRequired(api_access=True) | |||
r862 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |||
'repository.admin') | ||||
r547 | def __before__(self): | |||
super(FeedController, self).__before__() | ||||
#common values for feeds | ||||
r1038 | self.description = _('Changes on %s repository') | |||
r1088 | self.title = self.title = _('%s %s feed') % (c.rhodecode_name, '%s') | |||
r547 | self.language = 'en-us' | |||
self.ttl = "5" | ||||
r3028 | import rhodecode | |||
CONF = rhodecode.CONFIG | ||||
self.include_diff = str2bool(CONF.get('rss_include_diff', False)) | ||||
self.feed_nr = safe_int(CONF.get('rss_items_per_page', 20)) | ||||
r3018 | # we need to protect from parsing huge diffs here other way | |||
r3028 | # we can kill the server | |||
r3030 | self.feed_diff_limit = safe_int(CONF.get('rss_cut_off_limit', 32 * 1024)) | |||
r547 | ||||
r1897 | def _get_title(self, cs): | |||
r2385 | return "%s" % ( | |||
h.shorter(cs.message, 160) | ||||
r1897 | ) | |||
r1162 | def __changes(self, cs): | |||
r1359 | changes = [] | |||
r3018 | diff_processor = DiffProcessor(cs.diff(), | |||
diff_limit=self.feed_diff_limit) | ||||
_parsed = diff_processor.prepare(inline_diff=False) | ||||
limited_diff = False | ||||
if isinstance(_parsed, LimitedDiffContainer): | ||||
limited_diff = True | ||||
for st in _parsed: | ||||
r3821 | st.update({'added': st['stats']['added'], | |||
'removed': st['stats']['deleted']}) | ||||
r2385 | changes.append('\n %(operation)s %(filename)s ' | |||
'(%(added)s lines added, %(removed)s lines removed)' | ||||
% st) | ||||
r3018 | if limited_diff: | |||
changes = changes + ['\n ' + | ||||
_('Changeset was too big and was cut off...')] | ||||
r3028 | return diff_processor, changes | |||
r1162 | ||||
r2385 | def __get_desc(self, cs): | |||
desc_msg = [] | ||||
|
r3654 | desc_msg.append((_('%s committed on %s') | ||
% (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>') | ||||
r2980 | #branches, tags, bookmarks | |||
if cs.branch: | ||||
desc_msg.append('branch: %s<br/>' % cs.branch) | ||||
if h.is_hg(c.rhodecode_repo): | ||||
for book in cs.bookmarks: | ||||
desc_msg.append('bookmark: %s<br/>' % book) | ||||
for tag in cs.tags: | ||||
desc_msg.append('tag: %s<br/>' % tag) | ||||
r3028 | diff_processor, changes = self.__changes(cs) | |||
r2980 | # rev link | |||
_url = url('changeset_home', repo_name=cs.repository.name, | ||||
revision=cs.raw_id, qualified=True) | ||||
|
r3654 | desc_msg.append('changeset: <a href="%s">%s</a>' % (_url, cs.raw_id[:8])) | ||
r2980 | ||||
r2385 | desc_msg.append('<pre>') | |||
desc_msg.append(cs.message) | ||||
desc_msg.append('\n') | ||||
r3028 | desc_msg.extend(changes) | |||
if self.include_diff: | ||||
desc_msg.append('\n\n') | ||||
desc_msg.append(diff_processor.as_raw()) | ||||
r2385 | desc_msg.append('</pre>') | |||
r3292 | return map(safe_unicode, desc_msg) | |||
r1162 | ||||
r547 | def atom(self, repo_name): | |||
"""Produce an atom-1.0 feed via feedgenerator module""" | ||||
r3018 | ||||
@cache_region('long_term') | ||||
|
r3773 | def _get_feed_from_cache(key, kind): | ||
r3018 | feed = Atom1Feed( | |||
title=self.title % repo_name, | ||||
link=url('summary_home', repo_name=repo_name, | ||||
qualified=True), | ||||
description=self.description % repo_name, | ||||
language=self.language, | ||||
ttl=self.ttl | ||||
) | ||||
r1897 | ||||
r3018 | for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])): | |||
feed.add_item(title=self._get_title(cs), | ||||
link=url('changeset_home', repo_name=repo_name, | ||||
revision=cs.raw_id, qualified=True), | ||||
author_name=cs.author, | ||||
description=''.join(self.__get_desc(cs)), | ||||
pubdate=cs.date, | ||||
) | ||||
r861 | ||||
r3018 | response.content_type = feed.mime_type | |||
return feed.writeString('utf-8') | ||||
|
r3773 | kind = 'ATOM' | ||
valid = CacheInvalidation.test_and_set_valid(repo_name, kind) | ||||
|
r3772 | if not valid: | ||
|
r3773 | region_invalidate(_get_feed_from_cache, None, repo_name, kind) | ||
return _get_feed_from_cache(repo_name, kind) | ||||
r547 | ||||
def rss(self, repo_name): | ||||
"""Produce an rss2 feed via feedgenerator module""" | ||||
r3018 | ||||
@cache_region('long_term') | ||||
|
r3773 | def _get_feed_from_cache(key, kind): | ||
r3018 | feed = Rss201rev2Feed( | |||
title=self.title % repo_name, | ||||
link=url('summary_home', repo_name=repo_name, | ||||
qualified=True), | ||||
description=self.description % repo_name, | ||||
language=self.language, | ||||
ttl=self.ttl | ||||
) | ||||
r1897 | ||||
r3018 | for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])): | |||
feed.add_item(title=self._get_title(cs), | ||||
link=url('changeset_home', repo_name=repo_name, | ||||
revision=cs.raw_id, qualified=True), | ||||
author_name=cs.author, | ||||
description=''.join(self.__get_desc(cs)), | ||||
pubdate=cs.date, | ||||
) | ||||
r861 | ||||
r3018 | response.content_type = feed.mime_type | |||
return feed.writeString('utf-8') | ||||
|
r3773 | kind = 'RSS' | ||
valid = CacheInvalidation.test_and_set_valid(repo_name, kind) | ||||
|
r3772 | if not valid: | ||
|
r3773 | region_invalidate(_get_feed_from_cache, None, repo_name, kind) | ||
return _get_feed_from_cache(repo_name, kind) | ||||