def screenshot_deleted(self, req, screenshot): # Create temporary resource. resource = Resource('screenshots', to_unicode(screenshot['id'])) # Delete tags of screenshot. tag_system = TagSystem(self.env) tag_system.delete_tags(req, resource)
def expand_macro(self, formatter, name, args): req = formatter.req add_stylesheet(req, 'hacks/css/trachacks.css') tag_system = TagSystem(self.env) releases = natural_sort([r.id for r, _ in tag_system.query(req, 'realm:wiki release')]) def link(resource): return render_resource_link(self.env, formatter.context, resource, 'compact') dl = builder.dl(class_='tracreleasesmacro') for release in releases: page = WikiPage(self.env, release) match = self.title_extract.search(page.text) if match: rel_title = '%s' % match.group(1).strip() else: rel_title = '%s' % release dl(builder.dt(link(Resource('wiki', release)))) dl(builder.dd(wiki_to_html(rel_title, self.env, req))) return dl
def expand_macro(self, formatter, name, args): req = formatter.req add_stylesheet(req, 'hacks/css/trachacks.css') tag_system = TagSystem(self.env) categories = natural_sort([r.id for r, _ in tag_system.query(req, 'realm:wiki type')]) def link(resource): return render_resource_link(self.env, formatter.context, resource, 'compact') dl = builder.dl(class_='hacktypesmacro') for category in categories: page = WikiPage(self.env, category) match = self.title_extract.search(page.text) if match: cat_title = '%s' % match.group(1).strip() cat_body = self.title_extract.sub('', page.text, 1) else: cat_title = '%s' % category cat_body = page.text cat_body = self.self_extract.sub('', cat_body).strip() dl(builder.dt(link(Resource('wiki', category)))) dl(builder.dd(wiki_to_html(cat_body, self.env, req))) return dl
def render_admin_panel(self, req, cat, page, version): req.perm.require("TAGS_ADMIN") data = {} tag_system = TagSystem(self.env) if req.method == "POST": # Replace Tag allow_delete = req.args.get("allow_delete") new_tag = req.args.get("tag_new_name").strip() new_tag = not new_tag == u"" and new_tag or None if not (allow_delete or new_tag): data["error"] = _( """Selected current tag(s) and either new tag or delete approval are required""" ) else: comment = req.args.get("comment", u"") old_tags = req.args.get("tag_name") if old_tags: # Provide list regardless of single or multiple selection. old_tags = isinstance(old_tags, list) and old_tags or [old_tags] tag_system.replace_tag(req, old_tags, new_tag, comment, allow_delete) data["selected"] = new_tag all_tags = sorted(tag_system.get_all_tags(req, "-dummy")) data["tags"] = all_tags try: Chrome(self.env).add_textarea_grips(req) except AttributeError: # Element modifiers unavailable before Trac 0.12, skip gracefully. pass return "admin_tag_change.html", data
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 process_request(self, req): """Process the request. For ClearSilver, return a (template_name, content_type) tuple, where `template` is the ClearSilver template to use (either a `neo_cs.CS` object, or the file name of the template), and `content_type` is the MIME type of the content. For Genshi, return a (template_name, data, content_type) tuple, where `data` is a dictionary of substitutions for the template. For both templating systems, "text/html" is assumed if `content_type` is `None`. Note that if template processing should not occur, this method can simply send the response itself and not return anything. """ query = req.args.get('q', '').lower() tagsystem = TagSystem(self.env) alltags = tagsystem.query(req) tags = {} for resource, _tags in alltags: for tag in _tags: if query in tag.lower(): tags[tag] = tags.setdefault(tag, 0) + 1 tags = sorted(tags.items(), key=lambda x: x[1], reverse=True) writeOut=str('\n'.join(['%s|%d' % (name, number) for name, number in tags])) req.send_header('Content-length', str(len(writeOut))) req.end_headers() req.write(writeOut)
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 Main(opts): """ Cross your fingers and pray """ env = Environment(opts.envpath) from tractags.api import TagSystem tlist = opts.tags or split_tags(env.config.get('blog', 'default_tag', 'blog')) tags = TagSystem(env) req = Mock(perm=MockPerm()) blog = tags.query(req, ' '.join(tlist + ['realm:wiki'])) cnx = env.get_db_cnx() for resource, page_tags in list(blog): try: page = WikiPage(env, version=1, name=resource.id) _, publish_time, author, _, _ = page.get_history().next() if opts.deleteonly: page.delete() continue categories = ' '.join([t for t in page_tags if t not in tlist]) page = WikiPage(env, name=resource.id) for version, version_time, version_author, version_comment, \ _ in page.get_history(): # Currently the basename of the post url is used due to # http://trac-hacks.org/ticket/2956 #name = resource.id.replace('/', '_') name = resource.id # extract title from text: fulltext = page.text match = _title_split_match(fulltext) if match: title = match.group(1) fulltext = match.group(2) else: title = name body = fulltext print "Adding post %s, v%s: %s" % (name, version, title) insert_blog_post(cnx, name, version, title, body, publish_time, version_time, version_comment, version_author, author, categories) reparent_blog_attachments(env, resource.id, name) continue cnx.commit() if opts.delete: page.delete() continue except: env.log.debug("Error loading wiki page %s" % resource.id, exc_info=True) print "Failed to add post %s, v%s: %s" % (name, version, title) cnx.rollback() cnx.close() return 1 cnx.close() return 0
def __call__(self, context, type_): if not (type_ and isinstance(type_, basestring) and len(type_)): raise ValidationError('No type selected?!') tags = TagSystem(self.env) req = FakeRequest(self.env) types = [r.id for r, _ in tags.query(req, 'realm:wiki type')] if type_ not in types: raise ValidationError('Selected type "%s" invalid?!' % str(type_)) return type_
def screenshot_created(self, req, screenshot): # Create temporary resource. resource = Resource('screenshots', to_unicode(screenshot['id'])) # Delete tags of screenshot with same ID for sure. tag_system = TagSystem(self.env) tag_system.delete_tags(req, resource) # Add tags of new screenshot. new_tags = self._get_tags(screenshot) tag_system.add_tags(req, resource, new_tags)
def download_deleted(self, req, download): # Check proper permissions to modify tags. if not req.perm.has_permission('TAGS_MODIFY'): return # Create temporary resource. resource = Resource('downloads', download['id']) # Delete tags of download. tag_system = TagSystem(self.env) tag_system.delete_tags(req, resource)
def user_created(self, user, password): req = FakeRequest(self.env, user) resource = Resource('wiki', user) tag_system = TagSystem(self.env) tag_system.add_tags(req, resource, ['user',]) page = WikiPage(self.env, user) page.text = '''= %(user)s =\n\n[[ListTagged(%(user)s)]]\n''' % {'user' : user} page.save(user, 'New user %s registered' % user, None) self.env.log.debug("New user %s registered" % user)
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)
def _update_tags(self, req, resource, new_tags): # Get old tags of the resource. tag_system = TagSystem(self.env) old_tags = self._get_stored_tags(req, resource) self.log.debug("setting tags: %s" % (new_tags,)) # Replace with new tags if different. if old_tags != new_tags: tag_system.set_tags(req, resource, new_tags) return True return False
def screenshot_changed(self, req, screenshot, old_screenshot): # Update old screenshot with new values. old_screenshot.update(screenshot) # Create temporary resource. resource = Resource('screenshots', to_unicode(old_screenshot['id'])) # Delete old tags. tag_system = TagSystem(self.env) tag_system.delete_tags(req, resource) # Add new ones. new_tags = self._get_tags(old_screenshot) tag_system.add_tags(req, resource, new_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 _get_keywords_string(self, req): keywords = set(self.sticky_tags_opt) # prevent duplicates if self.tags_enabled: # Use TagsPlugin >= 0.7 performance-enhanced API. tags = TagSystem(self.env).get_all_tags(req) keywords.update(tags.keys()) if keywords: keywords = sorted(keywords) keywords = ','.join(("'%s'" % javascript_quote(_keyword) for _keyword in keywords)) else: keywords = '' return keywords
def __call__(self, context, selected): if selected: tags = TagSystem(self.env) req = FakeRequest(self.env) releases = [r.id for r, _ in tags.query(req, 'realm:wiki release')] if isinstance(selected, (basestring, unicode)): selected = [ selected ] for s in selected: if s not in releases: hack = context.data.get('name', '') + \ context.data.get('type', '').title() self.env.log.error( "Invalid release %s selected for new hack %s" % (s, hack) ) raise ValidationError('Selected release "%s" invalid?!' % str(s)) return selected
def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() self.perms = PermissionSystem(self.env) self.db = self.env.get_db_cnx() setup = TagSetup(self.env) # Current tractags schema is setup with enabled component anyway. # Revert these changes for getting default permissions inserted. self._revert_tractags_schema_init() setup.upgrade_environment(self.db) self.provider = TicketTagProvider(self.env) self.realm = 'ticket' self.tag_sys = TagSystem(self.env) self.tags = ['tag1'] cursor = self.db.cursor() # Populate table with initial test data, not synced with tickets yet. cursor.execute(""" INSERT INTO tags (tagspace, name, tag) VALUES ('ticket', '1', 'deleted')""") self.realm = 'ticket' self._create_ticket(self.tags) self.req = Mock() # Mock an anonymous request. self.req.perm = PermissionCache(self.env)
def download_created(self, context, download): # Check proper permissions to modify tags. if not context.req.perm.has_permission('TAGS_MODIFY'): return # Create temporary resource. resource = Resource(self.realm, download['id']) # Delete tags of download with same ID for sure. tag_system = TagSystem(self.env) tag_system.delete_tags(context.req, resource) # Add tags of new download. new_tags = self._get_tags(download) self.log.debug('tags: %s' % (new_tags,)) tag_system.add_tags(context.req, resource, new_tags)
def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() self.db = self.env.get_db_cnx() setup = TagSetup(self.env) # Current tractags schema is partially setup with enabled component. # Revert these changes for getting a clean setup. self._revert_tractags_schema_init() setup.upgrade_environment(self.db) self.perms = PermissionSystem(self.env) self.tag_s = TagSystem(self.env) self.tag_wp = WikiTagProvider(self.env) cursor = self.db.cursor() # Populate table with initial test data. cursor.execute(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'WikiStart', 'tag1') """) self.req = Mock(authname='editor') # Mock an anonymous request. self.req.perm = PermissionCache(self.env) self.realm = 'wiki' self.tags = ['tag1']
def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() self.perms = PermissionSystem(self.env) self.db = self.env.get_db_cnx() setup = TagSetup(self.env) # Current tractags schema is setup with enabled component anyway. # Revert these changes for getting default permissions inserted. self._revert_tractags_schema_init() setup.upgrade_environment(self.db) self.provider = TicketTagProvider(self.env) self.realm = 'ticket' self.tag_sys = TagSystem(self.env) self.tags = ['tag1', 'tag2'] cursor = self.db.cursor() # Populate tables with initial test data. self._create_ticket(self.tags) # Mock an anonymous request. self.anon_req = Mock() self.anon_req.perm = PermissionCache(self.env) self.req = Mock(authname='editor') self.req.authname = 'editor' self.req.perm = PermissionCache(self.env, username='******')
def download_created(self, req, download): # Check proper permissions to modify tags. if not req.perm.has_permission('TAGS_MODIFY'): return # Create temporary resource. resource = Resource() resource.realm = 'downloads' resource.id = download['id'] # Delete tags of download with same ID for sure. tag_system = TagSystem(self.env) tag_system.delete_tags(req, resource) # Add tags of new download. new_tags = self._get_tags(download) tag_system.add_tags(req, resource, new_tags)
def render_admin_panel(self, req, cat, page, version): req.perm.require('TAGS_ADMIN') tag_system = TagSystem(self.env) all_realms = tag_system.get_taggable_realms(req.perm) # Check request for enabled filters, or use default. if not [r for r in all_realms if r in req.args]: for realm in all_realms: req.args[realm] = 'on' checked_realms = [r for r in all_realms if r in req.args] data = dict(checked_realms=checked_realms, tag_realms=list(dict(name=realm, checked=realm in checked_realms) for realm in all_realms)) if req.method == 'POST': # Replace Tag allow_delete = req.args.get('allow_delete') new_tag = req.args.get('tag_new_name').strip() new_tag = not new_tag == u'' and new_tag or None if not (allow_delete or new_tag): data['error'] = _("Selected current tag(s) and either " "new tag or delete approval are required") else: comment = req.args.get('comment', u'') old_tags = req.args.get('tag_name') if old_tags: # Provide list regardless of single or multiple selection. old_tags = isinstance(old_tags, list) and old_tags or \ [old_tags] tag_system.replace_tag(req, old_tags, new_tag, comment, allow_delete, filter=checked_realms) data['selected'] = new_tag query = ' or '.join(['realm:%s' % r for r in checked_realms]) all_tags = sorted(tag_system.get_all_tags(req, query)) data['tags'] = all_tags try: Chrome(self.env).add_textarea_grips(req) except AttributeError: # Element modifiers unavailable before Trac 0.12, skip gracefully. pass return 'admin_tag_change.html', data
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 process_request(self, req): data = {} tag_system = TagSystem(self.env) #match = self.path_match.match(req.path_info) #view = 'cloud' #if match.group(1): # view = match.group(1) # Hack types and their description types = [] for category in sorted([r.id for r, _ in tag_system.query(req, 'realm:wiki type')]): page = WikiPage(self.env, category) match = self.title_extract.search(page.text) if match: title = '%s' % match.group(1).strip() else: title = '%s' % category types.append((category, title)) # Trac releases releases = natural_sort([r.id for r, _ in tag_system.query(req, 'realm:wiki release')]) data['types'] = types data['releases'] = releases selected_releases = req.args.get('release', set(['0.10', '0.11', 'anyrelease'])) data['selected_releases'] = selected_releases hacks = self.fetch_hacks(req, data, [ t[0] for t in types ], selected_releases) add_stylesheet(req, 'tags/css/tractags.css') add_stylesheet(req, 'hacks/css/trachacks.css') add_script(req, 'hacks/js/trachacks.js') if req.path_info == '/newhack': return self.render_new(req, data, hacks)
def download_changed(self, req, download, old_download): # Check proper permissions to modify tags. if not req.perm.has_permission('TAGS_MODIFY'): return # Check if tags has to be updated. if not self._has_tags_changed(download): return # Update old download with new values. old_download.update(download) # Create temporary resource. resource = Resource('downloads', old_download['id']) # Delete old tags. tag_system = TagSystem(self.env) tag_system.delete_tags(req, resource) # Add new ones. new_tags = self._get_tags(old_download) tag_system.add_tags(req, resource, new_tags)
def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() self.perms = PermissionSystem(self.env) self.req = Mock() self.actions = ['TAGS_ADMIN', 'TAGS_MODIFY', 'TAGS_VIEW'] self.tag_s = TagSystem(self.env) self.db = self.env.get_db_cnx() setup = TagSetup(self.env) # Current tractags schema is setup with enabled component anyway. # Revert these changes for getting default permissions inserted. self._revert_tractags_schema_init() setup.upgrade_environment(self.db)
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 expand_macro(self, formatter, name, content): req = formatter.req query_result = TagSystem(self.env).query(req, content) def link(resource): return render_resource_link(self.env, formatter.context, resource, 'compact') ul = builder.ul(class_='taglist') # Beware: Resources can be Unicode strings. for resource, tags in sorted(query_result, key=lambda r: r[0].id): tags = sorted(tags) if tags: rendered_tags = [link(resource('tag', tag)) for tag in tags] li = builder.li(link(resource), ' (', rendered_tags[0], [(' ', tag) for tag in rendered_tags[1:]], ')') else: li = builder.li(link(resource)) ul(li, '\n') return ul
def download_created(self, context, download): # Check proper permissions to modify tags. if not context.req.perm.has_permission('TAGS_MODIFY'): return # Create temporary resource. resource = Resource(self.realm, download['id']) # Delete tags of download with same ID for sure. tag_system = TagSystem(self.env) tag_system.delete_tags(context.req, resource) # Add tags of new download. new_tags = self._get_tags(download) self.log.debug('tags: %s' % (new_tags, )) tag_system.add_tags(context.req, resource, new_tags)
def _fetch_tkt_tags(self): """Transfer all relevant ticket attributes to tags db table.""" # Initial sync is done by forced, stupid one-way mirroring. # Data aquisition for this utilizes the known ticket tags query. db = self.env.get_db_cnx() fields = ["COALESCE(%s, '')" % f for f in self.fields] ignore = '' if self.ignore_closed_tickets: ignore = " WHERE status != 'closed'" sql = """ SELECT * FROM (SELECT id, %s, %s AS std_fields FROM ticket%s) s """ % (','.join(self.fields), db.concat(*fields), ignore) sql += " WHERE std_fields != '' ORDER BY id" self.env.log.debug(sql) # Obtain cursors for reading tickets and altering tags db table. # DEVEL: Use appropriate cursor typs from Trac 1.0 db API. ro_cursor = db.cursor() rw_cursor = db.cursor() # Delete all previous entries for 'ticket' tagspace. rw_cursor.execute('DELETE FROM tags WHERE tagspace=%s', (self.realm, )) self.log.debug('ENTER_TAG_DB_CHECKOUT') ro_cursor.execute(sql) self.log.debug('EXIT_TAG_DB_CHECKOUT') split_into_tags = TagSystem(self.env).split_into_tags self.log.debug('ENTER_TAG_SYNC') for row in ro_cursor: tkt_id, ttags = row[0], ' '.join([f for f in row[1:-1] if f]) ticket_tags = split_into_tags(ttags) rw_cursor.executemany( """ INSERT INTO tags (tagspace, name, tag) VALUES (%s, %s, %s) """, [(self.realm, str(tkt_id), tag) for tag in ticket_tags]) db.commit() self.log.debug('EXIT_TAG_SYNC')
def render_admin_panel(self, req, cat, page, version): req.perm.require('TAGS_ADMIN') tag_system = TagSystem(self.env) all_realms = tag_system.get_taggable_realms(req.perm) # Check request for enabled filters, or use default. if [r for r in all_realms if r in req.args] == []: for realm in all_realms: req.args[realm] = 'on' checked_realms = [r for r in all_realms if r in req.args] data = dict(checked_realms=checked_realms, tag_realms=list( dict(name=realm, checked=realm in checked_realms) for realm in all_realms)) if req.method == 'POST': # Replace Tag allow_delete = req.args.get('allow_delete') new_tag = req.args.get('tag_new_name').strip() new_tag = not new_tag == u'' and new_tag or None if not (allow_delete or new_tag): data['error'] = _("Selected current tag(s) and either " "new tag or delete approval are required") else: comment = req.args.get('comment', u'') old_tags = req.args.get('tag_name') if old_tags: # Provide list regardless of single or multiple selection. old_tags = isinstance(old_tags, list) and old_tags or \ [old_tags] tag_system.replace_tag(req, old_tags, new_tag, comment, allow_delete, filter=checked_realms) data['selected'] = new_tag query = ' or '.join(['realm:%s' % r for r in checked_realms]) all_tags = sorted(tag_system.get_all_tags(req, query)) data['tags'] = all_tags try: Chrome(self.env).add_textarea_grips(req) except AttributeError: # Element modifiers unavailable before Trac 0.12, skip gracefully. pass return 'admin_tag_change.html', data
def render_admin_panel(self, req, cat, page, version): req.perm.require('TAGS_ADMIN') tag_system = TagSystem(self.env) all_realms = tag_system.get_taggable_realms(req.perm) # Check request for enabled filters, or use default. if not [r for r in all_realms if r in req.args]: for realm in all_realms: req.args[realm] = 'on' checked_realms = [r for r in all_realms if r in req.args] data = dict(checked_realms=checked_realms, tag_realms=list( dict(name=realm, checked=realm in checked_realms) for realm in all_realms)) if req.method == 'POST': # Replace Tag allow_delete = req.args.get('allow_delete') new_tag = req.args.get('tag_new_name').strip() new_tag = not new_tag == u'' and new_tag or None if not (allow_delete or new_tag): add_warning( req, _("Selected current tag(s) and either " "new tag or delete approval are required")) else: comment = req.args.get('comment', u'') old_tags = req.args.getlist('tag_name') if old_tags: tag_system.replace_tag(req, old_tags, new_tag, comment, allow_delete, filter=checked_realms) data['selected'] = new_tag req.redirect(req.href.admin('tags', 'replace')) query = ' or '.join('realm:%s' % r for r in checked_realms) all_tags = sorted(tag_system.get_all_tags(req, query)) data['tags'] = all_tags chrome = Chrome(self.env) chrome.add_textarea_grips(req) if hasattr(chrome, 'jenv'): return 'admin_tag_change.html', data, None else: return 'admin_tag_change.html', data
def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() setup = TagSetup(self.env) # Current tractags schema is partially setup with enabled component. # Revert these changes for getting a clean setup. self._revert_tractags_schema_init() setup.upgrade_environment() self.perms = PermissionSystem(self.env) self.tag_s = TagSystem(self.env) # Populate table with initial test data. self.env.db_transaction(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'WikiStart', 'tag1') """) self.req = Mock(authname='editor') # Mock an anonymous request. self.req.perm = PermissionCache(self.env)
def setUp(self): self.env = EnvironmentStub(enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() setup = TagSetup(self.env) # Current tractags schema is setup with enabled component anyway. # Revert these changes for getting a clean setup. self._revert_tractags_schema_init() setup.upgrade_environment() self.tag_s = TagSystem(self.env) self.tag_rh = TagRequestHandler(self.env) perms = PermissionSystem(self.env) # Revoke default permissions, because more diversity is required here. perms.revoke_permission('anonymous', 'TAGS_VIEW') perms.revoke_permission('authenticated', 'TAGS_MODIFY') perms.grant_permission('reader', 'TAGS_VIEW') perms.grant_permission('writer', 'TAGS_MODIFY') perms.grant_permission('admin', 'TAGS_ADMIN') self.href = Href('/trac') self.abs_href = Href('http://example.org/trac')
def get_tagged_resources(self, req, tags): if 'TICKET_VIEW' not in req.perm: return split_into_tags = TagSystem(self.env).split_into_tags db = self.env.get_db_cnx() cursor = db.cursor() args = [] ignore = '' if self.ignore_closed_tickets: ignore = " WHERE status != 'closed'" sql = "SELECT * FROM (SELECT id, %s, %s AS fields FROM ticket%s) s" % ( ','.join(self.fields), '||'.join( ["COALESCE(%s, '')" % f for f in self.fields]), ignore) constraints = [] if tags: constraints.append("(" + ' OR '.join(["fields LIKE %s" for t in tags]) + ")") args += ['%' + t + '%' for t in tags] else: constraints.append("fields != ''") if constraints: sql += " WHERE " + " AND ".join(constraints) sql += " ORDER BY id" self.env.log.debug(sql) cursor.execute(sql, args) for row in cursor: id, ttags = row[0], ' '.join([f for f in row[1:-1] if f]) perm = req.perm('ticket', id) if 'TICKET_VIEW' not in perm or 'TAGS_VIEW' not in perm: continue ticket_tags = split_into_tags(ttags) tags = set([to_unicode(x) for x in tags]) if (not tags or ticket_tags.intersection(tags)): yield Resource('ticket', id), ticket_tags
def check_permission(self, action, username, resource, perm): if resource is None or action.split('_')[0] != resource.realm.upper(): return None from tractags.api import TagSystem class FakeRequest(object): def __init__(self, perm): self.perm = perm permission = action.lower().split('_')[1] req = FakeRequest(perm) tags = TagSystem(self.env).get_tags(None, resource) # Explicitly denied? if ':-'.join((username, permission)) in tags: return False # Find all granted permissions for the requesting user from # tagged permissions by expanding any meta action as well. if action in set(PermissionSystem(self.env).expand_actions( ['_'.join([resource.realm, t.split(':')[1]]).upper() for t in tags if t.split(':')[0] == username])): return True
class TicketTagProviderTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() self.perms = PermissionSystem(self.env) setup = TagSetup(self.env) # Current tractags schema is setup with enabled component anyway. # Revert these changes for getting default permissions inserted. self._revert_tractags_schema_init() setup.upgrade_environment() self.provider = TicketTagProvider(self.env) self.realm = 'ticket' self.tag_sys = TagSystem(self.env) self.tags = ['tag1', 'tag2'] # Populate tables with initial test data. self._create_ticket(self.tags) def tearDown(self): self.env.shutdown() shutil.rmtree(self.env.path) # Helpers def _create_ticket(self, tags, **kwargs): ticket = Ticket(self.env) ticket['keywords'] = u' '.join(sorted(map(to_unicode, tags))) ticket['summary'] = 'summary' ticket['reporter'] = 'admin' for name, value in kwargs.iteritems(): ticket[name] = value ticket.insert() return ticket def _revert_tractags_schema_init(self): with self.env.db_transaction as db: db("DROP TABLE IF EXISTS tags") db("DROP TABLE IF EXISTS tags_change") db("DELETE FROM system WHERE name='tags_version'") db("DELETE FROM permission WHERE action %s" % db.like(), ('TAGS_%', )) def _tags(self): tags = {} for name, tag in self.env.db_query(""" SELECT name,tag FROM tags """): if name in tags: tags[name].add(tag) else: tags[name] = set([tag]) return tags # Tests def test_get_tagged_resources(self): # No tags, no restrictions, all resources. req = MockRequest(self.env, authname='editor') self.assertEquals( [r for r in self.provider.get_tagged_resources(req, None)][0][1], set(self.tags)) # Force fine-grained perm-check check for all tags, not just the one # from query. self.provider.fast_permcheck = False self.assertEquals([ r for r in self.provider.get_tagged_resources( req, set(self.tags[:1])) ][0][1], set(self.tags)) def test_get_tags(self): req = MockRequest(self.env, authname='editor') resource = Resource('ticket', 2) self.assertRaises(ResourceNotFound, self.provider.get_resource_tags, req, resource) self._create_ticket(self.tags) self.assertEquals( [tag for tag in self.provider.get_resource_tags(req, resource)], self.tags) def test_set_tags(self): req = MockRequest(self.env, authname='editor') tags = ['tag3'] ticket = Ticket(self.env, 1) ticket['keywords'] = tags[0] # Tags get updated by TicketChangeListener method. ticket.save_changes(req.authname) self.assertEquals(self.tag_sys.get_all_tags(req).keys(), tags) def test_remove_tags(self): req = MockRequest(self.env, authname='editor') anon_req = MockRequest(self.env, authname='anonymous') resource = Resource('ticket', 1) # Anonymous lacks required permissions. self.assertRaises(PermissionError, self.provider.remove_resource_tags, anon_req, resource) # Shouldn't raise an error with appropriate permission. self.provider.remove_resource_tags(req, resource, 'comment') ticket = Ticket(self.env, 1) self.assertEquals(ticket['keywords'], '') def test_describe_tagged_resource(self): req = MockRequest(self.env, authname='editor') resource = Resource('ticket', 1) self.assertEquals( self.provider.describe_tagged_resource(req, resource), 'defect: summary') def test_create_ticket_by_anonymous(self): req = MockRequest(self.env, authname='editor') ticket = self._create_ticket(self.tags, reporter='anonymous') tags = self.provider.get_resource_tags(req, ticket.resource) self.assertEquals(tags, set(self.tags)) def test_update_ticket_by_anonymous(self): req = MockRequest(self.env, authname='editor') ticket = self._create_ticket([]) tags = self.provider.get_resource_tags(req, ticket.resource) self.assertEquals(tags, set([])) ticket['keywords'] = ', '.join(self.tags) ticket.save_changes('anonymous', comment='Adding keywords') tags = self.provider.get_resource_tags(req, ticket.resource) self.assertEquals(tags, set(self.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, resource): # Return tags associated to resource. tag_system = TagSystem(self.env) tags = tag_system.get_tags(req, resource) return sorted(tags)
class WikiTagProviderTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True, path=tempfile.mkdtemp(), enable=['trac.*', 'tractags.*']) setup = TagSetup(self.env) # Current tractags schema is partially setup with enabled component. # Revert these changes for getting a clean setup. self._revert_tractags_schema_init() setup.upgrade_environment() self.perms = PermissionSystem(self.env) self.tag_s = TagSystem(self.env) self.tag_wp = WikiTagProvider(self.env) # Populate table with initial test data. self.env.db_transaction(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'WikiStart', 'tag1') """) self.realm = 'wiki' self.tags = ['tag1'] def tearDown(self): self.env.shutdown() shutil.rmtree(self.env.path) # Helpers def _revert_tractags_schema_init(self): _revert_tractags_schema_init(self.env) # Tests def test_get_tags(self): resource = Resource('wiki', 'WikiStart') req = MockRequest(self.env, authname='editor') self.assertEquals([tag for tag in self.tag_wp.get_resource_tags(req, resource)], self.tags) def test_exclude_template_tags(self): # Populate table with more test data. req = MockRequest(self.env, authname='editor') self.env.db_transaction(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'PageTemplates/Template', 'tag2') """) tags = ['tag1', 'tag2'] self.assertEquals(self.tag_s.get_all_tags(req).keys(), self.tags) self.env.config.set('tags', 'query_exclude_wiki_templates', False) self.assertEquals(self.tag_s.get_all_tags(req).keys(), tags) def test_set_tags_no_perms(self): resource = Resource('wiki', 'TaggedPage') req = MockRequest(self.env, authname='anonymous') self.assertRaises(PermissionError, self.tag_wp.set_resource_tags, req, resource, self.tags) def test_set_tags(self): resource = Resource('wiki', 'TaggedPage') req = MockRequest(self.env, authname='editor') # Shouldn't raise an error with appropriate permission. self.tag_wp.set_resource_tags(req, resource, self.tags) self.tag_wp.set_resource_tags(req, resource, ['tag2']) # Check change records. rows = self.env.db_query(""" SELECT author,oldtags,newtags FROM tags_change WHERE tagspace=%s AND name=%s ORDER by time DESC """, ('wiki', 'TaggedPage')) self.assertEqual(rows[0], ('editor', 'tag1', 'tag2')) self.assertEqual(rows[1], ('editor', '', 'tag1'))
class TicketTagProviderTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() self.perms = PermissionSystem(self.env) self.db = self.env.get_db_cnx() setup = TagSetup(self.env) # Current tractags schema is setup with enabled component anyway. # Revert these changes for getting default permissions inserted. self._revert_tractags_schema_init() setup.upgrade_environment(self.db) self.provider = TicketTagProvider(self.env) self.realm = 'ticket' self.tag_sys = TagSystem(self.env) self.tags = ['tag1'] cursor = self.db.cursor() # Populate table with initial test data, not synced with tickets yet. cursor.execute(""" INSERT INTO tags (tagspace, name, tag) VALUES ('ticket', '1', 'deleted')""") self.realm = 'ticket' self._create_ticket(self.tags) self.req = Mock() # Mock an anonymous request. self.req.perm = PermissionCache(self.env) def tearDown(self): self.db.close() # Really close db connections. self.env.shutdown() shutil.rmtree(self.env.path) # Helpers def _create_ticket(self, tags): ticket = Ticket(self.env) ticket['keywords'] = u' '.join(sorted(map(to_unicode, tags))) ticket['summary'] = 'summary' ticket.insert() def _revert_tractags_schema_init(self): cursor = self.db.cursor() cursor.execute("DROP TABLE IF EXISTS tags") cursor.execute("DELETE FROM system WHERE name='tags_version'") cursor.execute( "DELETE FROM permission WHERE action %s" % self.db.like(), ('TAGS_%', )) def _tags(self): tags = {} cursor = self.db.cursor() cursor.execute("SELECT name,tag FROM tags") for name, tag in cursor.fetchall(): if name in tags: tags[name].add(tag) else: tags[name] = set([tag]) return tags # Tests def test_get_tags(self): resource = Resource('ticket', 2) self.assertRaises(ResourceNotFound, self.provider.get_resource_tags, self.req, resource) self._create_ticket(self.tags) self.assertEquals([ tag for tag in self.provider.get_resource_tags(self.req, resource) ], self.tags) #ignore_closed_tickets def test_set_tags(self): resource = Resource('ticket', 1) self.tags = ['tag2'] # Anonymous lacks required permissions. self.assertRaises(PermissionError, self.provider.set_resource_tags, self.req, resource, self.tags) self.req.authname = 'user' self.req.perm = PermissionCache(self.env, username='******') # Shouldn't raise an error with appropriate permission. self.provider.set_resource_tags(self.req, resource, self.tags) self.assertEquals( self.tag_sys.get_all_tags(self.req, '').keys(), self.tags) def test_remove_tags(self): resource = Resource('ticket', 1) # Anonymous lacks required permissions. self.assertRaises(PermissionError, self.provider.remove_resource_tags, self.req, resource) self.req.authname = 'user' self.req.perm = PermissionCache(self.env, username='******') # Shouldn't raise an error with appropriate permission. self.provider.remove_resource_tags(self.req, resource, 'comment') tkt = Ticket(self.env, 1) self.assertEquals(tkt['keywords'], '') def test_describe_tagged_resource(self): resource = Resource('ticket', 1) self.assertEquals( self.provider.describe_tagged_resource(self.req, resource), 'defect: summary')
def expand_macro(self, formatter, name, args): req = formatter.req tag_system = TagSystem(self.env) all_releases = natural_sort([r.id for r, _ in tag_system.query(req, 'realm:wiki release')]) all_categories = sorted([r.id for r, _ in tag_system.query(req, 'realm:wiki type')]) hide_release_picker = False hide_fieldset_legend = False hide_fieldset_description = False other = [] if args: categories = [] releases = [] for arg in args.split(): if arg in all_releases: hide_release_picker = True releases.append(arg) elif arg in all_categories: categories.append(arg) else: other.append(arg) if len(categories) or len(releases): hide_fieldset_description = True if not len(categories): categories = all_categories elif len(categories) == 1: hide_fieldset_legend = True if not len(releases): releases = all_releases else: categories = all_categories releases = all_releases if 'update_th_filter' in req.args: show_releases = req.args.get('release', ['0.11']) if isinstance(show_releases, basestring): show_releases = [show_releases] req.session['th_release_filter'] = ','.join(show_releases) else: show_releases = req.session.get('th_release_filter', '0.11').split(',') output = "" if not hide_release_picker: style = "text-align:right; padding-top:1em; margin-right:5em;" form = builder.form('\n', style=style, method="get") style = "font-size:xx-small;" span = builder.span("Show hacks for releases:", style=style) for version in releases: inp = builder.input(version, type_="checkbox", name="release", value=version) if version in show_releases: inp(checked="checked") span(inp, '\n') style = "font-size:xx-small; padding:0; border:solid 1px black;" span(builder.input(name="update_th_filter", type_="submit", style=style, value="Update"), '\n') form('\n', span, '\n') output = "%s%s\n" % (output, form) def link(resource): return render_resource_link(self.env, formatter.context, resource, 'compact') for category in categories: page = WikiPage(self.env, category) match = self.title_extract.search(page.text) if match: cat_title = '%s' % match.group(1).strip() cat_body = self.title_extract.sub('', page.text, 1) else: cat_title = '%s' % category cat_body = page.text cat_body = self.self_extract.sub('', cat_body).strip() style = "padding:1em; margin:0em 5em 2em 5em; border:1px solid #999;" fieldset = builder.fieldset('\n', style=style) if not hide_fieldset_legend: legend = builder.legend(style="color: #999;") legend(builder.a(cat_title, href=self.env.href.wiki(category))) fieldset(legend, '\n') if not hide_fieldset_description: fieldset(builder.p(wiki_to_html(cat_body, self.env, req))) ul = builder.ul('\n', class_="listtagged") query = 'realm:wiki (%s) %s %s' % \ (' or '.join(show_releases), category, ' '.join(other)) lines = 0 for resource, tags in tag_system.query(req, query): # filter out the page used to make important tags # persistent if resource.id == "tags/persistent": continue lines += 1 li = builder.li(link(resource), ': ') page = WikiPage(self.env, resource) match = self.title_extract.search(page.text) description = "''no description available''" if match: if match.group(1): description = match.group(1).strip() li(wiki_to_oneliner(description, self.env, req=req)) if tags: if hide_fieldset_legend == False and category in tags: tags.remove(category) self.log.debug("hide %s: no legend" % category) for o in other: if o in tags: tags.remove(o) rendered_tags = [ link(resource('tag', tag)) for tag in natural_sort(tags) ] span = builder.span(style="font-size:xx-small;") span(' (tags: ', rendered_tags[0], [(', ', tag) for tag in rendered_tags[1:]], ')') li(span) ul(li, '\n') if lines: fieldset(ul, '\n') else: message = "No results for %s." % \ (hide_release_picker and "this version" or "your selection") fieldset(builder.p(builder.em(message)), '\n') output = "%s%s\n" % (output, fieldset) return output
def expand_macro(self, formatter, name, content): env = self.env req = formatter.req args, kw = parse_args(content) # Use macro arguments (most likely wiki macro calls). realms = 'realm' in kw and kw['realm'].split('|') or [] tag_system = TagSystem(env) all_realms = [p.get_taggable_realm() for p in tag_system.tag_providers] self.all_realms = all_realms self.realms = realms if name == 'TagCloud': args.append(' or '.join(['realm:%s' % r for r in realms])) all_tags = tag_system.get_all_tags(req, ' '.join(args)) mincount = 'mincount' in kw and kw['mincount'] or None return self.render_cloud(req, all_tags, caseless_sort=self.caseless_sort, mincount=mincount) elif name == 'ListTagged': if _OBSOLETE_ARGS_RE.search(content): data = {'warning': 'obsolete_args'} else: data = {'warning': None} context = formatter.context # Use TagsQuery arguments (most likely wiki macro calls). cols = 'cols' in kw and kw['cols'] or self.default_cols format = 'format' in kw and kw['format'] or self.default_format query = args and args[0].strip() or None if query and not realms: # First read query arguments (most likely a web-UI call). for realm in all_realms: if re.search('(^|\W)realm:%s(\W|$)' % (realm), query): realms = realms and realms.append(realm) or [realm] if not realms: # Apply ListTagged defaults to macro call w/o realm. realms = list(set(all_realms) - set(self.exclude_realms)) if not realms: return '' else: self.query = query self.realms = realms query = '(%s) (%s)' % (query or '', ' or '.join( ['realm:%s' % (r) for r in realms])) env.log.debug('LISTTAGGED_QUERY: ' + query) query_result = tag_system.query(req, query) if not query_result: return '' def _link(resource): if resource.realm == 'tag': # Keep realm selection in tag links. return builder.a(resource.id, href=self.get_href(req, tag=resource)) elif resource.realm == 'ticket': # Return resource link including ticket status dependend # class to allow for common Trac ticket link style. ticket = Ticket(env, resource.id) return builder.a('#%s' % ticket.id, class_=ticket['status'], href=formatter.href.ticket(ticket.id), title=shorten_line(ticket['summary'])) return render_resource_link(env, context, resource, 'compact') if format == 'table': cols = [ col for col in cols.split('|') if col in self.supported_cols ] # Use available translations from Trac core. try: labels = TicketSystem(env).get_ticket_field_labels() labels['id'] = _('Id') except AttributeError: # Trac 0.11 neither has the attribute nor uses i18n. labels = {'id': 'Id', 'description': 'Description'} labels['realm'] = _('Realm') labels['tags'] = _('Tags') headers = [{'label': labels.get(col)} for col in cols] data.update({'cols': cols, 'headers': headers}) results = sorted(query_result, key=lambda r: \ embedded_numbers(to_unicode(r[0].id))) results = self._paginate(req, results) rows = [] for resource, tags in results: desc = tag_system.describe_tagged_resource(req, resource) tags = sorted(tags) if tags: rendered_tags = [ _link(Resource('tag', tag)) for tag in tags ] if 'oldlist' == format: resource_link = _link(resource) else: desc = desc or \ get_resource_description(env, resource, context=context) resource_link = builder.a(desc, href=get_resource_url( env, resource, context.href)) if 'table' == format: cells = [] for col in cols: if col == 'id': cells.append(_link(resource)) # Don't duplicate links to resource in both. elif col == 'description' and 'id' in cols: cells.append(desc) elif col == 'description': cells.append(resource_link) elif col == 'realm': cells.append(resource.realm) elif col == 'tags': cells.append( builder([(tag, ' ') for tag in rendered_tags])) rows.append({'cells': cells}) continue rows.append({ 'desc': desc, 'rendered_tags': None, 'resource_link': _link(resource) }) data.update({ 'format': format, 'paginator': results, 'results': rows, 'tags_url': req.href('tags') }) # Work around a bug in trac/templates/layout.html, that causes a # TypeError for the wiki macro call, if we use add_link() alone. add_stylesheet(req, 'common/css/search.css') return Chrome(env).render_template(req, 'listtagged_results.html', data, 'text/html', True)
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)
def expand_macro(self, formatter, name, content, realms=[]): """Evaluate macro call and render results. Calls from web-UI come with pre-processed realm selection. """ env = self.env req = formatter.req tag_system = TagSystem(env) all_realms = tag_system.get_taggable_realms() if not all_realms: # Tag providers are required, no result without at least one. return '' args, kw = parse_args(content) query = args and args[0].strip() or None if not realms: # Check macro arguments for realms (typical wiki macro call). realms = 'realm' in kw and kw['realm'].split('|') or [] if query: # Add realms from query expression. realms.extend(query_realms(query, all_realms)) # Remove redundant realm selection for performance. if set(realms) == all_realms: query = re.sub('(^|\W)realm:\S+(\W|$)', ' ', query).strip() if name == 'TagCloud': # Set implicit 'all tagged realms' as default. if not realms: realms = all_realms if query: all_tags = Counter() # Require per resource query including view permission checks. for resource, tags in tag_system.query(req, query): all_tags.update(tags) else: # Allow faster per tag query, side steps permission checks. all_tags = tag_system.get_all_tags(req, realms=realms) mincount = 'mincount' in kw and kw['mincount'] or None return self.render_cloud(req, all_tags, caseless_sort=self.caseless_sort, mincount=mincount, realms=realms) elif name == 'ListTagged': if content and _OBSOLETE_ARGS_RE.search(content): data = {'warning': 'obsolete_args'} else: data = {'warning': None} context = formatter.context # Use TagsQuery arguments (most likely wiki macro calls). cols = 'cols' in kw and kw['cols'] or self.default_cols format = 'format' in kw and kw['format'] or self.default_format if not realms: # Apply ListTagged defaults to macro call w/o realm. realms = list(set(all_realms) - set(self.exclude_realms)) if not realms: return '' query = '(%s) (%s)' % (query or '', ' or '.join( ['realm:%s' % (r) for r in realms])) query_result = tag_system.query(req, query) excludes = [ exc.strip() for exc in kw.get('exclude', '').split(':') if exc.strip() ] if excludes and query_result: filtered_result = [(resource, tags) for resource, tags in query_result if not any( fnmatchcase(resource.id, exc) for exc in excludes)] query_result = filtered_result if not query_result: return '' def _link(resource): if resource.realm == 'tag': # Keep realm selection in tag links. return builder.a(resource.id, href=self.get_href(req, realms, tag=resource)) elif resource.realm == 'ticket': # Return resource link including ticket status dependend # class to allow for common Trac ticket link style. ticket = Ticket(env, resource.id) return builder.a('#%s' % ticket.id, class_=ticket['status'], href=formatter.href.ticket(ticket.id), title=shorten_line(ticket['summary'])) return render_resource_link(env, context, resource, 'compact') if format == 'table': cols = [ col for col in cols.split('|') if col in self.supported_cols ] # Use available translations from Trac core. try: labels = TicketSystem(env).get_ticket_field_labels() labels['id'] = _('Id') except AttributeError: # Trac 0.11 neither has the attribute nor uses i18n. labels = {'id': 'Id', 'description': 'Description'} labels['realm'] = _('Realm') labels['tags'] = _('Tags') headers = [{'label': labels.get(col)} for col in cols] data.update({'cols': cols, 'headers': headers}) try: results = sorted( query_result, key=lambda r: embedded_numbers(to_unicode(r[0].id))) except (InvalidQuery, InvalidTagRealm), e: return system_message(_("ListTagged macro error"), e) results = self._paginate(req, results, realms) rows = [] for resource, tags in results: desc = tag_system.describe_tagged_resource(req, resource) tags = sorted(tags) wiki_desc = format_to_oneliner(env, context, desc) if tags: rendered_tags = [ _link(Resource('tag', tag)) for tag in tags ] if 'oldlist' == format: resource_link = _link(resource) else: resource_link = builder.a(wiki_desc, href=get_resource_url( env, resource, context.href)) if 'table' == format: cells = [] for col in cols: if col == 'id': cells.append(_link(resource)) # Don't duplicate links to resource in both. elif col == 'description' and 'id' in cols: cells.append(wiki_desc) elif col == 'description': cells.append(resource_link) elif col == 'realm': cells.append(resource.realm) elif col == 'tags': cells.append( builder([(tag, ' ') for tag in rendered_tags])) rows.append({'cells': cells}) continue rows.append({ 'desc': wiki_desc, 'rendered_tags': None, 'resource_link': _link(resource) }) data.update({ 'format': format, 'paginator': results, 'results': rows, 'tags_url': req.href('tags') }) # Work around a bug in trac/templates/layout.html, that causes a # TypeError for the wiki macro call, if we use add_link() alone. add_stylesheet(req, 'common/css/search.css') return Chrome(env).render_template(req, 'listtagged_results.html', data, 'text/html', True)
class TagWikiSyntaxProvider(Component): """[opt] Provides tag:<expr> links. This extends TracLinks via WikiFormatting to point at tag queries or at specific tags. """ implements(IWikiSyntaxProvider) def __init__(self): self.tag_system = TagSystem(self.env) # IWikiSyntaxProvider methods def get_wiki_syntax(self): """Additional syntax for quoted tags or tag expression.""" tag_expr = (r"(%s)" % (WikiParser.QUOTED_STRING)) # Simple (tag|tagged):link syntax yield ( r'''(?P<qualifier>tag(?:ged)?):(?P<tag_expr>%s)''' % tag_expr, lambda f, ns, match: self._format_tagged( f, match.group('qualifier'), match.group('tag_expr'), '%s:%s' % (match.group('qualifier'), match.group('tag_expr')))) # [(tag|tagged):link with label] yield ( r'''\[tag(?:ged)?:''' r'''(?P<ltag_expr>%s)\s*(?P<tag_title>[^\]]+)?\]''' % tag_expr, lambda f, ns, match: self._format_tagged( f, 'tag', match.group('ltag_expr'), match.group('tag_title'))) def get_link_resolvers(self): return [('tag', self._format_tagged), ('tagged', self._format_tagged)] def _format_tagged(self, formatter, ns, target, label, fullmatch=None): """Tag and tag query expression link formatter.""" def unquote(text): """Strip all matching pairs of outer quotes from string.""" while re.match(WikiParser.QUOTED_STRING, text): # Remove outer whitespace after stripped quotation too. text = text[1:-1].strip() return text label = label and unquote(label.strip()) or '' target = unquote(target.strip()) query = target # Pop realms from query expression. all_realms = self.tag_system.get_taggable_realms(formatter.perm) realms = query_realms(target, all_realms) if realms: kwargs = dict((realm, 'on') for realm in realms) target = re.sub('(^|\W)realm:\S+(\W|$)', ' ', target).strip() else: kwargs = {} tag_res = Resource('tag', target) if 'TAGS_VIEW' not in formatter.perm(tag_res): return tag.span(label, class_='forbidden tags', title=_("no permission to view tags")) context = formatter.context href = self.tag_system.get_resource_url(tag_res, context.href, kwargs) if all_realms and (target in self.tag_system.get_all_tags( formatter.req) or not iter_is_empty( self.tag_system.query(formatter.req, query))): # At least one tag provider is available and tag exists or # tags query yields at least one match. if label: return tag.a(label, href=href) return render_resource_link(self.env, context, tag_res) return tag.a(label + '?', href=href, class_='missing tags', rel='nofollow')
class WikiTagProviderTestCase(unittest.TestCase): def setUp(self): self.env = EnvironmentStub(default_data=True, enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() self.perms = PermissionSystem(self.env) self.tag_s = TagSystem(self.env) self.tag_wp = WikiTagProvider(self.env) self.db = self.env.get_db_cnx() setup = TagSetup(self.env) # Current tractags schema is partially setup with enabled component. # Revert these changes for getting a clean setup. self._revert_tractags_schema_init() setup.upgrade_environment(self.db) cursor = self.db.cursor() # Populate table with initial test data. cursor.execute(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'WikiStart', 'tag1') """) self.req = Mock() # Mock an anonymous request. self.req.perm = PermissionCache(self.env) self.realm = 'wiki' self.tags = ['tag1'] def tearDown(self): self.db.close() # Really close db connections. self.env.shutdown() shutil.rmtree(self.env.path) # Helpers def _revert_tractags_schema_init(self): cursor = self.db.cursor() cursor.execute("DROP TABLE IF EXISTS tags") cursor.execute("DELETE FROM system WHERE name='tags_version'") cursor.execute( "DELETE FROM permission WHERE action %s" % self.db.like(), ('TAGS_%', )) # Tests def test_get_tags(self): resource = Resource('wiki', 'WikiStart') self.assertEquals( [tag for tag in self.tag_wp.get_resource_tags(self.req, resource)], self.tags) def test_exclude_template_tags(self): cursor = self.db.cursor() # Populate table with more test data. cursor.execute(""" INSERT INTO tags (tagspace, name, tag) VALUES ('wiki', 'PageTemplates/Template', 'tag2') """) tags = ['tag1', 'tag2'] # Previous workaround for regression in query parser still works, # but the query without argument works again as well. self.assertEquals( self.tag_s.get_all_tags(self.req, '-invalid').keys(), self.tags) self.assertEquals( self.tag_s.get_all_tags(self.req, '').keys(), self.tags) self.env.config.set('tags', 'query_exclude_wiki_templates', False) self.assertEquals( self.tag_s.get_all_tags(self.req, '-invalid').keys(), tags) self.assertEquals(self.tag_s.get_all_tags(self.req, '').keys(), tags) def test_set_tags_no_perms(self): resource = Resource('wiki', 'TaggedPage') self.assertRaises(PermissionError, self.tag_wp.set_resource_tags, self.req, resource, self.tags) def test_set_tags(self): resource = Resource('wiki', 'TaggedPage') self.req.perm = PermissionCache(self.env, username='******') # Shouldn't raise an error with appropriate permission. self.tag_wp.set_resource_tags(self.req, resource, self.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 TagRPC(Component): """[extra] RPC interface for the tag system. Access Trac resource tagging system through methods provided by [https://trac-hacks.org/wiki/XmlRpcPlugin XmlRpcPlugin]. """ implements(IXMLRPCHandler) def __init__(self): self.tag_system = TagSystem(self.env) # IXMLRPCHandler methods def xmlrpc_namespace(self): return 'tags' def xmlrpc_methods(self): yield (None, ((list, str),), self.splitIntoTags) yield ('TAGS_VIEW', ((list,),), self.getTaggableRealms) yield ('TAGS_VIEW', ((dict,), (dict, list)), self.getAllTags) yield ('TAGS_VIEW', ((list, str, str),), self.getTags) yield ('TAGS_VIEW', ((list, str),), self.query) yield ('TAGS_MODIFY', ((list, str, str, list), (list, str, str, list, str)), self.addTags) yield ('TAGS_MODIFY', ((list, str, str, list), (list, str, str, list, str)), self.setTags) # Exported functions and TagSystem methods def addTags(self, req, realm, id, tags, comment=u''): """Add the supplied list of tags to a taggable Trac resource. Returns the updated list of resource tags. """ resource = Resource(realm, id) # Replicate TagSystem.add_tags() method due to xmlrpclib issue. tags = set(tags) tags.update(self._get_tags(req, resource)) self.tag_system.set_tags(req, resource, tags, comment) return self._get_tags(req, resource) def getAllTags(self, req, realms=[]): """Returns a dict of all tags as keys and occurrences as values. If a realm list is supplied, only tags from these taggable realms are shown. """ # Type conversion needed for content transfer of Counter object. return dict(self.tag_system.get_all_tags(req, realms)) def getTaggableRealms(self, req): """Returns the list of taggable Trac realms.""" return list(self.tag_system.get_taggable_realms()) def getTags(self, req, realm, id): """Returns the list of tags for a Trac resource.""" return self._get_tags(req, Resource(realm, id)) def query(self, req, query_str): """Returns a list of tagged Trac resources, whose tags match the supplied tag query expression. """ # Type conversion needed for content transfer of Python set objects. return [(resource.realm, resource.id, list(tags)) for resource, tags in self.tag_system.query(req, query_str)] def setTags(self, req, realm, id, tags, comment=u''): """Replace tags for a Trac resource with the supplied list of tags. Returns the updated list of resource tags. """ resource = Resource(realm, id) self._get_tags(req, resource) # Trac resource exists? self.tag_system.set_tags(req, resource, tags, comment) return self._get_tags(req, resource) def splitIntoTags(self, req, tag_str): """Returns a list of tags from a string. Comma, whitespace and combinations of these characters are recognized as delimiter, that get stripped from the output. """ return split_into_tags(tag_str) # Private methods def _get_tags(self, req, resource): if not resource_exists(self.env, resource): raise ResourceNotFound('Resource "%r" does not exists' % resource) # Workaround for ServiceException when calling TagSystem.get_tags(). provider = [p for p in self.tag_system.tag_providers if p.get_taggable_realm() == resource.realm][0] # Type conversion needed for content transfer of Python set objects. return list(provider.get_resource_tags(req, resource))
def __init__(self): self.tag_system = TagSystem(self.env)
def render_new(self, req, data, hacks): req.perm.require('HACK_CREATE') tag_system = TagSystem(self.env) hacks = list(hacks) hack_names = set(r[2].id for r in hacks) users = set(u.id for u, _ in tag_system.query(req, 'realm:wiki user')) exclude = hack_names.union(users).union(data['types']).union(data['releases']) cloud = {} for votes, rank, resource, tags, title in hacks: for tag in tags: if tag in exclude: continue try: cloud[tag] += 1 except KeyError: cloud[tag] = 1 # Pick the top 25 tags + a random sample of 10 from the rest. cloud = sorted(cloud.items(), key=lambda i: -i[1]) remainder = cloud[25:] cloud = dict(cloud[:25] + random.sample(remainder, min(10, len(remainder)))) # Render the cloud min_px = 8 max_px = 20 def cloud_renderer(tag, count, percent): self.env.log.debug("cloud: %s = %2.2f%%" % (tag, percent * 100)) return builder.a(tag, href='#', style='font-size: %ipx' % int(min_px + percent * (max_px - min_px))) data['cloud'] = render_cloud(self.env, req, cloud, cloud_renderer) add_script(req, 'common/js/wikitoolbar.js') add_script(req, 'common/js/folding.js') data['focus'] = 'name' # Populate data with form submission if req.method == 'POST' and 'create' in req.args or 'preview' in req.args: data.update(req.args) context = self.form.validate(data) data['form_context'] = context vars = {} vars['OWNER'] = req.authname vars['WIKINAME'] = get_page_name(data['name'], data['type']) vars['TYPE'] = data.setdefault('type', 'plugin') vars['TITLE'] = data.setdefault('title', 'No title available') vars['LCNAME'] = vars['WIKINAME'].lower() vars['SOURCEURL'] = '%s/%s' % (self.svnbase, vars['LCNAME']) vars['DESCRIPTION'] = data.setdefault('description', 'No description available') vars['EXAMPLE'] = data.setdefault('example', 'No example available') if 'create' in req.args and not context.errors: success, message = self.create_hack(req, data, vars) if success: target = '%s?%s' % \ (req.href.wiki(vars['WIKINAME']), 'hack=created') req.redirect(target) raise RequestDone else: add_warning(req, message) elif 'preview' in req.args and not context.errors: page = WikiPage(self.env, self.template) if not page.exists: raise TracError('New hack template %s does not exist.' % \ self.template) template = Template(page.text).substitute(vars) template = re.sub(r'\[\[ChangeLog[^\]]*\]\]', 'No changes yet', template) data['page_preview'] = wiki_to_html(template, self.env, req) else: data['form_context'] = None data['type'] = 'plugin' data['release'] = ['0.11'] self.env.log.debug('MUPPETS AHOY') return 'hacks_new.html', data, None
def _delete_tags(self, req, resource): # Delete tags of the resource. tag_system = TagSystem(self.env) tag_system.delete_tags(req, resource)
def create_hack(self, req, data, vars): import fcntl messages = [] created = False have_lock = False lockfile = open(self.lockfile, "w") try: rv = fcntl.flock(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB) if rv: raise TracError('Failed to acquire lock, error: %i' % rv) have_lock = True except IOError: messages.append( 'A hack is currently being created by another user. ' 'Please wait a few seconds, then click the "Create hack" ' 'button again.' ) if have_lock: steps_done = [] try: # Step 1: create repository paths from os import popen svn_path = 'file://%s' % \ self.env.config.get('trac', 'repository_dir') svn_path = svn_path.rstrip('/') page_name = vars['WIKINAME'] hack_path = vars['LCNAME'] paths = [ '%s/%s' % (svn_path, hack_path) ] selected_releases = data['selected_releases'] if isinstance(selected_releases, (basestring, unicode)): selected_releases = [ selected_releases, ] for release in selected_releases: if release == 'anyrelease': continue paths.append("%s/%s/%s" % \ (svn_path, hack_path, release)) cmd = '/usr/bin/op create-hack %s ' % req.authname cmd += '"New hack %s, created by %s" ' % \ (page_name, req.authname) cmd += '%s 2>&1' % ' '.join(paths) output = popen(cmd).readlines() if output: raise Exception( "Failed to create Subversion paths:\n%s" % \ '\n'.join(output) ) steps_done.append('repository') # Step 2: Add permissions from svnauthz.model import User, Path, PathAcl authz_file = self.env.config.get('trac', 'authz_file') authz = AuthzFileReader().read(authz_file) svn_path_acl = PathAcl(User(req.authname), r=True, w=True) authz.add_path(Path("/%s" % hack_path, acls = [svn_path_acl,])) AuthzFileWriter().write(authz_file, authz) steps_done.append('permissions') # Step 3: Add component component = TicketComponent(self.env) component.name = page_name component.owner = req.authname component.insert() steps_done.append('component') # Step 4: Create wiki page template_page = WikiPage(self.env, self.template) page = WikiPage(self.env, page_name) page.text = Template(template_page.text).substitute(vars) page.save(req.authname, 'New hack %s, created by %s' % \ (page_name, req.authname), '0.0.0.0') steps_done.append('wiki') # Step 5: Tag the new wiki page res = Resource('wiki', page_name) tags = data['tags'].split() + selected_releases + [data['type']] TagSystem(self.env).set_tags(req, res, tags) steps_done.append('tags') rv = fcntl.flock(lockfile, fcntl.LOCK_UN) created = True except Exception, e: try: if 'tags' in steps_done: res = Resource('wiki', page_name) tags = data['tags'].split() + selected_releases TagSystem(self.env).delete_tags(req, res, tags) if 'wiki' in steps_done: WikiPage(self.env, page_name).delete() if 'component' in steps_done: TicketComponent(self.env, page_name).delete() if 'permissions' in steps_done: authz_file = self.env.config.get('trac', 'authz_file') authz = AuthzFileReader().read(authz_file) authz.del_path(Path("/%s" % hack_path)) AuthzFileWriter().write(authz_file, authz) # TODO: rollback subversion path creation rv = fcntl.flock(lockfile, fcntl.LOCK_UN) except: self.env.log.error("Rollback failed") rv = fcntl.flock(lockfile, fcntl.LOCK_UN) self.env.log.error(e, exc_info=True) raise TracError(str(e))
def process_request(self, req): req.perm.require('TAGS_VIEW') match = re.match(r'/tags/?(.*)', req.path_info) tag_id = match.group(1) and match.group(1) or None query = req.args.get('q', '') # Consider only providers, that are permitted for display. tag_system = TagSystem(self.env) all_realms = tag_system.get_taggable_realms(req.perm) if not (tag_id or query) or [r for r in all_realms if r in req.args ] == []: for realm in all_realms: if not realm in self.exclude_realms: req.args[realm] = 'on' checked_realms = [r for r in all_realms if r in req.args] if query: # Add permitted realms from query expression. checked_realms.extend(query_realms(query, all_realms)) realm_args = dict( zip([r for r in checked_realms], ['on' for r in checked_realms])) # Switch between single tag and tag query expression mode. if tag_id and not re.match(r"""(['"]?)(\S+)\1$""", tag_id, re.UNICODE): # Convert complex, invalid tag ID's --> query expression. req.redirect(req.href.tags(realm_args, q=tag_id)) elif query: single_page = re.match(r"""(['"]?)(\S+)\1$""", query, re.UNICODE) if single_page: # Convert simple query --> single tag. req.redirect(req.href.tags(single_page.group(2), realm_args)) data = dict(page_title=_("Tags"), checked_realms=checked_realms) # Populate the TagsQuery form field. data['tag_query'] = tag_id and tag_id or query data['tag_realms'] = list( dict(name=realm, checked=realm in checked_realms) for realm in all_realms) if tag_id: data['tag_page'] = WikiPage(self.env, tag_system.wiki_page_prefix + tag_id) if query or tag_id: macro = 'ListTagged' # TRANSLATOR: The meta-nav link label. add_ctxtnav(req, _("Back to Cloud"), req.href.tags()) args = "%s,format=%s,cols=%s" % \ (tag_id and tag_id or query, self.default_format, self.default_cols) data['mincount'] = None else: macro = 'TagCloud' mincount = as_int(req.args.get('mincount', None), self.cloud_mincount) args = mincount and "mincount=%s" % mincount or None data['mincount'] = mincount formatter = Formatter(self.env, Context.from_request(req, Resource('tag'))) self.env.log.debug("%s macro arguments: %s" % (macro, args and args or '(none)')) macros = TagWikiMacros(self.env) try: # Query string without realm throws 'NotImplementedError'. data['tag_body'] = checked_realms and \ macros.expand_macro(formatter, macro, args, realms=checked_realms) \ or '' except InvalidQuery, e: data['tag_query_error'] = to_unicode(e) data['tag_body'] = macros.expand_macro(formatter, 'TagCloud', '')
def fetch_hacks(self, req, data, types, releases): """Return a list of hacks in the form [votes, rank, resource, tags, title] """ tag_system = TagSystem(self.env) vote_system = VoteSystem(self.env) query = 'realm:wiki (%s) (%s)' % \ (' or '.join(releases), ' or '.join(types)) self.env.log.debug(query) tagged = tag_system.query(req, query) # Limit try: limit = int(req.args.get('limit', self.limit)) data['limit_message'] = 'top %s' % limit except ValueError: data['limit_message'] = 'all' limit = 9999 data['limit'] = limit # Query q = req.args.get('q', '') data['query'] = q query = Query(q.lower()) # Build hacks list hacks = [] for resource, tags in tagged: page = WikiPage(self.env, resource.id) if q: text = page.name.lower() + page.text.lower() + ' '.join(tags) if not query(text): continue _, count, _ = vote_system.get_vote_counts(resource) match = self.title_extract.search(page.text) count_string = pluralise(count, 'vote') if match: title = '%s (%s)' % (match.group(1).strip(), count_string) else: title = '%s' % count_string hacks.append([count, None, resource, tags, title]) # Rank total_hack_count = len(hacks) hacks = sorted(hacks, key=lambda i: -i[0]) remainder = hacks[limit:] hacks = hacks[:limit] + random.sample(remainder, min(limit, len(remainder))) # Navigation #if len(hacks) >= limit: # add_ctxtnav(req, builder.a('More', href='?action=more')) # limit = len(hacks) # data['limit'] = data['limit_message'] = limit #else: # add_ctxtnav(req, 'More') #if q or limit != self.limit: # add_ctxtnav(req, builder.a('Default', href='?action=default')) #else: # add_ctxtnav(req, 'Default') #if total_hack_count > limit: # add_ctxtnav(req, builder.a('All', href='?action=all')) #else: # add_ctxtnav(req, 'All') #if limit > 10: # limit = min(limit, len(hacks)) # add_ctxtnav(req, builder.a('Less', href='?action=less')) #else: # add_ctxtnav(req, 'Less') #for i, hack in enumerate(hacks): # hack[1] = i return hacks