Server : Apache System : Linux iad1-shared-b8-43 6.6.49-grsec-jammy+ #10 SMP Thu Sep 12 23:23:08 UTC 2024 x86_64 User : dh_edsupp ( 6597262) PHP Version : 8.2.26 Disable Function : NONE Directory : /lib/python3/dist-packages/trac/wiki/ |
Upload File : |
# -*- coding: utf-8 -*- # # Copyright (C) 2003-2021 Edgewall Software # Copyright (C) 2003-2005 Jonas Borgström <jonas@edgewall.com> # Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de> # All rights reserved. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at https://trac.edgewall.org/wiki/TracLicense. # # This software consists of voluntary contributions made by many # individuals. For the exact contribution history, see the revision # history and logs, available at https://trac.edgewall.org/log/. # # Author: Jonas Borgström <jonas@edgewall.com> # Christopher Lenz <cmlenz@gmx.de> import pkg_resources import re from trac.attachment import AttachmentModule, Attachment from trac.config import IntOption from trac.core import * from trac.mimeview.api import IContentConverter, Mimeview from trac.perm import IPermissionPolicy, IPermissionRequestor from trac.resource import * from trac.search import ISearchSource, search_to_sql, shorten_result from trac.timeline.api import ITimelineEventProvider from trac.util import as_int, get_reporter_id from trac.util.datefmt import from_utimestamp, to_utimestamp from trac.util.html import tag from trac.util.text import shorten_line from trac.util.translation import _, tag_ from trac.versioncontrol.diff import get_diff_options, diff_blocks from trac.web.api import HTTPBadRequest, IRequestHandler from trac.web.chrome import (Chrome, INavigationContributor, ITemplateProvider, accesskey, add_ctxtnav, add_link, add_notice, add_script, add_stylesheet, add_warning, prevnext_nav, web_context) from trac.wiki.api import IWikiPageManipulator, WikiSystem, validate_page_name from trac.wiki.formatter import format_to, OneLinerFormatter from trac.wiki.model import WikiPage class WikiModule(Component): implements(IContentConverter, INavigationContributor, IPermissionRequestor, IRequestHandler, ITimelineEventProvider, ISearchSource, ITemplateProvider) page_manipulators = ExtensionPoint(IWikiPageManipulator) realm = WikiSystem.realm max_size = IntOption('wiki', 'max_size', 262144, """Maximum allowed wiki page size in characters.""") default_edit_area_height = IntOption('wiki', 'default_edit_area_height', 20, """Default height of the textarea on the wiki edit page. (//Since 1.1.5//)""") START_PAGE = property(lambda self: WikiSystem.START_PAGE) TITLE_INDEX_PAGE = property(lambda self: WikiSystem.TITLE_INDEX_PAGE) PAGE_TEMPLATES_PREFIX = 'PageTemplates/' DEFAULT_PAGE_TEMPLATE = 'DefaultPage' # IContentConverter methods def get_supported_conversions(self): yield ('txt', _("Plain Text"), 'txt', 'text/x-trac-wiki', 'text/plain', 9) def convert_content(self, req, mimetype, content, key): return content, 'text/plain;charset=utf-8' # INavigationContributor methods def get_active_navigation_item(self, req): return 'wiki' def get_navigation_items(self, req): if 'WIKI_VIEW' in req.perm(self.realm, self.START_PAGE): yield ('mainnav', 'wiki', tag.a(_("Wiki"), href=req.href.wiki(), accesskey=accesskey(req, 1))) if 'WIKI_VIEW' in req.perm(self.realm, 'TracGuide'): yield ('metanav', 'help', tag.a(_("Help/Guide"), href=req.href.wiki('TracGuide'), accesskey=accesskey(req, 6))) # IPermissionRequestor methods def get_permission_actions(self): actions = ['WIKI_CREATE', 'WIKI_DELETE', 'WIKI_MODIFY', 'WIKI_RENAME', 'WIKI_VIEW'] return actions + [('WIKI_ADMIN', actions)] # IRequestHandler methods def match_request(self, req): match = re.match(r'/wiki(?:/(.+))?$', req.path_info) if match: if match.group(1): req.args['page'] = match.group(1) return 1 def process_request(self, req): action = req.args.get('action', 'view') pagename = req.args.get('page', self.START_PAGE) version = None if req.args.get('version'): # Allow version to be empty version = req.args.getint('version') old_version = req.args.getint('old_version') if pagename.startswith('/') or pagename.endswith('/') or \ '//' in pagename: pagename = re.sub(r'/{2,}', '/', pagename.strip('/')) req.redirect(req.href.wiki(pagename)) if not validate_page_name(pagename): raise TracError(_("Invalid Wiki page name '%(name)s'", name=pagename)) page = WikiPage(self.env, pagename) versioned_page = WikiPage(self.env, pagename, version) req.perm(versioned_page.resource).require('WIKI_VIEW') if version and versioned_page.version != version: raise ResourceNotFound( _('No version "%(num)s" for Wiki page "%(name)s"', num=version, name=page.name)) add_stylesheet(req, 'common/css/wiki.css') if req.method == 'POST': if action == 'edit': if 'cancel' in req.args: req.redirect(req.href.wiki(page.name)) has_collision = version != page.version for a in ('preview', 'diff', 'merge'): if a in req.args: action = a break versioned_page.text = req.args.get('text') valid = self._validate(req, versioned_page) if action == 'edit' and not has_collision and valid: return self._do_save(req, versioned_page) else: return self._render_editor(req, page, action, has_collision) elif action == 'edit_comment': self._do_edit_comment(req, versioned_page) elif action == 'delete': self._do_delete(req, versioned_page) elif action == 'rename': return self._do_rename(req, page) elif action == 'diff': style, options, diff_data = get_diff_options(req) contextall = diff_data['options']['contextall'] req.redirect(req.href.wiki(versioned_page.name, action='diff', old_version=old_version, version=version, contextall=contextall or None)) else: raise HTTPBadRequest(_("Invalid request arguments.")) elif action == 'delete': return self._render_confirm_delete(req, page) elif action == 'rename': return self._render_confirm_rename(req, page) elif action == 'edit': return self._render_editor(req, page) elif action == 'edit_comment': return self._render_edit_comment(req, versioned_page) elif action == 'diff': return self._render_diff(req, versioned_page) elif action == 'history': return self._render_history(req, versioned_page) else: format = req.args.get('format') if format: Mimeview(self.env).send_converted(req, 'text/x-trac-wiki', versioned_page.text, format, versioned_page.name) return self._render_view(req, versioned_page) # ITemplateProvider methods def get_htdocs_dirs(self): return [] def get_templates_dirs(self): return [pkg_resources.resource_filename('trac.wiki', 'templates')] # Internal methods def _validate(self, req, page): valid = True # Validate page size if len(req.args.get('text', '')) > self.max_size: add_warning(req, _("The wiki page is too long (must be less " "than %(num)s characters)", num=self.max_size)) valid = False # Give the manipulators a pass at post-processing the page for manipulator in self.page_manipulators: for field, message in manipulator.validate_wiki_page(req, page): valid = False if field: add_warning(req, tag_("The Wiki page field %(field)s" " is invalid: %(message)s", field=tag.strong(field), message=message)) else: add_warning(req, tag_("Invalid Wiki page: %(message)s", message=message)) return valid def _page_data(self, req, page, action=''): title = get_resource_summary(self.env, page.resource) if action: title += ' (%s)' % action return {'page': page, 'action': action, 'title': title} def _prepare_diff(self, req, page, old_text, new_text, old_version, new_version): diff_style, diff_options, diff_data = get_diff_options(req) diff_context = 3 for option in diff_options: if option.startswith('-U'): diff_context = int(option[2:]) break if diff_context < 0: diff_context = None diffs = diff_blocks(old_text, new_text, context=diff_context, ignore_blank_lines='-B' in diff_options, ignore_case='-i' in diff_options, ignore_space_changes='-b' in diff_options) def version_info(v, last=0): return {'path': get_resource_name(self.env, page.resource), # TRANSLATOR: wiki page 'rev': v or _("currently edited"), 'shortrev': v or last + 1, 'href': req.href.wiki(page.name, version=v) if v else None} changes = [{'diffs': diffs, 'props': [], 'new': version_info(new_version, old_version), 'old': version_info(old_version)}] add_stylesheet(req, 'common/css/diff.css') add_script(req, 'common/js/diff.js') return diff_data, changes def _do_edit_comment(self, req, page): req.perm(page.resource).require('WIKI_ADMIN') redirect_to = req.args.get('redirect_to') version = old_version = None if redirect_to == 'diff': version = page.version old_version = version - 1 redirect_href = req.href.wiki(page.name, action=redirect_to, version=version, old_version=old_version) if 'cancel' in req.args: req.redirect(redirect_href) new_comment = req.args.get('new_comment') page.edit_comment(new_comment) add_notice(req, _("The comment of version %(version)s of the page " "%(name)s has been updated.", version=page.version, name=page.name)) req.redirect(redirect_href) def _do_delete(self, req, page): req.perm(page.resource).require('WIKI_DELETE') if 'cancel' in req.args: req.redirect(get_resource_url(self.env, page.resource, req.href)) version = req.args.getint('version') old_version = req.args.getint('old_version', version) with self.env.db_transaction: if version and old_version and version > old_version: # delete from `old_version` exclusive to `version` inclusive: for v in range(old_version, version): page.delete(v + 1) else: # only delete that `version`, or the whole page if `None` page.delete(version) if not page.exists: add_notice(req, _("The page %(name)s has been deleted.", name=page.name)) req.redirect(req.href.wiki()) else: if version and old_version and version > old_version + 1: add_notice(req, _("The versions %(from_)d to %(to)d of the " "page %(name)s have been deleted.", from_=old_version + 1, to=version, name=page.name)) else: add_notice(req, _("The version %(version)d of the page " "%(name)s has been deleted.", version=version, name=page.name)) req.redirect(req.href.wiki(page.name)) def _do_rename(self, req, page): req.perm(page.resource).require('WIKI_RENAME') if 'cancel' in req.args: req.redirect(get_resource_url(self.env, page.resource, req.href)) old_name, old_version = page.name, page.version new_name = req.args.get('new_name', '') new_name = re.sub(r'/{2,}', '/', new_name.strip('/')) redirect = req.args.get('redirect') # verify input parameters warn = None if not new_name: warn = _("A new name is mandatory for a rename.") elif not validate_page_name(new_name): warn = _("The new name is invalid (a name which is separated " "with slashes cannot be '.' or '..').") elif new_name == old_name: warn = _("The new name must be different from the old name.") elif WikiPage(self.env, new_name).exists: warn = _("The page %(name)s already exists.", name=new_name) if warn: add_warning(req, warn) return self._render_confirm_rename(req, page, new_name) with self.env.db_transaction as db: page.rename(new_name) if redirect: redirection = WikiPage(self.env, old_name) redirection.text = _('See [wiki:"%(name)s"].', name=new_name) author = get_reporter_id(req) comment = '[wiki:"%s@%d" %s] \u2192 [wiki:"%s"].' % ( new_name, old_version, old_name, new_name) redirection.save(author, comment) add_notice(req, _("The page %(old_name)s has been renamed to " "%(new_name)s.", old_name=old_name, new_name=new_name)) if redirect: add_notice(req, _("The page %(old_name)s has been recreated " "with a redirect to %(new_name)s.", old_name=old_name, new_name=new_name)) req.redirect(req.href.wiki(old_name if redirect else new_name)) def _do_save(self, req, page): if not page.exists: req.perm(page.resource).require('WIKI_CREATE') else: req.perm(page.resource).require('WIKI_MODIFY') if 'WIKI_CHANGE_READONLY' in req.perm(page.resource): # Modify the read-only flag if it has been changed and the user is # WIKI_ADMIN page.readonly = int('readonly' in req.args) try: page.save(get_reporter_id(req, 'author'), req.args.get('comment')) except TracError: add_warning(req, _("Page not modified, showing latest version.")) return self._render_view(req, page) href = req.href.wiki(page.name, action='diff', version=page.version) add_notice(req, tag_("Your changes have been saved in version " "%(version)s (%(diff)s).", version=page.version, diff=tag.a(_("diff"), href=href))) req.redirect(get_resource_url(self.env, page.resource, req.href, version=None)) def _render_confirm_delete(self, req, page): req.perm(page.resource).require('WIKI_DELETE') version = None if 'delete_version' in req.args: version = req.args.getint('version', 0) old_version = req.args.getint('old_version', version) what = 'multiple' if version and old_version \ and version - old_version > 1 \ else 'single' if version else 'page' num_versions = 0 new_date = None old_date = None for v, t, author, comment in page.get_history(): if (what == 'page' or v <= version) and new_date is None: new_date = t if (what == 'multiple' and v <= old_version or what == 'single' and num_versions > 1): break num_versions += 1 old_date = t data = self._page_data(req, page, 'delete') attachments = Attachment.select(self.env, self.realm, page.name) data.update({ 'what': what, 'new_version': None, 'old_version': None, 'num_versions': num_versions, 'new_date': new_date, 'old_date': old_date, 'attachments': list(attachments), }) if version is not None: data.update({'new_version': version, 'old_version': old_version}) self._wiki_ctxtnav(req, page) return 'wiki_delete.html', data def _render_confirm_rename(self, req, page, new_name=None): req.perm(page.resource).require('WIKI_RENAME') data = self._page_data(req, page, 'rename') data['new_name'] = new_name if new_name is not None else page.name self._wiki_ctxtnav(req, page) return 'wiki_rename.html', data def _render_diff(self, req, page): if not page.exists: raise TracError(_("Version %(num)s of page \"%(name)s\" does not " "exist", num=req.args.get('version'), name=page.name)) old_version = req.args.getint('old_version') if old_version: if old_version == page.version: old_version = None elif old_version > page.version: # FIXME: what about reverse diffs? old_version = page.resource.version page = WikiPage(self.env, page.name, old_version) req.perm(page.resource).require('WIKI_VIEW') latest_page = WikiPage(self.env, page.name) req.perm(latest_page.resource).require('WIKI_VIEW') new_version = page.version date = author = comment = None num_changes = 0 prev_version = next_version = None for version, t, a, c in latest_page.get_history(): if version == new_version: date = t author = a or 'anonymous' comment = c or '--' else: if version < new_version: num_changes += 1 if not prev_version: prev_version = version if old_version is None or version == old_version: old_version = version break else: next_version = version if not old_version: old_version = 0 old_page = WikiPage(self.env, page.name, old_version) req.perm(old_page.resource).require('WIKI_VIEW') # -- text diffs old_text = old_page.text.splitlines() new_text = page.text.splitlines() diff_data, changes = self._prepare_diff(req, page, old_text, new_text, old_version, new_version) # -- prev/up/next links if prev_version: add_link(req, 'prev', req.href.wiki(page.name, action='diff', version=prev_version), _("Version %(num)s", num=prev_version)) add_link(req, 'up', req.href.wiki(page.name, action='history'), _('Page history')) if next_version: add_link(req, 'next', req.href.wiki(page.name, action='diff', version=next_version), _("Version %(num)s", num=next_version)) data = self._page_data(req, page, 'diff') data.update({ 'change': {'date': date, 'author': author, 'comment': comment}, 'new_version': new_version, 'old_version': old_version, 'latest_version': latest_page.version, 'num_changes': num_changes, 'longcol': 'Version', 'shortcol': 'v', 'changes': changes, 'diff': diff_data, 'can_edit_comment': 'WIKI_ADMIN' in req.perm(page.resource), }) prevnext_nav(req, _("Previous Change"), _("Next Change"), _("Wiki History")) return 'wiki_diff.html', data def _render_editor(self, req, page, action='edit', has_collision=False): if has_collision: if action == 'merge': page = WikiPage(self.env, page.name) req.perm(page.resource).require('WIKI_VIEW') else: action = 'collision' if not page.exists: req.perm(page.resource).require('WIKI_CREATE') else: req.perm(page.resource).require('WIKI_MODIFY') original_text = page.text comment = req.args.get('comment', '') if 'text' in req.args: page.text = req.args.get('text') elif 'template' in req.args: template = req.args.get('template') template = template[1:] if template.startswith('/') \ else self.PAGE_TEMPLATES_PREFIX + template template_page = WikiPage(self.env, template) if template_page and template_page.exists and \ 'WIKI_VIEW' in req.perm(template_page.resource): page.text = template_page.text elif 'version' in req.args: version = None if req.args.get('version'): # Allow version to be empty version = req.args.as_int('version') if version is not None: old_page = WikiPage(self.env, page.name, version) req.perm(page.resource).require('WIKI_VIEW') page.text = old_page.text comment = _("Reverted to version %(version)s.", version=version) if action in ('preview', 'diff'): page.readonly = 'readonly' in req.args author = get_reporter_id(req, 'author') defaults = {'editrows': str(self.default_edit_area_height)} prefs = {key: req.session.get('wiki_%s' % key, defaults.get(key)) for key in ('editrows', 'sidebyside')} if 'from_editor' in req.args: sidebyside = req.args.get('sidebyside') or None if sidebyside != prefs['sidebyside']: req.session.set('wiki_sidebyside', int(bool(sidebyside)), 0) else: sidebyside = prefs['sidebyside'] if sidebyside: editrows = max(int(prefs['editrows']), len(page.text.splitlines()) + 1) else: editrows = req.args.get('editrows') if editrows: if editrows != prefs['editrows']: req.session.set('wiki_editrows', editrows, defaults['editrows']) else: editrows = prefs['editrows'] data = self._page_data(req, page, action) context = web_context(req, page.resource) data.update({ 'context': context, 'author': author, 'comment': comment, 'edit_rows': editrows, 'sidebyside': sidebyside, 'scroll_bar_pos': req.args.get('scroll_bar_pos', ''), 'diff': None, 'attachments': AttachmentModule(self.env).attachment_data(context) }) if action in ('diff', 'merge'): old_text = original_text.splitlines() if original_text else [] new_text = page.text.splitlines() if page.text else [] diff_data, changes = self._prepare_diff( req, page, old_text, new_text, page.version, '') data.update({'diff': diff_data, 'changes': changes, 'action': 'preview', 'merge': action == 'merge', 'longcol': 'Version', 'shortcol': 'v'}) elif sidebyside and action != 'collision': data['action'] = 'preview' self._wiki_ctxtnav(req, page) Chrome(self.env).add_wiki_toolbars(req) Chrome(self.env).add_auto_preview(req) add_script(req, 'common/js/wiki.js') return 'wiki_edit.html', data def _render_edit_comment(self, req, page): req.perm(page.resource).require('WIKI_ADMIN') data = self._page_data(req, page, 'edit_comment') data.update({'redirect_to': req.args.get('redirect_to', 'history')}) self._wiki_ctxtnav(req, page) return 'wiki_edit_comment.html', data def _render_history(self, req, page): """Extract the complete history for a given page. This information is used to present a changelog/history for a given page. """ if not page.exists: raise TracError(_("Page %(name)s does not exist", name=page.name)) data = self._page_data(req, page, 'history') history = [] for version, date, author, comment in page.get_history(): history.append({ 'version': version, 'date': date, 'author': author, 'comment': comment or '' }) data.update({ 'history': history, 'resource': page.resource, 'can_edit_comment': 'WIKI_ADMIN' in req.perm(page.resource) }) add_ctxtnav(req, _("Back to %(wikipage)s", wikipage=page.name), req.href.wiki(page.name)) return 'history_view.html', data def _render_view(self, req, page): version = page.resource.version # Add registered converters if page.exists: for conversion in Mimeview(self.env) \ .get_supported_conversions('text/x-trac-wiki'): conversion_href = req.href.wiki(page.name, version=version, format=conversion.key) add_link(req, 'alternate', conversion_href, conversion.name, conversion.in_mimetype) data = self._page_data(req, page) if page.name == self.START_PAGE: data['title'] = '' ws = WikiSystem(self.env) context = web_context(req, page.resource) higher, related = [], [] if not page.exists: if 'WIKI_CREATE' not in req.perm(page.resource): raise ResourceNotFound(_("Page %(name)s not found", name=page.name)) formatter = OneLinerFormatter(self.env, context) if '/' in page.name: parts = page.name.split('/') for i in range(len(parts) - 2, -1, -1): name = '/'.join(parts[:i] + [parts[-1]]) if not ws.has_page(name): higher.append(ws._format_link(formatter, 'wiki', '/' + name, name, False)) else: name = page.name name = name.lower() related = [each for each in ws.pages if name in each.lower() and 'WIKI_VIEW' in req.perm(self.realm, each)] related.sort() related = [ws._format_link(formatter, 'wiki', '/' + each, each, False) for each in related] latest_page = WikiPage(self.env, page.name) prev_version = next_version = None if version: version = as_int(version, None) if version is not None: for hist in latest_page.get_history(): v = hist[0] if v != version: if v < version: if not prev_version: prev_version = v break else: next_version = v prefix = self.PAGE_TEMPLATES_PREFIX templates = [template[len(prefix):] for template in ws.get_pages(prefix) if 'WIKI_VIEW' in req.perm(self.realm, template)] # -- prev/up/next links if prev_version: add_link(req, 'prev', req.href.wiki(page.name, version=prev_version), _("Version %(num)s", num=prev_version)) parent = None if version: add_link(req, 'up', req.href.wiki(page.name, version=None), _("View latest version")) elif '/' in page.name: parent = page.name[:page.name.rindex('/')] add_link(req, 'up', req.href.wiki(parent, version=None), _("View parent page")) if next_version: add_link(req, 'next', req.href.wiki(page.name, version=next_version), _('Version %(num)s', num=next_version)) # Add ctxtnav entries if version: prevnext_nav(req, _("Previous Version"), _("Next Version"), _("View Latest Version")) else: if parent: add_ctxtnav(req, _('Up'), req.href.wiki(parent)) self._wiki_ctxtnav(req, page) # Plugin content validation fields = {'text': page.text} for manipulator in self.page_manipulators: manipulator.prepare_wiki_page(req, page, fields) text = fields.get('text', '') data.update({ 'context': context, 'text': text, 'latest_version': latest_page.version, 'attachments': AttachmentModule(self.env).attachment_data(context), 'start_page': self.START_PAGE, 'default_template': self.DEFAULT_PAGE_TEMPLATE, 'templates': templates, 'version': version, 'higher': higher, 'related': related, 'resourcepath_template': 'wiki_page_path.html', 'fullwidth': req.session.get('wiki_fullwidth'), }) add_script(req, 'common/js/wiki.js') return 'wiki_view.html', data def _wiki_ctxtnav(self, req, page): """Add the normal wiki ctxtnav entries.""" if 'WIKI_VIEW' in req.perm('wiki', self.START_PAGE): add_ctxtnav(req, _("Start Page"), req.href.wiki(self.START_PAGE)) if 'WIKI_VIEW' in req.perm('wiki', self.TITLE_INDEX_PAGE): add_ctxtnav(req, _("Index"), req.href.wiki(self.TITLE_INDEX_PAGE)) if page.exists: add_ctxtnav(req, _("History"), req.href.wiki(page.name, action='history')) # ITimelineEventProvider methods def get_timeline_filters(self, req): if 'WIKI_VIEW' in req.perm: yield ('wiki', _('Wiki changes')) def get_timeline_events(self, req, start, stop, filters): if 'wiki' in filters: wiki_realm = Resource(self.realm) for ts, name, comment, author, version in self.env.db_query(""" SELECT time, name, comment, author, version FROM wiki WHERE time>=%s AND time<=%s """, (to_utimestamp(start), to_utimestamp(stop))): wiki_page = wiki_realm(id=name, version=version) if 'WIKI_VIEW' not in req.perm(wiki_page): continue yield ('wiki', from_utimestamp(ts), author, (wiki_page, comment)) # Attachments for event in AttachmentModule(self.env).get_timeline_events( req, wiki_realm, start, stop): yield event def render_timeline_event(self, context, field, event): wiki_page, comment = event[3] if field == 'url': return context.href.wiki(wiki_page.id, version=wiki_page.version) elif field == 'title': name = tag.em(get_resource_name(self.env, wiki_page)) if wiki_page.version > 1: return tag_("%(page)s edited", page=name) else: return tag_("%(page)s created", page=name) elif field == 'description': markup = format_to(self.env, None, context.child(resource=wiki_page), comment) if wiki_page.version > 1: diff_href = context.href.wiki( wiki_page.id, version=wiki_page.version, action='diff') markup = tag(markup, " (", tag.a(_("diff"), href=diff_href), ")") return markup # ISearchSource methods def get_search_filters(self, req): if 'WIKI_VIEW' in req.perm: yield ('wiki', _('Wiki')) def get_search_results(self, req, terms, filters): if 'wiki' not in filters: return with self.env.db_query as db: sql_query, args = search_to_sql(db, ['w1.name', 'w1.author', 'w1.text'], terms) wiki_realm = Resource(self.realm) for name, ts, author, text in db(""" SELECT w1.name, w1.time, w1.author, w1.text FROM wiki w1,(SELECT name, max(version) AS ver FROM wiki GROUP BY name) w2 WHERE w1.version = w2.ver AND w1.name = w2.name AND """ + sql_query, args): page = wiki_realm(id=name) if 'WIKI_VIEW' in req.perm(page): yield (get_resource_url(self.env, page, req.href), '%s: %s' % (name, shorten_line(text)), from_utimestamp(ts), author, shorten_result(text, terms)) # Attachments for result in AttachmentModule(self.env).get_search_results( req, wiki_realm, terms): yield result class DefaultWikiPolicy(Component): """Default permission policy for the wiki system. Wiki pages with the read-only attribute require `WIKI_ADMIN` to delete, modify or rename the page. """ implements(IPermissionPolicy) realm = WikiSystem.realm # IPermissionPolicy methods def check_permission(self, action, username, resource, perm): if resource and resource.realm == self.realm: if action == 'WIKI_CHANGE_READONLY': return 'WIKI_ADMIN' in perm(resource) if action in ('WIKI_DELETE', 'WIKI_MODIFY', 'WIKI_RENAME'): page = WikiPage(self.env, resource) if page.readonly and 'WIKI_ADMIN' not in perm(resource): return False