def _render_full_format(self, formatter, post_list, post_instances, heading, max_size, show_meta): """ Renters full blog posts. """ out = '' if 'BLOG_VIEW' in formatter.req.perm('blog'): out = tag.div(class_="blog") out.append( tag.div(tag.a(heading, href=formatter.req.href.blog()), class_="blog-list-title")) for post in post_instances: data = { 'post': post, 'blog_personal_blog': self.config.getbool('fullblog', 'personal_blog'), 'list_mode': True, 'show_meta': show_meta, 'execute_blog_macro': True } if max_size: data['blog_max_size'] = max_size txt = Chrome(self.env).render_template( formatter.req, 'fullblog_macro_post.html', data, {'fragment': True}) out.append(Markup(to_unicode(txt))) return out
def expand_macro(self, formatter, name, text, args): if not text: raw_actions = self.config.options('ticket-workflow') else: if args is None: text = '\n'.join(line.lstrip() for line in text.split(';')) if '[ticket-workflow]' not in text: text = '[ticket-workflow]\n' + text parser = RawConfigParser() try: parser.readfp(io.StringIO(text)) except ParsingError as e: return system_message(_("Error parsing workflow."), unicode(e)) raw_actions = list(parser.items('ticket-workflow')) actions = parse_workflow_config(raw_actions) states = list({ state for action in actions.itervalues() for state in action['oldstates'] } | {action['newstate'] for action in actions.itervalues()}) action_labels = [attrs['label'] for attrs in actions.values()] action_names = actions.keys() edges = [] for name, action in actions.items(): new_index = states.index(action['newstate']) name_index = action_names.index(name) for old_state in action['oldstates']: old_index = states.index(old_state) edges.append((old_index, new_index, name_index)) args = args or {} width = args.get('width', 800) height = args.get('height', 600) graph = { 'nodes': states, 'actions': action_labels, 'edges': edges, 'width': width, 'height': height } graph_id = '%012x' % id(graph) req = formatter.req add_script(req, 'common/js/excanvas.js', ie_if='IE') add_script(req, 'common/js/workflow_graph.js') add_script_data(req, {'graph_%s' % graph_id: graph}) return tag( tag.div('', class_='trac-workflow-graph trac-noscript', id='trac-workflow-graph-%s' % graph_id, style="display:inline-block;width:%spx;height:%spx" % (width, height)), tag.noscript( tag.div(_("Enable JavaScript to display the workflow graph."), class_='system-message')))
def generate_captcha(self, req): add_script(req, 'https://www.google.com/recaptcha/api.js') return None, tag( tag.div(class_='g-recaptcha', data_sitekey=self.public_key), tag.input(type='submit', value=_("Submit")) )
def _render(self, formatter, cols, name_pat, size, header, limit): #noinspection PyArgumentList icon = Icons(self.env) icon_dir = icon.icon_location(size)[1] files = fnmatch.filter(os.listdir(icon_dir), '%s.png' % name_pat) icon_names = [os.path.splitext(p)[0] for p in files] if limit: displayed_icon_names = reduce_names(icon_names, limit) else: displayed_icon_names = icon_names icon_table = render_table( displayed_icon_names, cols, lambda name: icon._render_icon(formatter, name, size)) if not len(icon_names): message = 'No %s icon matches %s' % (SIZE_DESCR[size], name_pat) elif len(icon_names) == 1: message = 'Showing the only %s icon matching %s' % \ (SIZE_DESCR[size], name_pat) elif len(displayed_icon_names) == len(icon_names): message = 'Showing all %d %s icons matching %s' % \ (len(icon_names), SIZE_DESCR[size], name_pat) else: message = 'Showing %d of %d %s icons matching %s' % \ (len(displayed_icon_names), len(icon_names), SIZE_DESCR[size], name_pat) return tag.div(tag.p(tag.small(message)) if header else '', icon_table)
def expand_macro(self, formatter, name, content): from trac.mimeview.api import Mimeview mime_map = Mimeview(self.env).mime_map mime_type_filter = '' args, kw = parse_args(content) if args: mime_type_filter = args.pop(0).strip().rstrip('*') mime_types = {} for key, mime_type in mime_map.iteritems(): if (not mime_type_filter or mime_type.startswith(mime_type_filter) ) and key != mime_type: mime_types.setdefault(mime_type, []).append(key) return tag.div(class_='mimetypes')( tag.table(class_='wiki')( tag.thead( tag.tr( tag.th(_("MIME Types")), # always use plural tag.th( tag.a("WikiProcessors", href=formatter.context.href.wiki( 'WikiProcessors'))))), tag.tbody( tag.tr( tag.th(tag.code(mime_type), style="text-align: left"), tag.td( tag.code(' '.join(sorted(mime_types[mime_type]))))) for mime_type in sorted(mime_types))))
def expand_macro(self, formatter, name, content, args=None): args = args or {} reponame = args.get('repository') or '' rev = args.get('revision') repos = RepositoryManager(self.env).get_repository(reponame) try: changeset = repos.get_changeset(rev) except Exception: message = content resource = Resource('repository', reponame) else: message = changeset.message rev = changeset.rev resource = repos.resource if formatter.context.resource.realm == 'ticket': ticket_re = CommitTicketUpdater.ticket_re if not any( int(tkt_id) == int(formatter.context.resource.id) for tkt_id in ticket_re.findall(message)): return tag.p(_("(The changeset message doesn't reference " "this ticket)"), class_='hint') if ChangesetModule(self.env).wiki_format_messages: return tag.div(format_to_html(self.env, formatter.context.child( 'changeset', rev, parent=resource), message, escape_newlines=True), class_='message') else: return tag.pre(message, class_='message')
def render_registration_fields(self, req, data): insert = tag.div(tag.label(_("Details:"), tag.input(type="text", name=TrapFieldFilterStrategy(self.env).name_register, size=60, class_="textwidget"))) if RegistrationFilterStrategy: return RegistrationFilterStrategy(self.env).render_registration_fields(req, data, dict(optional=insert)) else: return dict(optional=insert), data
def filter_stream(self, req, method, filename, stream, data): if self.karma_points > 0: # Insert the hidden field right before the submit buttons trap = tag.div(style='display:none;')( tag.input(type='text', name=self.name, value=''), tag.input(type='hidden', name=self.name_hidden, value='')) stream = stream | \ Transformer('//div[@class="buttons"]').before(trap) return stream
def expand_macro(self, formatter, name, content): min_depth, max_depth = 1, 6 title = None inline = False numbered = True if content: argv = [arg.strip() for arg in content.split(',')] if len(argv) > 0: depth = argv[0] if '-' in depth: min_depth, max_depth = \ [_arg_as_int(d, min=min_depth, max=max_depth) for d in depth.split('-', 1)] else: min_depth = max_depth = \ _arg_as_int(depth, min=min_depth, max=max_depth) if len(argv) > 1: title = argv[1].strip() for arg in argv[2:]: arg = arg.strip().lower() if arg == 'inline': inline = True elif arg == 'unnumbered': numbered = False # TODO: - integrate the rest of the OutlineFormatter directly here # - use formatter.wikidom instead of formatter.source out = io.StringIO() oformatter = OutlineFormatter(self.env, formatter.context) oformatter.format(formatter.source, out, max_depth, min_depth, shorten=not inline) outline = Markup(out.getvalue()) if title: outline = tag.h4(title, class_='section') + outline if not inline: outline = tag.div(outline, class_='wiki-toc') elif not numbered: outline = tag.div(outline, class_='wiki-toc-un') return outline
def _error_div(self, msg): """Display msg in an error box, using Trac style.""" self.log.error(msg) if isinstance(msg, str): msg = tag.pre(escape(msg)) return tag.div(tag.strong( _("Graphviz macro processor has detected an error. " "Please fix the problem before continuing.")), msg, class_="system-message")
def expand_macro(self, formatter, name, content): from trac.wiki.formatter import system_message content = content.strip() if content else '' name_filter = content.strip('*') def get_macro_descr(): for macro_provider in formatter.wiki.macro_providers: names = list(macro_provider.get_macros() or []) if name_filter and not any( name.startswith(name_filter) for name in names): continue try: name_descriptions = [ (name, macro_provider.get_macro_description(name)) for name in names ] except Exception as e: yield system_message( _("Error: Can't get description for macro %(name)s", name=names[0]), e), names else: for descr, pairs in groupby(name_descriptions, key=lambda p: p[1]): if descr: if isinstance(descr, (tuple, list)): descr = dgettext(descr[0], to_unicode(descr[1])) \ if descr[1] else '' else: descr = to_unicode(descr) or '' if content == '*': descr = format_to_oneliner(self.env, formatter.context, descr, shorten=True) else: descr = format_to_html(self.env, formatter.context, descr) yield descr, [name for name, descr in pairs] return tag.div(class_='trac-macrolist')( (tag.h3(tag.code('[[', names[0], ']]'), id='%s-macro' % names[0]), len(names) > 1 and tag.p( tag.strong(_("Aliases:")), [tag.code(' [[', alias, ']]') for alias in names[1:]]) or None, description or tag.em(_("Sorry, no documentation found"))) for description, names in sorted(get_macro_descr(), key=lambda item: item[1][0]))
def expand_macro(self, formatter, name, content): args, kw = parse_args(content) prefix = args[0].strip() if args else None limit = _arg_as_int(args[1].strip(), min=1) if len(args) > 1 else None group = kw.get('group', 'date') sql = """SELECT name, max(version) AS max_version, max(time) AS max_time FROM wiki""" args = [] if prefix: with self.env.db_query as db: sql += " WHERE name %s" % db.prefix_match() args.append(db.prefix_match_value(prefix)) sql += " GROUP BY name ORDER BY max_time DESC" if limit: sql += " LIMIT %s" args.append(limit) entries_per_date = [] prevdate = None for name, version, ts in self.env.db_query(sql, args): if 'WIKI_VIEW' not in formatter.perm('wiki', name, version): continue req = formatter.req date = user_time(req, format_date, from_utimestamp(ts)) if date != prevdate: prevdate = date entries_per_date.append((date, [])) version = int(version) diff_href = None if version > 1: diff_href = formatter.href.wiki(name, action='diff', version=version) page_name = formatter.wiki.format_page_name(name) entries_per_date[-1][1].append((page_name, name, version, diff_href)) items_per_date = ( (date, (tag.li(tag.a(page, href=formatter.href.wiki(name)), tag.small(' (', tag.a(_("diff"), href=diff_href), ')') if diff_href else None, '\n') for page, name, version, diff_href in entries)) for date, entries in entries_per_date) if group == 'date': out = ((tag.h3(date, class_='section'), tag.ul(entries)) for date, entries in items_per_date) else: out = tag.ul(entries for date, entries in items_per_date) return tag.div(out, class_="wikipage")
def _wiki_edit(self, req, stream): tags = ' '.join(self._page_tags(req)) # TRANSLATOR: Label text for link to '/tags'. link = tag.a(_("view all tags"), href=req.href.tags()) # TRANSLATOR: ... (view all tags) insert = tag( tag_("Tag under: (%(tags_link)s)", tags_link=link), tag.br(), tag.input(id='tags', type='text', name='tags', size='50', value=req.args.get('tags', tags))) insert = tag.div(tag.label(insert), class_='field') return stream | Transformer('//div[@id="changeinfo1"]').append(insert)
def expand_macro(self, formatter, name, content): content = content.strip() if content else '' name_filter = content.strip('*') items = {} for subscriber in NotificationSystem(self.env).subscribers: name = subscriber.__class__.__name__ if not name_filter or name.startswith(name_filter): items[name] = subscriber.description() return tag.div(class_='trac-subscriberlist')(tag.table(class_='wiki')( tag.thead(tag.tr(tag.th(_("Subscriber")), tag.th(_("Description")))), tag.tbody( tag.tr(tag.td(tag.code(name)), tag.td(items[name]), class_='odd' if idx % 2 else 'even') for idx, name in enumerate(sorted(items)))))
def get_navigation_items(self, req): if req.is_authenticated: yield ('metanav', 'login', tag_("logged in as %(user)s", user=Chrome(self.env).authorinfo(req, req.authname))) yield ('metanav', 'logout', tag.form( tag.div( tag.button(_("Logout"), name='logout', type='submit'), tag.input(type='hidden', name='__FORM_TOKEN', value=req.form_token) ), action=req.href.logout(), method='post', id='logout', class_='trac-logout')) else: yield ('metanav', 'login', tag.a(_("Login"), href=req.href.login()))
def expand_macro(self, formatter, name, content): curpage = formatter.resource.id # scoped TOC (e.g. TranslateRu/TracGuide or 0.11/TracGuide ...) prefix = '' idx = curpage.find('/') if idx > 0: prefix = curpage[:idx+1] ws = WikiSystem(self.env) return tag.div( tag.h4(_('Table of Contents')), tag.ul([tag.li(tag.a(title, href=formatter.href.wiki(prefix+ref), class_=(not ws.has_page(prefix+ref) and 'missing')), class_=(prefix+ref == curpage and 'active')) for ref, title in self.TOC]), class_='wiki-toc')
def _post_process_request_wiki_edit(self, req): tags = ' '.join(self._page_tags(req)) # TRANSLATOR: Label text for link to '/tags'. link = tag.a(_("view all tags"), href=req.href.tags()) # TRANSLATOR: ... (view all tags) insert = tag( tag_("Tag under: (%(tags_link)s)", tags_link=link), tag.br(), tag.input(id='tags', type='text', name='tags', size='50', value=req.args.get('tags', tags))) insert = tag.div(tag.label(insert), class_='field') filter_lst = [] # xpath = //div[@id="changeinfo1"] xform = JTransformer('div#changeinfo1') filter_lst.append(xform.append(Markup(insert))) self._add_jtransform(req, filter_lst)
def expand_macro(self, formatter, name, content): def wikify(text): return format_to_oneliner(self.env, formatter.context, text) return tag.div( tag.p( wikify( _(""" The following tokens can be used in the `PageTemplates/MyPage` or `PageTemplates/MyPage/<user>` wiki pages: """))), tag.dl([(tag.dt(tag.tt(token)), tag.dd(wikify(gettext(description)))) for token, description in sorted( MyPageModule(self.env).tokens.values())]), tag.p( wikify( _(""" Note that you can also use the `[[MyPageNav]]` wiki macro for creating dynamic links to other ''MyPage'' pages (use `[[MyPageNav?]]` to get help on this macro). """))))
def expand_macro(self, formatter, name, content, args=None): if content is not None: content = content.strip() if not args and not content: raw_actions = self.config.options('ticket-workflow') else: is_macro = args is None if is_macro: kwargs = parse_args(content)[1] file = kwargs.get('file') else: file = args.get('file') if not file and not content: raise ProcessorError("Invalid argument(s).") if file: print(file) text = RepositoryManager(self.env).read_file_by_path(file) if text is None: raise ProcessorError( tag_("The file %(file)s does not exist.", file=tag.code(file))) elif is_macro: text = '\n'.join(line.lstrip() for line in content.split(';')) else: text = content if '[ticket-workflow]' not in text: text = '[ticket-workflow]\n' + text parser = RawConfigParser() try: parser.readfp(io.StringIO(text)) except ParsingError as e: if is_macro: raise MacroError(exception_to_unicode(e)) else: raise ProcessorError(exception_to_unicode(e)) raw_actions = list(parser.items('ticket-workflow')) actions = parse_workflow_config(raw_actions) states = list( {state for action in actions.itervalues() for state in action['oldstates']} | {action['newstate'] for action in actions.itervalues()}) action_labels = [attrs['label'] for attrs in actions.values()] action_names = list(actions) edges = [] for name, action in actions.items(): new_index = states.index(action['newstate']) name_index = action_names.index(name) for old_state in action['oldstates']: old_index = states.index(old_state) edges.append((old_index, new_index, name_index)) args = args or {} width = args.get('width', 800) height = args.get('height', 600) graph = {'nodes': states, 'actions': action_labels, 'edges': edges, 'width': width, 'height': height} graph_id = '%012x' % id(graph) req = formatter.req add_script(req, 'common/js/excanvas.js', ie_if='IE') add_script(req, 'common/js/workflow_graph.js') add_script_data(req, {'graph_%s' % graph_id: graph}) return tag( tag.div('', class_='trac-workflow-graph trac-noscript', id='trac-workflow-graph-%s' % graph_id, style="display:inline-block;width:%spx;height:%spx" % (width, height)), tag.noscript( tag.div(_("Enable JavaScript to display the workflow graph."), class_='system-message')))
def render(self, context, mimetype, content, filename=None, url=None, annotations=None, force_source=False): """Render an XHTML preview of the given `content`. `content` is the same as an `IHTMLPreviewRenderer.render`'s `content` argument. The specified `mimetype` will be used to select the most appropriate `IHTMLPreviewRenderer` implementation available for this MIME type. If not given, the MIME type will be infered from the filename or the content. Return a string containing the XHTML text. When rendering with an `IHTMLPreviewRenderer` fails, a warning is added to the request associated with the context (if any), unless the `disable_warnings` hint is set to `True`. """ if not content: return '' # Ensure we have a MIME type for this content full_mimetype = mimetype if not full_mimetype: if hasattr(content, 'read'): content = content.read(self.max_preview_size) full_mimetype = self.get_mimetype(filename, content) if full_mimetype: mimetype = ct_mimetype(full_mimetype) # split off charset else: mimetype = full_mimetype = 'text/plain' # fallback if not binary # Determine candidate `IHTMLPreviewRenderer`s candidates = [] for renderer in self.renderers: qr = renderer.get_quality_ratio(mimetype) if qr > 0: candidates.append((qr, renderer)) candidates.sort(key=lambda item: -item[0]) # Wrap file-like object so that it can be read multiple times if hasattr(content, 'read'): content = Content(content, self.max_preview_size) # First candidate which renders successfully wins. # Also, we don't want to expand tabs more than once. expanded_content = None for qr, renderer in candidates: if force_source and not getattr(renderer, 'returns_source', False): continue # skip non-source renderers in force_source mode if isinstance(content, Content): content.reset() try: ann_names = ', '.join(annotations) if annotations else \ 'no annotations' self.log.debug('Trying to render HTML preview using %s [%s]', renderer.__class__.__name__, ann_names) # check if we need to perform a tab expansion rendered_content = content if getattr(renderer, 'expand_tabs', False): if expanded_content is None: content = content_to_unicode(self.env, content, full_mimetype) expanded_content = content.expandtabs(self.tab_width) rendered_content = expanded_content result = renderer.render(context, full_mimetype, rendered_content, filename, url) if not result: continue if not (force_source or getattr(renderer, 'returns_source', False)): # Direct rendering of content if isinstance(result, basestring): return Markup(to_unicode(result)) elif isinstance(result, Fragment): return result.__html__() else: return result # Render content as source code if annotations: marks = context.req.args.get('marks') if context.req \ else None if marks: context.set_hints(marks=marks) return self._render_source(context, result, annotations) else: if isinstance(result, list): result = Markup('\n').join(result) return tag.div(class_='code')(tag.pre(result)) except Exception as e: self.log.warning('HTML preview using %s with %r failed: %s', renderer.__class__.__name__, context, exception_to_unicode(e, traceback=True)) if context.req and not context.get_hint('disable_warnings'): from trac.web.chrome import add_warning add_warning( context.req, _("HTML preview using %(renderer)s failed (%(err)s)", renderer=renderer.__class__.__name__, err=exception_to_unicode(e)))
def expand_macro(self, formatter, name, content, args=None): class_list = ['wikiextras', 'box'] style_list = [] if args is None: content, args = parse_args(content) #noinspection PyArgumentList if not Icons(self.env).shadowless: class_list.append('shadow') class_arg = args.get('class', '') if class_arg: class_list.append(class_arg) align = ('right' if name in ('newsbox', 'rbox') else 'center' if name == 'imagebox' else 'left' if name == 'lbox' else '') align = args.get('align', align) if align: class_list.append(align) if name == 'newsbox': type = 'news' elif name == 'imagebox': type = 'image' else: type = args.get('type') if not type: for flag, value in args.iteritems(): if value is True: type = flag break type = self._get_type(type) if type in self.types: td = self.types[type] # type data if td[1]: #icon class_list += ['icon', td[1]] else: class_list.append(type) bg = self.urgency_bg.get(td[0]) if bg: class_list.append(bg) del td elif type: class_list.append(type) style = args.get('style', '') if style: style_list.append(style) width = args.get('width', '') if width: if width.isdigit(): width = '%spx' % width if width.endswith('px'): # compensate for padding if self._has_icon(type): width = '%dpx' % (int(width[:-2]) - 57) else: width = '%dpx' % (int(width[:-2]) - 22) style_list.append('width:%s' % width) html = format_to_html(self.env, formatter.context, content) class_ = ' '.join(class_list) style = ';'.join(style_list) div = sanitize_attrib(self.env, tag.div(class_=class_, style=style)) div(html) return div
def render(self, context, mimetype, content, filename=None, url=None): if url: return tag.div(tag.img(src=url, alt=filename), class_='image-file')
def expand_macro(self, formatter, name, content): # Parse content for arguments args_list, args_dict = parse_args(content) from_dt, to_dt = parse_period( list(args_dict.get('period', '').split('/'))) category = args_dict.get('category', '') author = args_dict.get('author', '') recent = as_int(args_dict.get('recent'), 0) format = args_dict.get('format', 'inline').lower() heading = args_dict.get('heading', '') max_size = as_int(args_dict.get('max_size', 0)) show_meta = args_dict.get('meta', '') != 'off' and True or False # Get blog posts all_posts = get_blog_posts(self.env, author=author, category=category, from_dt=from_dt, to_dt=to_dt) # Trim posts against permissions and count post_list = [] post_instances = [] if format in ['float', 'full']: recent = recent or self.config.getint('fullblog', 'num_items_front') recent = recent or len(all_posts) count = 0 for post in all_posts: if count == recent: break bp = BlogPost(self.env, post[0]) if 'BLOG_VIEW' in formatter.req.perm(bp.resource): count += 1 post_instances.append(bp) post_list.append(post) # Rendering add_stylesheet(formatter.req, 'tracfullblog/css/fullblog.css') add_stylesheet(formatter.req, 'common/css/code.css') if format == 'inline': data = { 'heading': heading, 'posts': post_list, 'blog_personal_blog': self.config.getbool('fullblog', 'personal_blog'), 'show_meta': show_meta, 'execute_blog_macro': True } return Chrome(self.env).render_template( formatter.req, 'fullblog_macro_monthlist.html', data, {'fragment': True}) elif format in ('full', 'float'): out = self._render_full_format(formatter, post_list, post_instances, heading, max_size, show_meta) if out and format == 'float': return tag.div(out, class_="blogflash") else: return out else: raise TracError("Invalid 'format' argument used for macro %s." % name)
def expand_macro(self, formatter, name, content): from trac.config import ConfigSection, Option args, kw = parse_args(content) filters = {} for name, index in (('section', 0), ('option', 1)): pattern = kw.get(name, '').strip() if pattern: filters[name] = fnmatch.translate(pattern) continue prefix = args[index].strip() if index < len(args) else '' if prefix: filters[name] = re.escape(prefix) has_option_filter = 'option' in filters for name in ('section', 'option'): filters[name] = re.compile(filters[name], re.IGNORECASE).match \ if name in filters \ else lambda v: True section_filter = filters['section'] option_filter = filters['option'] section_registry = ConfigSection.get_registry(self.compmgr) option_registry = Option.get_registry(self.compmgr) options = {} for (section, key), option in option_registry.iteritems(): if section_filter(section) and option_filter(key): options.setdefault(section, {})[key] = option if not has_option_filter: for section in section_registry: if section_filter(section): options.setdefault(section, {}) for section in options: options[section] = sorted(options[section].itervalues(), key=lambda option: option.name) sections = [(section, section_registry[section].doc if section in section_registry else '') for section in sorted(options)] def default_cell(option): default = option.default if default is not None and default != '': return tag.td(tag.code(option.dumps(default)), class_='default') else: return tag.td(_("(no default)"), class_='nodefault') def options_table(section, options): if options: return tag.table(class_='wiki')(tag.tbody( tag.tr(tag.td( tag.a(tag.code(option.name), class_='tracini-option', href='#%s-%s-option' % (section, option.name))), tag.td( format_to_html(self.env, formatter.context, option.doc)), default_cell(option), id='%s-%s-option' % (section, option.name), class_='odd' if idx % 2 else 'even') for idx, option in enumerate(options))) return tag.div(class_='tracini')( (tag.h3(tag.code('[%s]' % section), id='%s-section' % section), format_to_html(self.env, formatter.context, section_doc), options_table(section, options.get(section))) for section, section_doc in sections)
self._record_action(status, type, ("ok" if spamstatus == rejected else "error"), strategy, 0) else: self._record_action(status, type, '', strategy, 0) self._record_action(status, type, '', '', 0) LogEntry.purge(self.env, self.purge_age) if score < self.min_karma: self.log.debug('Rejecting submission %r by "%s" (%r) because it ' 'earned only %d karma points (%d are required).', abbrev, author, req.remote_addr, score, self.min_karma) rejects = [] outreasons.sort() for r in outreasons: rejects.append(tag.li(r)) msg = tag.div(tag.ul(rejects), class_='message') self.reject_handler.reject_content(req, msg) def train(self, req, ids, spam=True, delete=False): environ = {} for name, value in req.environ.items(): if not name.startswith('HTTP_'): environ[name] = value if not isinstance(ids, list): ids = [ids] for log_id in ids: start = time.time() entry = LogEntry.fetch(self.env, log_id) if entry:
def expand_macro(self, formatter, name, content): args, kw = parse_args(content) prefix = args[0].strip() if args else None hideprefix = args and len(args) > 1 and args[1].strip() == 'hideprefix' minsize = _arg_as_int(kw.get('min', 1), 'min', min=1) minsize_group = max(minsize, 2) depth = _arg_as_int(kw.get('depth', -1), 'depth', min=-1) format = kw.get('format', '') def parse_list(name): return [ inc.strip() for inc in kw.get(name, '').split(':') if inc.strip() ] includes = parse_list('include') or ['*'] excludes = parse_list('exclude') wiki = formatter.wiki resource = formatter.resource if prefix and resource and resource.realm == 'wiki': prefix = wiki.resolve_relative_name(prefix, resource.id) start = prefix.count('/') if prefix else 0 if hideprefix: omitprefix = lambda page: page[len(prefix):] else: omitprefix = lambda page: page pages = sorted(page for page in wiki.get_pages(prefix) if (depth < 0 or depth >= page.count('/') - start) and 'WIKI_VIEW' in formatter.perm('wiki', page) and any( fnmatchcase(page, inc) for inc in includes) and not any( fnmatchcase(page, exc) for exc in excludes)) if format == 'compact': return tag( separated((tag.a(wiki.format_page_name(omitprefix(p)), href=formatter.href.wiki(p)) for p in pages), ', ')) # the function definitions for the different format styles # the different page split formats, each corresponding to its rendering def split_pages_group(pages): """Return a list of (path elements, page_name) pairs, where path elements correspond to the page name (without prefix) splitted at Camel Case word boundaries, numbers and '/'. """ page_paths = [] for page in pages: path = [ elt.strip() for elt in self.SPLIT_RE.split( self.NUM_SPLIT_RE.sub( r" \1 ", wiki.format_page_name(omitprefix(page), split=True))) ] page_paths.append(([elt for elt in path if elt], page)) return page_paths def split_pages_hierarchy(pages): """Return a list of (path elements, page_name) pairs, where path elements correspond to the page name (without prefix) splitted according to the '/' hierarchy. """ return [(wiki.format_page_name(omitprefix(page)).split("/"), page) for page in pages] # the different tree structures, each corresponding to its rendering def tree_group(entries): """Transform a flat list of entries into a tree structure. `entries` is a list of `(path_elements, page_name)` pairs Return a list organized in a tree structure, in which: - a leaf is a page name - a node is a `(key, nodes)` pairs, where: - `key` is the leftmost of the path elements, common to the grouped (path element, page_name) entries - `nodes` is a list of nodes or leaves """ def keyfn(args): elts, name = args return elts[0] if elts else '' groups = [] for key, grouper in groupby(entries, keyfn): # remove key from path_elements in grouped entries for further # grouping grouped_entries = [(path_elements[1:], page_name) for path_elements, page_name in grouper] if key and len(grouped_entries) >= minsize_group: subnodes = tree_group(sorted(grouped_entries)) if len(subnodes) == 1: subkey, subnodes = subnodes[0] node = (key + subkey, subnodes) groups.append(node) elif self.SPLIT_RE.match(key): for elt in subnodes: if isinstance(elt, tuple): subkey, subnodes = elt elt = (key + subkey, subnodes) groups.append(elt) else: node = (key, subnodes) groups.append(node) else: for path_elements, page_name in grouped_entries: groups.append(page_name) return groups def tree_hierarchy(entries): """Transform a flat list of entries into a tree structure. `entries` is a list of `(path_elements, page_name)` pairs Return a list organized in a tree structure, in which: - a leaf is a `(rest, page)` pair, where: - `rest` is the rest of the path to be shown - `page` is a page name - a node is a `(key, nodes, page)` pair, where: - `key` is the leftmost of the path elements, common to the grouped (path element, page_name) entries - `page` is a page name (if one exists for that node) - `nodes` is a list of nodes or leaves """ def keyfn(args): elts, name = args return elts[0] if elts else '' groups = [] for key, grouper in groupby(entries, keyfn): grouped_entries = [e for e in grouper] sub_entries = [e for e in grouped_entries if len(e[0]) > 1] key_entries = [e for e in grouped_entries if len(e[0]) == 1] key_entry = key_entries[0] if key_entries else None key_page = key_entry[1] if key_entries else None if key and len(sub_entries) >= minsize: # remove key from path_elements in grouped entries for # further grouping sub_entries = [(path_elements[1:], page) for path_elements, page in sub_entries] subnodes = tree_hierarchy(sorted(sub_entries)) node = (key, key_page, subnodes) groups.append(node) else: if key_entry: groups.append(key_entry) groups.extend(sub_entries) return groups # the different rendering formats def render_group(group): return tag.ul( tag.li( tag(tag.strong(elt[0].strip('/')), render_group(elt[1]) ) if isinstance(elt, tuple) else tag. a(wiki.format_page_name(omitprefix(elt)), href=formatter.href.wiki(elt))) for elt in group) def render_hierarchy(group): return tag.ul( tag.li( tag( tag.a(elt[0], href=formatter.href.wiki(elt[1]) ) if elt[1] else tag(elt[0]), render_hierarchy(elt[2])) if len(elt) == 3 else tag. a('/'.join(elt[0]), href=formatter.href.wiki(elt[1]))) for elt in group) transform = { 'group': lambda p: render_group(tree_group(split_pages_group(p))), 'hierarchy': lambda p: render_hierarchy(tree_hierarchy(split_pages_hierarchy(p)) ), }.get(format) if transform: titleindex = transform(pages) else: titleindex = tag.ul( tag.li( tag.a(wiki.format_page_name(omitprefix(page)), href=formatter.href.wiki(page))) for page in pages) return tag.div(titleindex, class_='titleindex')