def post_process_request(self, req, template, data, content_type): if req.method == 'GET' and req.path_info.startswith('/wiki/') and \ req.args.get('action') == 'edit' and \ req.args.get('template') and 'tags' not in req.args: # Retrieve template resource to be queried for tags. template_page = WikiPage( self.env, ''.join([ WikiModule.PAGE_TEMPLATES_PREFIX, req.args.get('template') ])) if template_page and template_page.exists and \ 'TAGS_VIEW' in req.perm(template_page.resource): ts = TagSystem(self.env) tags = sorted(ts.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'))) return (template, data, content_type)
def _page_tags(self, req): pagename = req.args.get('page', 'WikiStart') tag_system = TagSystem(self.env) resource = Resource('wiki', pagename) tags = sorted(tag_system.get_tags(req, resource)) return tags
def post_process_request(self, req, template, data, content_type): if data and req.path_info == '/timeline' and \ 'TAGS_VIEW' in req.perm(Resource('tags')): def realm_handler(_, node, context): return query.match(node, [context.realm]) query_str = req.args.getfirst(self.key) if query_str is None and req.args.get('format') != 'rss': query_str = req.session.get('timeline.%s' % self.key) else: query_str = (query_str or '').strip() # Record tag query expression between visits. req.session['timeline.%s' % self.key] = query_str if data.get('events') and query_str: tag_system = TagSystem(self.env) try: query = Query(query_str, attribute_handlers={'realm': realm_handler}) except InvalidQuery as e: add_warning(req, _("Tag query syntax error: %s" % e)) else: all_realms = tag_system.get_taggable_realms(req.perm) query_realms = set() for m in REALM_RE.finditer(query.as_string()): query_realms.add(m.group(1)) # Don't care about resources from non-taggable realms. realms = not query_realms and all_realms or \ query_realms.intersection(all_realms) events = [] self.log.info("Filtering timeline events by tags '%s'", query_str) for event in data['events']: resource = resource_from_event(event) if resource and resource.realm in realms: # Shortcut view permission checks here. tags = tag_system.get_tags(None, resource) if query(tags, context=resource): events.append(event) # Overwrite with filtered list. data['events'] = events if query_str: # Add current value for next form rendering. data[self.key] = query_str elif self.key in req.session: del req.session[self.key] filter_lst = [] # xpath = '//form[@id="prefs"]/div[1]' xform = JTransformer('form#prefs > div:nth-of-type(1)') insert = builder(Markup('<br />'), tag_("matching tags "), builder.input(type='text', name=self.key, value=data.get(self.key))) filter_lst.append(xform.append(Markup(insert))) add_script_data(req, {'tags_filter': filter_lst}) add_script(req, 'tags/js/tags_jtransform.js') return template, data, content_type
def _update_tags(self, req, page): tag_system = TagSystem(self.env) newtags = tag_system.split_into_tags(req.args.get('tags', '')) oldtags = tag_system.get_tags(req, page.resource) if oldtags != newtags: tag_system.set_tags(req, page.resource, newtags) return True return False
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 tag_sys = TagSystem(self.env) tags = sorted(tag_sys.get_tags(req, resource, when=tags_version)) return tags
def post_process_request(self, req, template, data, content_type): if data and req.path_info == '/timeline' and \ 'TAGS_VIEW' in req.perm(Resource('tags')): def realm_handler(_, node, context): return query.match(node, [context.realm]) query_str = req.args.get(self.key) if query_str is None and req.args.get('format') != 'rss': query_str = req.session.get('timeline.%s' % self.key) else: query_str = (query_str or '').strip() # Record tag query expression between visits. req.session['timeline.%s' % self.key] = query_str if data.get('events') and query_str: tag_system = TagSystem(self.env) try: query = Query(query_str, attribute_handlers=dict(realm=realm_handler) ) except InvalidQuery, e: add_warning(req, _("Tag query syntax error: %s" % to_unicode(e))) else: all_realms = tag_system.get_taggable_realms(req.perm) query_realms = set() for m in REALM_RE.finditer(query.as_string()): query_realms.add(m.group(1)) # Don't care about resources from non-taggable realms. realms = not query_realms and all_realms or \ query_realms.intersection(all_realms) events = [] self.log.debug("Filtering timeline events by tags '%s'", query_str) for event in data['events']: resource = event['data'][0] if resource.realm in realms: # Shortcut view permission checks here. tags = tag_system.get_tags(None, resource) if query(tags, context=resource): events.append(event) # Overwrite with filtered list. data['events'] = events if query_str: # Add current value for next form rendering. data[self.key] = query_str elif self.key in req.session: del req.session[self.key]
def post_process_request(self, req, template, data, content_type): if data and req.path_info == '/timeline' and \ 'TAGS_VIEW' in req.perm(Resource('tags')): def realm_handler(_, node, context): return query.match(node, [context.realm]) query_str = req.args.get(self.key) if query_str is None and req.args.get('format') != 'rss': query_str = req.session.get('timeline.%s' % self.key) else: query_str = (query_str or '').strip() # Record tag query expression between visits. req.session['timeline.%s' % self.key] = query_str if data.get('events') and query_str: tag_system = TagSystem(self.env) try: query = Query(query_str, attribute_handlers=dict(realm=realm_handler)) except InvalidQuery, e: add_warning( req, _("Tag query syntax error: %s" % to_unicode(e))) else: all_realms = tag_system.get_taggable_realms(req.perm) query_realms = set() for m in REALM_RE.finditer(query.as_string()): query_realms.add(m.group(1)) # Don't care about resources from non-taggable realms. realms = not query_realms and all_realms or \ query_realms.intersection(all_realms) events = [] self.log.debug("Filtering timeline events by tags '%s'" % query_str) for event in data['events']: resource = event['data'][0] if resource.realm in realms: # Shortcut view permission checks here. tags = tag_system.get_tags(None, resource) if query(tags, context=resource): events.append(event) # Overwrite with filtered list. data['events'] = events if query_str: # Add current value for next form rendering. data[self.key] = query_str elif self.key in req.session: del req.session[self.key]
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): tag_sys = TagSystem(self.env) tags = sorted(tag_sys.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(self, req, template, data, content_type): if req.method == 'GET' and req.path_info.startswith('/wiki/') and \ req.args.get('action') == 'edit' and \ req.args.get('template') and 'tags' not in req.args: # Retrieve template resource to be queried for tags. template_page = WikiPage(self.env,''.join( [WikiModule.PAGE_TEMPLATES_PREFIX, req.args.get('template')])) if template_page and template_page.exists and \ 'TAGS_VIEW' in req.perm(template_page.resource): ts = TagSystem(self.env) tags = sorted(ts.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'))) return (template, data, content_type)
def _get_stored_tags(self, req, resource): # Return tags associated to resource. tag_system = TagSystem(self.env) tags = tag_system.get_tags(req, resource) return sorted(tags)
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 HacksCache(Borg): _lock = threading.RLock() _initialized = False _hacks = dict() _types = dict() _releases = dict() def __init__(self, env): if self._initialized: self._log('already initialized') return else: env.log.debug('HacksCache %x: initializing' % id(self.__dict__)) self._lock.acquire() self._env = env self._tag_system = TagSystem(env) self._req = FakeRequest(env) self.id = id(self.__dict__) self._rebuild_cache() self._initialized = True self._lock.release() self._log('initialization finished') def __del__(self): self._log('Aiiieeeee') def _rebuild_cache(self): """ Rebuild the cache. Caller MUST hold the lock! """ self._log('rebuilding cache (initialized=%s)' % self._initialized) self._hacks = dict() self._types = dict() self._releases = dict() self._update_types() self._update_releases() query = 'realm:wiki (%s) (%s)' % \ (' or '.join(self._types), ' or '.join(self._releases)) for h in self._query_tags(query): self._update_hack(h, False, False) def _log(self, message): self._env.log.debug('HacksCache %x: %s' % (self.id, message)) def _query_tags(self, query): """ Helper to perform queries on cached tags system """ return [r.id for r, _ in self._tag_system.query(self._req, query)] def _update_types(self): """ Get/update list of hack types """ types = self._query_tags('realm:wiki type') keys = self._types.keys() # add types that have been added since last update for t in types: if t not in keys: self._types[t] = Tag(t, self._env, self._req, self._tag_system) # remove types that no longer exist for k in keys: if k not in types: del self._types[k] def _update_releases(self): """ Get/update list of Trac releases """ releases = self._query_tags('realm:wiki release') keys = self._releases.keys() # add releases that have been added since last update for r in releases: if r not in keys: self._releases[r] = Tag(r, self._env, self._req, self._tag_system) # remove releases that no longer exist for k in keys: if k not in releases: del self._releases[k] def _update_hack(self, name, full_update=True, check_delete=True): """ Get/update/delete hack properties """ if full_update: self._update_types() self._update_releases() delete = False if check_delete: page = WikiPage(self._env, name) if page.exists: tags = set(self._tag_system.get_tags(self._req, page.resource)) if not (tags.intersection(self._types) and tags.intersection(self._releases)): delete = True else: delete = True if delete: try: del self._hacks[name] self._log('deleted hack %s' % name) except: self._log('%s is no hack, skipped' % name) else: try: self._hacks[name].update() self._log('updated hack %s' % name) except: self._hacks[name] = Hack(name, self._env, self._req, self._tag_system) self._log('learned hack %s' % name) def _get(self, where, what): try: return where[what] except: return None def _get_all(self, where, sorted=False): v = where.values() if sorted: return natural_sort(v) else: return v # Public API def update(self, hack=None): """ Update cache for all or just the given hack """ if hack: self._update_hack(hack, True, True) else: self._lock.acquire() self._rebuild_cache() self._lock.release() def get_type(self, name): return self._get(self._types, name) def get_all_types(self, sorted=False): return self._get_all(self._types, sorted) def get_release(self, name): return self._get(self._releases, name) def get_all_releases(self, sorted=False): return self._get_all(self._releases, sorted) def get_hack(self, name): return self._get(self._hacks, name) def get_all_hacks(self, sorted=False): return self._get_all(self._hacks, sorted)
def _get_stored_tags(self, req, download_id): tag_system = TagSystem(self.env) resource = Resource('downloads', download_id) tags = tag_system.get_tags(req, resource) return sorted(tags)
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)
def _get_stored_tags(self, context, download_id): tag_system = TagSystem(self.env) resource = Resource(self.realm, download_id) tags = tag_system.get_tags(context.req, resource) return sorted(tags)
class HacksCache(Borg): _lock = threading.RLock() _initialized = False _hacks = dict() _types = dict() _releases = dict() def __init__(self, env): if self._initialized: self._log('already initialized') return else: env.log.debug('HacksCache %x: initializing' % id(self.__dict__)) self._lock.acquire() self._env = env self._tag_system = TagSystem(env) self._req = FakeRequest(env) self.id = id(self.__dict__) self._rebuild_cache() self._initialized = True self._lock.release() self._log('initialization finished') def __del__(self): self._log('Aiiieeeee') def _rebuild_cache(self): """ Rebuild the cache. Caller MUST hold the lock! """ self._log('rebuilding cache (initialized=%s)' % self._initialized) self._hacks = dict() self._types = dict() self._releases = dict() self._update_types() self._update_releases() query = 'realm:wiki (%s) (%s)' % \ (' or '.join(self._types), ' or '.join(self._releases)) for h in self._query_tags(query): self._update_hack(h, False, False) def _log(self, message): self._env.log.debug('HacksCache %x: %s' % (self.id, message)) def _query_tags(self, query): """ Helper to perform queries on cached tags system """ return [ r.id for r, _ in self._tag_system.query(self._req, query) ] def _update_types(self): """ Get/update list of hack types """ types = self._query_tags('realm:wiki type') keys = self._types.keys() # add types that have been added since last update for t in types: if t not in keys: self._types[t] = Tag(t, self._env, self._req, self._tag_system) # remove types that no longer exist for k in keys: if k not in types: del self._types[k] def _update_releases(self): """ Get/update list of Trac releases """ releases = self._query_tags('realm:wiki release') keys = self._releases.keys() # add releases that have been added since last update for r in releases: if r not in keys: self._releases[r] = Tag(r, self._env, self._req, self._tag_system) # remove releases that no longer exist for k in keys: if k not in releases: del self._releases[k] def _update_hack(self, name, full_update = True, check_delete = True): """ Get/update/delete hack properties """ if full_update: self._update_types() self._update_releases() delete = False if check_delete: page = WikiPage(self._env, name) if page.exists: tags = set(self._tag_system.get_tags(self._req, page.resource)) if not (tags.intersection(self._types) and tags.intersection(self._releases)): delete = True else: delete = True if delete: try: del self._hacks[name] self._log('deleted hack %s' % name) except: self._log('%s is no hack, skipped' % name) else: try: self._hacks[name].update() self._log('updated hack %s' % name) except: self._hacks[name] = Hack(name, self._env, self._req, self._tag_system) self._log('learned hack %s' % name) def _get(self, where, what): try: return where[what] except: return None def _get_all(self, where, sorted = False): v = where.values() if sorted: return natural_sort(v) else: return v # Public API def update(self, hack = None): """ Update cache for all or just the given hack """ if hack: self._update_hack(hack, True, True) else: self._lock.acquire() self._rebuild_cache() self._lock.release() def get_type(self, name): return self._get(self._types, name) def get_all_types(self, sorted = False): return self._get_all(self._types, sorted) def get_release(self, name): return self._get(self._releases, name) def get_all_releases(self, sorted = False): return self._get_all(self._releases, sorted) def get_hack(self, name): return self._get(self._hacks, name) def get_all_hacks(self, sorted = False): return self._get_all(self._hacks, sorted)
def _get_stored_tags(self, req, screenshot_id): tag_system = TagSystem(self.env) resource = Resource('screenshots', to_unicode(screenshot_id)) tags = tag_system.get_tags(req, resource) return sorted(tags)