def wiki_page_renamed(self, page, old_name): """Called when a page has been renamed (since Trac 0.12).""" self.log.debug("Moving wiki page tags from %s to %s", old_name, page.name) tag_sys = TagSystem(self.env) # XXX Ugh. Hopefully this will be sufficient to fool any endpoints. from trac.test import Mock, MockPerm req = Mock(authname='anonymous', perm=MockPerm()) tag_sys.reparent_tags(req, Resource('wiki', page.name), old_name)
def wiki_page_renamed(self, page, old_name): """Called when a page has been renamed (since Trac 0.12).""" new_resource = Resource('wiki', page.name) old_resource = Resource('wiki', old_name) self.log.debug("Moving tags from %s to %s", old_resource.id, new_resource.id) tag_system = TagSystem(self.env) # XXX Ugh. Hopefully this will be sufficient to fool any endpoints. from trac.test import Mock, MockPerm req = Mock(authname='anonymous', perm=MockPerm()) tag_system.reparent_tags(req, old_resource, new_resource)
class WikiTagInterface(TagTemplateProvider): """[main] Implements the user interface for tagging Wiki pages.""" implements(IRequestFilter, ITemplateStreamFilter, IWikiChangeListener, IWikiPageManipulator) def __init__(self): self.tag_system = TagSystem(self.env) # IRequestFilter methods def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type): if template is not None: if req.method == 'GET' and req.path_info.startswith('/wiki/'): if req.args.get('action') == 'edit' and \ req.args.get('template') and 'tags' not in req.args: self._post_process_request_edit(req) if req.args.get('action') == 'history' and \ data and 'history' in data: self._post_process_request_history(req, data) elif req.method == 'POST' and \ req.path_info.startswith('/wiki/') and \ 'save' in req.args: requests.reset() return template, data, content_type # ITemplateStreamFilter methods def filter_stream(self, req, method, filename, stream, data): page_name = req.args.get('page', 'WikiStart') resource = Resource('wiki', page_name) if filename == 'wiki_view.html' and 'TAGS_VIEW' in req.perm(resource): return self._wiki_view(req, stream) elif filename == 'wiki_edit.html' and \ 'TAGS_MODIFY' in req.perm(resource): return self._wiki_edit(req, stream) elif filename == 'history_view.html' and \ 'TAGS_VIEW' in req.perm(resource): return self._wiki_history(req, stream) return stream # IWikiPageManipulator methods def prepare_wiki_page(self, req, page, fields): pass def validate_wiki_page(self, req, page): # If we're saving the wiki page, and can modify tags, do so. if req and 'TAGS_MODIFY' in req.perm(page.resource) \ and req.path_info.startswith('/wiki') and 'save' in req.args: page_modified = req.args.get('text') != page.old_text or \ page.readonly != int('readonly' in req.args) if page_modified: requests.set(req) req.add_redirect_listener(self._redirect_listener) elif page.version > 0: # If the page hasn't been otherwise modified, save tags and # redirect to avoid the "page has not been modified" warning. if self._update_tags(req, page): req.redirect( get_resource_url(self.env, page.resource, req.href, version=None)) return [] # IWikiChangeListener methods def wiki_page_added(self, page): req = requests.get() if req: self._update_tags(req, page, page.time) def wiki_page_changed(self, page, version, t, comment, author, ipnr): req = requests.get() if req: self._update_tags(req, page, page.time) def wiki_page_renamed(self, page, old_name): """Called when a page has been renamed (since Trac 0.12).""" self.log.debug("Moving wiki page tags from %s to %s", old_name, page.name) req = MockReq() self.tag_system.reparent_tags(req, Resource('wiki', page.name), old_name) def wiki_page_deleted(self, page): # Page gone, so remove all records on it. delete_tags(self.env, page.resource, purge=True) def wiki_page_version_deleted(self, page): pass # Internal methods def _page_tags(self, req): pagename = req.args.get('page', 'WikiStart') version = req.args.get('version') tags_version = req.args.get('tags_version') page = WikiPage(self.env, pagename, version=version) resource = page.resource if version and not tags_version: tags_version = page.time tags = sorted( self.tag_system.get_tags(req, resource, when=tags_version)) return tags def _redirect_listener(self, req, url, permanent): requests.reset() def _post_process_request_edit(self, req): # Retrieve template resource to be queried for tags. template_pagename = ''.join( [WikiModule.PAGE_TEMPLATES_PREFIX, req.args.get('template')]) template_page = WikiPage(self.env, template_pagename) if template_page.exists and \ 'TAGS_VIEW' in req.perm(template_page.resource): tags = sorted(self.tag_system.get_tags(req, template_page.resource)) # Prepare tags as content for the editor field. tags_str = ' '.join(tags) self.env.log.debug("Tags retrieved from template: '%s'", unicode(tags_str).encode('utf-8')) # DEVEL: More arguments need to be propagated here? req.redirect( req.href(req.path_info, action='edit', tags=tags_str, template=req.args.get('template'))) def _post_process_request_history(self, req, data): history = [] page_histories = data.get('history', []) resource = data['resource'] tags_histories = tag_changes(self.env, resource) for page_history in page_histories: while tags_histories and \ tags_histories[0][0] >= page_history['date']: tags_history = tags_histories.pop(0) date = tags_history[0] author = tags_history[1] comment = render_tag_changes(tags_history[2], tags_history[3]) url = req.href(resource.realm, resource.id, version=page_history['version'], tags_version=to_utimestamp(date)) history.append({ 'version': '*', 'url': url, 'date': date, 'author': author, 'comment': comment, 'ipnr': '' }) history.append(page_history) data.update( dict(history=history, wiki_to_oneliner=self._wiki_to_oneliner)) def _wiki_view(self, req, stream): add_stylesheet(req, 'tags/css/tractags.css') tags = self._page_tags(req) if not tags: return stream li = [] for tag_ in tags: resource = Resource('tag', tag_) anchor = render_resource_link(self.env, web_context(req, resource), resource) anchor = anchor(rel='tag') li.append(tag.li(anchor, ' ')) # TRANSLATOR: Header label text for tag list at wiki page bottom. insert = tag.ul(class_='tags')(tag.li(_("Tags"), class_='header'), li) return stream | ( Transformer('//div[contains(@class,"wikipage")]').after(insert)) def _update_tags(self, req, page, when=None): newtags = split_into_tags(req.args.get('tags', '')) oldtags = self.tag_system.get_tags(req, page.resource) if oldtags != newtags: self.tag_system.set_tags(req, page.resource, newtags, when=when) return True return False def _wiki_edit(self, req, stream): # TRANSLATOR: Label text for link to '/tags'. link = tag.a(_("view all tags"), href=req.href.tags()) # TRANSLATOR: ... (view all tags) insert = tag(Markup(_("Tag under: (%(tags_link)s)", tags_link=link))) insert( tag.br(), tag.input(id='tags', type='text', name='tags', size='50', value=req.args.get('tags', ' '.join(self._page_tags(req))))) insert = tag.div(tag.label(insert), class_='field') return stream | Transformer('//div[@id="changeinfo1"]').append(insert) def _wiki_history(self, req, stream): xpath = '//input[@type="radio" and @value="*"]' stream = stream | Transformer(xpath).remove() # Remove invalid links to wiki page revisions (fix for Trac < 0.12). xpath = '//a[contains(@href,"%2A")]' return stream | Transformer(xpath).remove() def _wiki_to_oneliner(self, context, wiki, shorten=None): if isinstance(wiki, Fragment): return wiki return format_to_oneliner(self.env, context, wiki, shorten=shorten)
class WikiTagInterface(TagTemplateProvider): """[main] Implements the user interface for tagging Wiki pages.""" implements(IRequestFilter, ITemplateStreamFilter, IWikiChangeListener, IWikiPageManipulator) def __init__(self): self.tag_system = TagSystem(self.env) # IRequestFilter methods def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type): if template is not None: if req.method == 'GET' and req.path_info.startswith('/wiki/'): if req.args.get('action') == 'edit' and \ req.args.get('template') and 'tags' not in req.args: self._post_process_request_edit(req) if req.args.get('action') == 'history' and \ data and 'history' in data: self._post_process_request_history(req, data) elif req.method == 'POST' and \ req.path_info.startswith('/wiki/') and \ 'save' in req.args: requests.reset() return template, data, content_type # ITemplateStreamFilter methods def filter_stream(self, req, method, filename, stream, data): page_name = req.args.get('page', 'WikiStart') resource = Resource('wiki', page_name) if filename == 'wiki_view.html' and 'TAGS_VIEW' in req.perm(resource): return self._wiki_view(req, stream) elif filename == 'wiki_edit.html' and \ 'TAGS_MODIFY' in req.perm(resource): return self._wiki_edit(req, stream) elif filename == 'history_view.html' and \ 'TAGS_VIEW' in req.perm(resource): return self._wiki_history(req, stream) return stream # IWikiPageManipulator methods def prepare_wiki_page(self, req, page, fields): pass def validate_wiki_page(self, req, page): # If we're saving the wiki page, and can modify tags, do so. if req and 'TAGS_MODIFY' in req.perm(page.resource) \ and req.path_info.startswith('/wiki') and 'save' in req.args: page_modified = req.args.get('text') != page.old_text or \ page.readonly != int('readonly' in req.args) if page_modified: requests.set(req) req.add_redirect_listener(self._redirect_listener) elif page.version > 0: # If the page hasn't been otherwise modified, save tags and # redirect to avoid the "page has not been modified" warning. if self._update_tags(req, page): req.redirect(get_resource_url(self.env, page.resource, req.href, version=None)) return [] # IWikiChangeListener methods def wiki_page_added(self, page): req = requests.get() if req: self._update_tags(req, page, page.time) def wiki_page_changed(self, page, version, t, comment, author, ipnr): req = requests.get() if req: self._update_tags(req, page, page.time) def wiki_page_renamed(self, page, old_name): """Called when a page has been renamed (since Trac 0.12).""" self.log.debug("Moving wiki page tags from %s to %s", old_name, page.name) req = MockReq() self.tag_system.reparent_tags(req, Resource('wiki', page.name), old_name) def wiki_page_deleted(self, page): # Page gone, so remove all records on it. delete_tags(self.env, page.resource, purge=True) def wiki_page_version_deleted(self, page): pass # Internal methods def _page_tags(self, req): pagename = req.args.get('page', 'WikiStart') version = req.args.get('version') tags_version = req.args.get('tags_version') page = WikiPage(self.env, pagename, version=version) resource = page.resource if version and not tags_version: tags_version = page.time tags = sorted(self.tag_system.get_tags(req, resource, when=tags_version)) return tags def _redirect_listener(self, req, url, permanent): requests.reset() def _post_process_request_edit(self, req): # Retrieve template resource to be queried for tags. template_pagename = ''.join([WikiModule.PAGE_TEMPLATES_PREFIX, req.args.get('template')]) template_page = WikiPage(self.env, template_pagename) if template_page.exists and \ 'TAGS_VIEW' in req.perm(template_page.resource): tags = sorted(self.tag_system.get_tags(req, template_page.resource)) # Prepare tags as content for the editor field. tags_str = ' '.join(tags) self.env.log.debug("Tags retrieved from template: '%s'", unicode(tags_str).encode('utf-8')) # DEVEL: More arguments need to be propagated here? req.redirect(req.href(req.path_info, action='edit', tags=tags_str, template=req.args.get('template'))) def _post_process_request_history(self, req, data): history = [] page_histories = data.get('history', []) resource = data['resource'] tags_histories = tag_changes(self.env, resource) for page_history in page_histories: while tags_histories and \ tags_histories[0][0] >= page_history['date']: tags_history = tags_histories.pop(0) date = tags_history[0] author = tags_history[1] comment = render_tag_changes(tags_history[2], tags_history[3]) url = req.href(resource.realm, resource.id, version=page_history['version'], tags_version=to_utimestamp(date)) history.append({'version': '*', 'url': url, 'date': date, 'author': author, 'comment': comment, 'ipnr': ''}) history.append(page_history) data.update(dict(history=history, wiki_to_oneliner=self._wiki_to_oneliner)) def _wiki_view(self, req, stream): add_stylesheet(req, 'tags/css/tractags.css') tags = self._page_tags(req) if not tags: return stream li = [] for tag_ in tags: resource = Resource('tag', tag_) anchor = render_resource_link(self.env, web_context(req, resource), resource) anchor = anchor(rel='tag') li.append(tag.li(anchor, ' ')) # TRANSLATOR: Header label text for tag list at wiki page bottom. insert = tag.ul(class_='tags')(tag.li(_("Tags"), class_='header'), li) return stream | (Transformer('//div[contains(@class,"wikipage")]') .after(insert)) def _update_tags(self, req, page, when=None): newtags = split_into_tags(req.args.get('tags', '')) oldtags = self.tag_system.get_tags(req, page.resource) if oldtags != newtags: self.tag_system.set_tags(req, page.resource, newtags, when=when) return True return False def _wiki_edit(self, req, stream): # TRANSLATOR: Label text for link to '/tags'. link = tag.a(_("view all tags"), href=req.href.tags()) # TRANSLATOR: ... (view all tags) insert = tag(Markup(_("Tag under: (%(tags_link)s)", tags_link=link))) insert( tag.br(), tag.input(id='tags', type='text', name='tags', size='50', value=req.args.get('tags', ' '.join(self._page_tags(req)))) ) insert = tag.div(tag.label(insert), class_='field') return stream | Transformer('//div[@id="changeinfo1"]').append(insert) def _wiki_history(self, req, stream): xpath = '//input[@type="radio" and @value="*"]' stream = stream | Transformer(xpath).remove() # Remove invalid links to wiki page revisions (fix for Trac < 0.12). xpath = '//a[contains(@href,"%2A")]' return stream | Transformer(xpath).remove() def _wiki_to_oneliner(self, context, wiki, shorten=None): if isinstance(wiki, Fragment): return wiki return format_to_oneliner(self.env, context, wiki, shorten=shorten)