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) # 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 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 set_resource_tags(self, req, ticket_or_resource, tags, comment=u''): try: resource = ticket_or_resource.resource except AttributeError: resource = ticket_or_resource assert resource.realm == self.realm if not self._check_permission(req, resource, 'modify'): raise PermissionError(resource=resource, env=self.env) tag_set = set(tags) # Processing a call from TracTags, try to alter the ticket. tkt = Ticket(self.env, resource.id) all = self._ticket_tags(tkt) # Avoid unnecessary ticket changes, considering comments below. if tag_set != all: # Will only alter tags in 'keywords' ticket field. split_into_tags = TagSystem(self.env).split_into_tags keywords = split_into_tags(tkt['keywords']) # Assume, that duplication is depreciated and consolitation # wanted to primarily affect 'keywords' ticket field. # Consequently updating ticket tags and reducing (tag) # 'ticket_fields' afterwards may result in undesired tag loss. tag_set.difference_update(all.difference(keywords)) tkt['keywords'] = u' '.join(sorted(map(to_unicode, tag_set))) tkt.save_changes(get_reporter_id(req), comment) else: # Processing a change listener event. tags = self._ticket_tags(ticket_or_resource) super(TicketTagProvider, self).set_resource_tags(req, resource, tags)
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 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 load_pages_with_tags(env, req, tags): tag_system = TagSystem(env) pages = [] blog_resources = [i for i in tag_system.query(req, tags)] for resource, ignored in blog_resources: pages.append(WikiPage(env, resource)) return pages
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 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 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
def _get_keywords(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()) return sorted(keywords) if keywords else []
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 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 setUp(self): self.env = EnvironmentStub( enable=['trac.*', 'tractags.*']) self.env.path = tempfile.mkdtemp() 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 a clean setup. self._revert_tractags_schema_init() setup.upgrade_environment(self.db) 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.anonymous = PermissionCache(self.env) self.reader = PermissionCache(self.env, 'reader') self.writer = PermissionCache(self.env, 'writer') self.admin = PermissionCache(self.env, 'admin') self.href = Href('/trac') self.abs_href = Href('http://example.org/trac')
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()) tag_res = Resource('tag', target) if 'TAGS_VIEW' in formatter.perm(tag_res): context = formatter.context href = get_resource_url(self.env, tag_res, context.href) tag_sys = TagSystem(self.env) # Tag exists or tags query yields at least one match. if target in tag_sys.get_all_tags(formatter.req) or \ [(res, tags) for res, tags in tag_sys.query(formatter.req, target)]: if label: return tag.a(label, href=href) return render_resource_link(self.env, context, tag_res) else: return tag.a(label+'?', href=href, class_='missing tags', rel='nofollow') else: return tag.span(label, class_='forbidden tags', title=_("no permission to view tags"))
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 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 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 set_resource_tags(self, req, resource, tags): req.perm.require('TICKET_MODIFY', resource) split_into_tags = TagSystem(self.env).split_into_tags ticket = Ticket(self.env, resource.id) all = self._ticket_tags(ticket) keywords = split_into_tags(ticket['keywords']) tags.difference_update(all.difference(keywords)) ticket['keywords'] = u' '.join(sorted(map(to_unicode, tags))) ticket.save_changes(req.username, u'')
def _do_save(self, req, versioned_page): title = req.args.get('blogtitle') content = '= %s =\n\n%s' % (title, req.args.get('text', '')) req.args['text'] = content tags = ['blog'] + self._get_tags(req) tag_system = TagSystem(self.env) tag_system.add_tags(req, versioned_page.resource, tags) result = super(NewPostModule, self)._do_save(req, versioned_page) return result
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 wiki_page_renamed(self, page, old_name): """Called when a page has been renamed (since Trac 0.12).""" self.log.debug("Moving wiki page tags from %s to %s", old_name, page.name) tag_sys = TagSystem(self.env) # XXX Ugh. Hopefully this will be sufficient to fool any endpoints. from trac.test import Mock, MockPerm req = Mock(authname='anonymous', perm=MockPerm()) tag_sys.reparent_tags(req, Resource('wiki', page.name), old_name)
def __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 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 download_deleted(self, context, download): # Check proper permissions to modify tags. if 'TAGS_MODIFY' not in context.req.perm: return # Create temporary resource. resource = Resource(self.realm, download['id']) # Delete tags of download. tag_system = TagSystem(self.env) tag_system.delete_tags(context.req, resource)
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 _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 expand_macro(self, formatter, name, content): req = formatter.req query_result = TagSystem(self.env).query(req, content) all_tags = {} # Find tag counts for resource, tags in query_result: for tag in tags: try: all_tags[tag] += 1 except KeyError: all_tags[tag] = 1 return render_cloud(self.env, req, all_tags)
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