def expand_macro(self, formatter, name, content): min_depth, max_depth = 1, 6 title = None inline = 0 if content: argv = [arg.strip() for arg in content.split(',')] if len(argv) > 0: depth = argv[0] if '-' in depth: min_depth, max_depth = [int(d) for d in depth.split('-', 1)] else: min_depth = max_depth = int(depth) if len(argv) > 1: title = argv[1].strip() if len(argv) > 2: inline = argv[2].strip().lower() == 'inline' # TODO: - integrate the rest of the OutlineFormatter directly here # - use formatter.wikidom instead of formatter.source out = 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) + outline if not inline: outline = tag.div(outline, class_='wiki-toc') return outline
def expand_macro(self, formatter, name, args): curpage = formatter.resource.id # scoped TOC (e.g. TranslateRu/Guide or 0.X/Guide ...) prefix = '' guideprefix = GUIDE_NAME + '/' data = { 'guide': GUIDE_NAME, } idx = curpage.find('/') if idx > 0: prefix = curpage[:idx + 1] if prefix.endswith(guideprefix): prefix = prefix[:len(prefix) - len(guideprefix)] 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 % data), class_=(not ws.has_page(prefix + ref % data) and 'missing')), class_=(prefix + ref % data == curpage and 'active')) for ref, title in self.TOC ]), class_='wiki-toc')
def display(self, toc, ul): for name, title, sub in toc: if sub == None: ul.append(tag.li( Markup(title), class_= (name == self.curpage) and "active" or None)) else: show_dots = not (name == None or sub) ul.append(tag.li( tag.h4(Markup(title), show_dots and "..." or None))) if len(sub) > 0: ul.append(self.display(sub, tag.ul())) return ul
def gentd(week_idx, day_info): day = day_info['date'] tt = day_info['milestones'] + day_info['tickets'] if len(tt) < 6: ttshow = tt ttall = [] else: ttshow = tt[:4] ttall = tt tdclass = [] if day == today: tdclass.append('today') if day.weekday() in (5, 6): tdclass.append('weekend') formatted_day = format_date(day, format='long', locale=locale) td = tag.td(class_=' '.join(tdclass), data_for_start_date=day.strftime(start_date_format), data_for_due_date=day.strftime(due_date_format), data_fdate=formatted_day) label = [] if day == today: label.append(tag.span(_("Today"), class_='today')) label.append( tag.span(unicode(day.day), class_=('day normal', 'day')[day == today])) td(tag.div(label)) if ttshow: td(tag.ul([genli(t) for t in ttshow])) if ttall: id = 'calendar-more-%s' % str(day) td( tag.a(_("%d more tickets...") % (len(ttall) - 4), href='#' + id, class_='show-all-list'), tag.div(tag.h4(formatted_day), tag.ul([genli(t) for t in ttall]), class_='ticketcalendar-popup-list', id=id, data_title=format_date(day, locale=locale, format='full'))) return td
def gentd(week_idx, day_info): day = day_info['date'] tt = day_info['milestones'] + day_info['tickets'] if len(tt) < 6: ttshow = tt ttall = [] else: ttshow = tt[:4] ttall = tt tdclass = [] if day == today: tdclass.append('today') if is_weekend(day, locale): tdclass.append('weekend') formatted_day = format_date(day, format='long', locale=locale) td = tag.td( class_=' '.join(tdclass), data_for_start_date=day.strftime(start_date_format), data_for_due_date=day.strftime(due_date_format), data_fdate=formatted_day) label = [] if day == today: label.append(tag.span(_("Today"), class_='today')) label.append(tag.span(unicode(day.day), class_=('day normal', 'day')[day == today])) td(tag.div(label)) if ttshow: td(tag.ul([genli(t) for t in ttshow])) if ttall: id = 'calendar-more-%s' % str(day) td(tag.a(_("%d more tickets...") % (len(ttall) - 4), href='#' + id, class_='show-all-list'), tag.div(tag.h4(formatted_day), tag.ul([genli(t) for t in ttall]), class_='ticketcalendar-popup-list', id=id, data_title=format_date(day, locale=locale, format='full'))) return td
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 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) + 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 expand_macro(self, formatter, name, args): curpage = formatter.resource.id # scoped TOC (e.g. TranslateRu/Guide or 0.X/Guide ...) prefix = '' guideprefix = GUIDE_NAME + '/' data = {'guide': GUIDE_NAME,} idx = curpage.find('/') if idx > 0: prefix = curpage[:idx+1] if prefix.endswith(guideprefix): prefix = prefix[:len(prefix)-len(guideprefix)] 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 % data), class_=(not ws.has_page(prefix+ref % data) and 'missing')), class_=(prefix+ref % data== curpage and 'active')) for ref, title in self.TOC]), class_='wiki-toc')
def _customize_View(self, stream): filter = Transformer('.//div [@id="banner"]') stream = stream | filter.wrap(self.css_banner_top2) buffer = StreamBuffer() stream = stream | Transformer('.//div [@id="banner"]').copy(buffer) \ .end().select('.//div [@id="top2"]') \ .after(tag.div(id_='top1')(buffer)) filter = Transformer('.//div [@id="mainnav"]') stream = stream | filter.wrap(self.css_banner_top4) buffer = StreamBuffer() stream = stream | Transformer('.//div [@id="mainnav"]').copy(buffer) \ .end().select('.//div [@id="top4"]') \ .after(tag.div(id_='top3')(buffer)) filter = Transformer('.//div [@id="top3"]') stream = stream | filter.after(tag.div(id_='right')(tag.p())) filter = Transformer('.//div [@id="right"]') stream = stream | filter. \ append(tag.div(class_='wiki-toc')(tag.h4(_('Table of Contents')))) # just for the menu / TOC filter = Transformer('.//div [@class="wiki-toc"]') if self.anchors and self.keylist: for key in self.keylist: stream = stream | filter.append( tag.a(key, href='#' + self.anchors.get(key), onclick="scrollup();") + tag.br()) filter = Transformer('.//div [@id="main"]') stream = stream | filter.wrap(self.css_left) return stream
def _customize_View(self, stream): filter = Transformer('.//div [@id="banner"]') stream = stream | filter.wrap(self.css_banner_top2) buffer = StreamBuffer() stream = stream | Transformer('.//div [@id="banner"]').copy(buffer).end().select('.//div [@id="top2"]').after( tag.div(id_="top1")(buffer) ) filter = Transformer('.//div [@id="mainnav"]') stream = stream | filter.wrap(self.css_banner_top4) buffer = StreamBuffer() stream = stream | Transformer('.//div [@id="mainnav"]').copy(buffer).end().select('.//div [@id="top4"]').after( tag.div(id_="top3")(buffer) ) filter = Transformer('.//div [@id="top3"]') stream = stream | filter.after(tag.div(id_="right")(tag.p())) filter = Transformer('.//div [@id="right"]') stream = stream | filter.append(tag.div(class_="wiki-toc")(tag.h4(_("Table of Contents")))) # just for the menu / TOC filter = Transformer('.//div [@class="wiki-toc"]') if self.anchors and self.keylist: for key in self.keylist: stream = stream | filter.append( tag.a(key, href="#" + self.anchors.get(key), onclick="scrollup();") + tag.br() ) filter = Transformer('.//div [@id="main"]') stream = stream | filter.wrap(self.css_left) return stream
def expand_macro(self, formatter, name, args): context = formatter.context resource = formatter.context.resource # Bail out if we are in a no-float zone if hasattr(formatter, 'properties') and \ 'macro_no_float' in formatter.properties: return '' current_page = resource.id # Split the args args, kw = parse_args(args) # Options inline = False pagenames = [] default_heading = 'Table of Contents' params = {'min_depth': 1, 'max_depth': 6} # Global options for arg in args: arg = arg.strip() if arg == 'inline': inline = True elif arg == 'noheading': default_heading = '' elif arg == 'notitle': params['min_depth'] = 2 # Skip page title elif (arg == 'titleindex') or (arg == 'sectionindex'): # sectionindex is a page-context sensitive titleindex if arg == 'sectionindex': params['section_index'] = True params['title_index'] = True default_heading = default_heading and 'Page Index' elif arg == 'nofloat': return '' elif arg != '': pagenames.append(arg) heading = kw.pop('heading', '') or default_heading if 'depth' in kw: params['max_depth'] = int(kw['depth']) # Has the user supplied a list of pages? if not pagenames: # Be sure to test section_index first as title_index is also true in this case if 'section_index' in params: # Use 'parent' of current page (level delimiter is /), if any toks = re.match('^(?P<parent>.*)/[^/]*$',current_page) if toks: pagenames.append(toks.group('parent')+'/') else: pagenames.append('*') elif 'title_index' in params: pagenames.append('*') # A marker for 'all' else: pagenames.append(current_page) params['root'] = '' params['min_depth'] = 2 # Skip page title # Check for wildcards and expand lists temp_pagenames = [] for pagename in pagenames: if 'section_index' in params: # / is considered an equivalent to * in sectionindex if pagename == '/': pagename = '*' if not pagename.endswith('*'): pagename += '*' if pagename.endswith('*'): temp_pagenames.extend(sorted( WikiSystem(self.env).get_pages(pagename[:-1]))) else: temp_pagenames.append(pagename) pagenames = temp_pagenames base = tag.div(class_=inline and 'wiki-toc-inline' or 'wiki-toc') ol = tag.ol() base.append([heading and tag.h4(heading), ol]) active = len(pagenames) > 1 for pagename in pagenames: page_resource = resource(id=pagename) if not 'WIKI_VIEW' in context.perm(page_resource): # Not access to the page, so should not be included continue if 'title_index' in params: self._render_title_index(formatter, ol, page_resource, active and pagename == current_page, params['min_depth'] < 2) else: self._render_page_outline(formatter, ol, page_resource, active, params) return base
def gen_calendar(self, tickets, query, month, width=None, nav=True): milestones = self._get_milestones() req = self.req locale = self._get_locale() first_week_day = self._get_first_week_day(locale) start_date_format = self.mod.start_date_format due_date_format = self.mod.due_date_format if not month: month = get_today(req.tz).replace(day=1) # init data today = get_today(req.tz) # generate calendar data weeks = self._get_month_calendar(month.year, month.month, first_week_day, locale) days = sorted(sum(weeks, [])) tickets = self._filter_tickets(days, tickets, req.tz) milestones = self._filter_milestones(days, milestones, req.tz) cal = [[{'date': day, 'tickets': tickets[day], 'milestones': milestones[day]} for day in week] for week in weeks] def genli(t): if isinstance(t, Milestone): return self._create_milestone_item(t) else: return self._create_ticket_item(t) def gentd(week_idx, day_info): day = day_info['date'] tt = day_info['milestones'] + day_info['tickets'] if len(tt) < 6: ttshow = tt ttall = [] else: ttshow = tt[:4] ttall = tt tdclass = [] if day == today: tdclass.append('today') if is_weekend(day, locale): tdclass.append('weekend') formatted_day = format_date(day, format='long', locale=locale) td = tag.td( class_=' '.join(tdclass), data_for_start_date=day.strftime(start_date_format), data_for_due_date=day.strftime(due_date_format), data_fdate=formatted_day) label = [] if day == today: label.append(tag.span(_("Today"), class_='today')) label.append(tag.span(unicode(day.day), class_=('day normal', 'day')[day == today])) td(tag.div(label)) if ttshow: td(tag.ul([genli(t) for t in ttshow])) if ttall: id = 'calendar-more-%s' % str(day) td(tag.a(_("%d more tickets...") % (len(ttall) - 4), href='#' + id, class_='show-all-list'), tag.div(tag.h4(formatted_day), tag.ul([genli(t) for t in ttall]), class_='ticketcalendar-popup-list', id=id, data_title=format_date(day, locale=locale, format='full'))) return td day_names = get_day_names(locale=locale, width='abbreviated') day_names = [day_names[(idx + first_week_day) % 7] for idx in xrange(7)] header = tag.div(class_='ticketcalendar-header') if nav: def nav_href(d): return self.get_box_href(query, d) def nav_pager(d): return tag.span( tag.a(u'\u25c4', href=nav_href(d - timedelta(days=1))), tag.a(_("Current month"), href=nav_href(get_today(req.tz))), tag.a(u'\u25ba', href=nav_href(d + timedelta(days=31))), class_='ticketcalendar-pager') def nav_macro(): macro = ( '[[TicketCalendar(type=box,month=%(month)s,' 'query=%(query)s,order=%(order)s%(extra)s)]]' % (dict(month=month.strftime('%Y-%m'), query=self.build_query_string(query.constraints), order=query.order, extra=query.desc and ',desc=1' or ''))) text = tag.input(type='text', readonly='readonly', size='80', value=macro, style='width:0;display:none') return tag.span(_("Macro"), text, class_='ticketcalendar-macro') header(tag.div(nav_macro(), nav_pager(month), class_='ticketcalendar-nav')) header(tag.h4(_("%(month_name)s, %(year)s", month_name=_get_month_name(month, locale), year=month.year))) calendar = tag.table( tag.thead(tag.tr(tag.th(name) for name in day_names)), tag.tbody([tag.tr([gentd(idx, d) for d in w]) for idx, w in enumerate(cal)]), class_='calendar') can_create = 'TICKET_CREATE' in req.perm ticket_box = tag.div( tag.h4(tag.span('', class_='tc-today-date')), tag.ul( tag.li(tag.a( tag_("New ticket with \"%(date)s\" as the start date", date=tag.span('', data='start-date')), data_href=req.href('newticket', [(self.mod.start_date_name, '')]), class_='newticket-start-date')), tag.li(tag.a( tag_("New ticket with \"%(date)s\" as the due date", date=tag.span('', data='due-date')), data_href=req.href('newticket', [(self.mod.due_date_name, '')]), class_='newticket-due-date'))), title=_("Create new ticket"), class_='ticketcalendar-newticket-box', style='display:none', data_writable=(None, 'writable')[can_create]) class_ = ('ticketcalendar', 'ticketcalendar ticketcalendar-can-create')[can_create] return tag.div(header, calendar, ticket_box, class_=class_, style=width and ('width: %s' % width) or None)
calendar = {} counttickets = {} currentDate = datetime.date.today() self.macroenv.tracenv.log.debug(repr(orderedtickets)) table = tag.table( class_="data pptableticketperday" , border = "1", style = 'width:auto;') # standard values mystyle_org = '' mytitle_org = '' myclass_org = '' # table header tr = tag.tr() tr(tag.th(tag.h4(self.rowtype))) # TODO: add today css class for segment in self.segments: mystyle = mystyle_org mytitle = mytitle_org myclass = myclass_org try: consideredDate = self.getDateOfSegment(segment) calendar[segment] = {} calendar[segment]['isocalendar'] = consideredDate.isocalendar() calendar[segment]['date'] = consideredDate subtitle = weekdays[calendar[segment]['isocalendar'][2]] + ', week '+str(calendar[segment]['isocalendar'][1]) if consideredDate == currentDate: myclass = 'today' # overwrite except Exception,e: self.macroenv.tracenv.log.error(str(e)+' '+segment)
def gen_calendar(self, tickets, query, month, width=None, nav=True): milestones = self._get_milestones() req = self.req locale = self._get_locale() first_week_day = self._get_first_week_day(locale) start_date_format = self.mod.start_date_format due_date_format = self.mod.due_date_format if not month: month = datetime.now(req.tz) month = datetime(month.year, month.month, 1).date() # init data today = datetime.now(req.tz).date() # generate calendar data weeks = self._get_month_calendar(month.year, month.month, first_week_day, locale) days = sorted(sum(weeks, [])) tickets = self._filter_tickets(days, tickets, req.tz) milestones = self._filter_milestones(days, milestones, req.tz) cal = [[{ 'date': day, 'tickets': tickets[day], 'milestones': milestones[day] } for day in week] for week in weeks] def genli(t): if isinstance(t, Milestone): return self._create_milestone_item(t) else: return self._create_ticket_item(t) def gentd(week_idx, day_info): day = day_info['date'] tt = day_info['milestones'] + day_info['tickets'] if len(tt) < 6: ttshow = tt ttall = [] else: ttshow = tt[:4] ttall = tt tdclass = [] if day == today: tdclass.append('today') if day.weekday() in (5, 6): tdclass.append('weekend') formatted_day = format_date(day, format='long', locale=locale) td = tag.td(class_=' '.join(tdclass), data_for_start_date=day.strftime(start_date_format), data_for_due_date=day.strftime(due_date_format), data_fdate=formatted_day) label = [] if day == today: label.append(tag.span(_("Today"), class_='today')) label.append( tag.span(unicode(day.day), class_=('day normal', 'day')[day == today])) td(tag.div(label)) if ttshow: td(tag.ul([genli(t) for t in ttshow])) if ttall: id = 'calendar-more-%s' % str(day) td( tag.a(_("%d more tickets...") % (len(ttall) - 4), href='#' + id, class_='show-all-list'), tag.div(tag.h4(formatted_day), tag.ul([genli(t) for t in ttall]), class_='ticketcalendar-popup-list', id=id, data_title=format_date(day, locale=locale, format='full'))) return td day_names = get_day_names(locale=locale, width='abbreviated') day_names = [ day_names[(idx + first_week_day) % 7] for idx in xrange(7) ] header = tag.div(class_='ticketcalendar-header') if nav: def nav_href(d): return self.get_box_href(query, d) def nav_pager(d): return tag.span(tag.a(u'\u25c4', href=nav_href(d - timedelta(days=1))), tag.a(_("Current month"), href=nav_href(date.today())), tag.a(u'\u25ba', href=nav_href(d + timedelta(days=31))), class_='ticketcalendar-pager') def nav_macro(): macro = ( '[[TicketCalendar(type=box,month=%(month)s,' 'query=%(query)s,order=%(order)s%(extra)s)]]' % (dict(month=month.strftime('%Y-%m'), query=self.build_query_string(query.constraints), order=query.order, extra=query.desc and ',desc=1' or ''))) text = tag.input(type='text', readonly='readonly', size='80', value=macro, style='width:0;display:none') return tag.span(_("Macro"), text, class_='ticketcalendar-macro') header( tag.div(nav_macro(), nav_pager(month), class_='ticketcalendar-nav')) header( tag.h4( _("%(month_name)s, %(year)s", month_name=_get_month_name(month, locale), year=month.year))) calendar = tag.table( tag.thead(tag.tr(tag.th(name) for name in day_names)), tag.tbody([ tag.tr([gentd(idx, d) for d in w]) for idx, w in enumerate(cal) ]), class_='calendar') can_create = 'TICKET_CREATE' in req.perm ticket_box = tag.div( tag.h4(tag.span('', class_='tc-today-date')), tag.ul( tag.li( tag.a(tag_( "New ticket with \"%(date)s\" as the start date", date=tag.span('', data='start-date')), data_href=req.href('newticket', [(self.mod.start_date_name, '')]), class_='newticket-start-date')), tag.li( tag.a(tag_("New ticket with \"%(date)s\" as the due date", date=tag.span('', data='due-date')), data_href=req.href('newticket', [(self.mod.due_date_name, '')]), class_='newticket-due-date'))), title=_("Create new ticket"), class_='ticketcalendar-newticket-box', style='display:none', data_writable=(None, 'writable')[can_create]) class_ = ('ticketcalendar', 'ticketcalendar ticketcalendar-can-create')[can_create] return tag.div(header, calendar, ticket_box, class_=class_, style=width and ('width: %s' % width) or None)
def expand_macro(self, formatter, name, content): args, kw = parse_args(content) req = formatter.req context = formatter.context # Prevent multiple inclusions - store a temp in req if hasattr(req, 'addcommentmacro'): raise TracError('\'AddComment\' macro cannot be included twice.') req.addcommentmacro = True # Prevent it being used outside of wiki page context resource = context.resource if not resource.realm == 'wiki': raise TracError('\'AddComment\' macro can only be used in Wiki pages.') # Setup info and defaults authname = req.authname page = WikiPage(self.env, resource) page_url = req.href.wiki(resource.id) wikipreview = req.args.get("preview", "") # Can this user add a comment to this page? appendonly = ('appendonly' in args) cancomment = False if page.readonly: if 'WIKI_ADMIN' in req.perm(resource): cancomment = True elif 'WIKI_MODIFY' in req.perm(resource): cancomment = True elif appendonly and 'WIKI_VIEW' in req.perm(resource): cancomment = True else: self.log.debug('Insufficient privileges for %s to AddComment to %s', req.authname, resource.id) # Get the data from the POST comment = req.args.get("addcomment", "") preview = req.args.get("previewaddcomment", "") cancel = req.args.get("canceladdcomment", "") submit = req.args.get("submitaddcomment", "") if not cancel and req.authname == 'anonymous': authname = req.args.get("authoraddcomment", authname) # Ensure [[AddComment]] is not present in comment, so that infinite # recursion does not occur. comment = to_unicode(re.sub('(^|[^!])(\[\[AddComment)', '\\1!\\2', comment)) the_preview = the_message = the_form = tag() # If we are submitting or previewing, inject comment as it should look if cancomment and comment and (preview or submit): heading = tag.h4("Comment by ", authname, " on ", to_unicode(time.strftime('%c', time.localtime())), id="commentpreview") if preview: the_preview = tag.div(heading, format_to_html(self.env, context, comment), class_="wikipage", id="preview") # Check the form_token form_ok = True if submit and req.args.get('__FORM_TOKEN','') != req.form_token: form_ok = False the_message = tag.div(tag.strong("ERROR: "), "AddComment received incorrect form token. " "Do you have cookies enabled?", class_="system-message") # When submitting, inject comment before macro if comment and submit and cancomment and form_ok: submitted = False newtext = "" for line in page.text.splitlines(): if line.find('[[AddComment') == 0: newtext += "==== Comment by %s on %s ====\n%s\n\n" % ( authname, to_unicode(time.strftime('%c', time.localtime())), comment) submitted = True newtext += line+"\n" if submitted: page.text = newtext # Let the wiki page manipulators have a look at the # submission. valid = True req.args.setdefault('comment', 'Comment added.') try: for manipulator in WikiModule(self.env).page_manipulators: for field, message in manipulator.validate_wiki_page(req, page): valid = False if field: the_message += tag.div(tag.strong("invalid field '%s': " % field), message, class_="system-message") else: the_message += tag.div(tag.strong("invalid: "), message, class_="system-message") # The TracSpamfilterPlugin does not generate messages, # but throws RejectContent. except TracError, s: valid = False the_message += tag.div(tag.strong("ERROR: "), s, class_="system-message") if valid: page.save(authname, req.args['comment'], req.environ['REMOTE_ADDR']) # We can't redirect from macro as it will raise RequestDone # which like other macro errors gets swallowed in the Formatter. # We need to re-raise it in a post_process_request instead. try: self.env.log.debug( "AddComment saved - redirecting to: %s" % page_url) req._outheaders = [] req.redirect(page_url) except RequestDone: req.addcomment_raise = True else: the_message = tag.div(tag.strong("ERROR: "), "[[AddComment]] " "macro call must be the only content on its line. " "Could not add comment.", class_="system-message")
def render(self, ticketset): return_div = tag.div(class_=self.cssclass+' projectplanrender' ) # check for missing parameters missingparameter = False if self.rows == [] or self.rows == None: return_div(tag.div('Missing parameter "rows": use a semicolon-separated list to input the "'+self.rowtype+'".', class_='ppwarning')) missingparameter = True if self.rowtype == None or str(self.rowtype).strip() == '': return_div(tag.div('Missing parameter "rowtype": specifies the ticket attribute that should be showed at the rows.', class_='ppwarning')) missingparameter = True if self.cols == [] or self.cols == None: return_div(tag.div('Missing parameter: use a semicolon-separated list to input the "cols".', class_='ppwarning')) missingparameter = True if self.coltype == None or str(self.coltype).strip() == '': return_div(tag.div('Missing parameter "coltype": specifies the ticket attribute that should be showed in the columns.', class_='ppwarning')) missingparameter = True if missingparameter: return return_div #ul = tag.ul() #for tid in ticketset.getIDSortedList(): #ticket = ticketset.getTicket(tid) #ul( tag.li(tid, " ",ticket.getfield('component') , " ", ticket.getfield('owner') )) #return_div(ul) def getstatistictitle( statusdict ): mytitle = '' mysum = 0 for status in statusdict: mytitle += "%s: %s\n" % (status, str(statusdict[status]) ) mysum += int(statusdict[status]) mytitle += "%s: %s" % ('number', mysum) return mytitle def setKV( myStruct, myKey, newValue ): ''' shortcut to set the values correctly used to reduce the code needed while using a list as key of a dict ''' myStruct[str(myKey)] = newValue def tableKeyPrettyPrint( mylist ) : ''' transform a list of keys to a user readable string in: ['a','b'] --> out: 'a|b' ''' return '|'.join(mylist) def tableKeyQueryParameter( parameter, mylist ) : ''' transform a list of keys to a Trac query string parameter (OR) in: x, ['a','b'] --> out: 'x=a&x=b' ''' return '&'.join([ "%s=%s" % (parameter, s) for s in mylist ]) chartheight=80 chartwidth=170 data = {} statistics = {} # init table data for row in self.rows : colstatistics = {} colkeys = {} for col in self.cols : # colkeys[col] = [] setKV( colkeys, col, [] ) # colstatistics[col] = {} setKV( colstatistics, col, {} ) # data[row] = colkeys setKV( data, row, colkeys ) # statistics[row] = colstatistics setKV( statistics, row, colstatistics ) for tid in ticketset.getIDSortedList(): ticket = ticketset.getTicket(tid) ticket_rowtype = ticket.getfield(self.rowtype) ticket_coltype = ticket.getfield(self.coltype) # determine the data cell where the ticket has to be added, keep in mind that rows and cols are list of lists for row in self.rows : for col in self.cols : if ticket_rowtype in row and ticket_coltype in col : data[str(row)][str(col)].append(ticket) # save tickets at precise values of row and col self.log_debug('row:%s col:%s append:%s' % (row,col,tid)) # if ticket_rowtype in self.rows and ticket_coltype in self.cols : # create HTML table table = tag.table( class_="data pptableticketperday" , border = "1", style = 'width:auto;') # create HTML table head thead = tag.thead() tr = tag.tr() tr( tag.th("%s vs %s" % (self.rowtype,self.coltype) ) ) for colkey in self.cols : tr( tag.th(tag.h4(tag.a( tableKeyPrettyPrint(colkey), href=self.macroenv.tracenv.href()+('/query?%s&order=%s' % ( tableKeyQueryParameter(self.coltype, colkey),self.rowtype)) )),title="%s is %s" % (self.coltype, tableKeyPrettyPrint(colkey) ) ) ) # first line with all colkeys if self.showsummarypiechart: tr( tag.th(tag.h4( "Ticket Overview" ) ) ) thead(tr) table(thead) # create HTML table body tbody = tag.tbody() counter=0 for rowkey in self.rows : # switch line color if counter % 2 == 1: class_ = 'odd' else: class_ = 'even' counter += 1 tr = tag.tr( class_=class_ ) # new line td = tag.td() # new cell td(tag.h5(tag.a( tableKeyPrettyPrint(rowkey), href=self.macroenv.tracenv.href()+('/query?%s&order=%s' % ( tableKeyQueryParameter( self.rowtype,rowkey),self.coltype)) )),title="%s is %s" % (self.rowtype, tableKeyPrettyPrint(rowkey) ) ) # first cell contains row key tr(td) for colkey in self.cols : td = tag.td() for ticket in data[str(rowkey)][str(colkey)] : td( tag.span(self.createTicketLink(ticket), class_ = 'ticket_inner' ), " " , mytitle="%s is %s and %s is %s" % (self.rowtype,rowkey,self.coltype,colkey) ) # mytitle might be used later by javascript if not statistics[str(rowkey)][str(colkey)].has_key( ticket.getstatus() ) : statistics[str(rowkey)][str(colkey)][ticket.getstatus()] = 0 statistics[str(rowkey)][str(colkey)][ticket.getstatus()] += 1 tr(td) # compute statistics rowstatistics = {} count = 0 for colkey in statistics[str(rowkey)] : for status in statistics[str(rowkey)][str(colkey)] : if not rowstatistics.has_key(status) : rowstatistics[status] = 0 try: rowstatistics[status] += statistics[str(rowkey)][str(colkey)][status] count += statistics[str(rowkey)][str(colkey)][status] except: pass if self.showsummarypiechart: tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', rowstatistics, '%s tickets' % (count,), height=chartheight )), class_='ppstatistics' , title=getstatistictitle(rowstatistics)) ) # Summary tbody(tr) table(tbody) # create HTML table foot if self.showsummarypiechart : fullstatistics = {} tfoot = tag.tfoot() tr = tag.tr() tr( tag.td(tag.h5('Ticket Overview') ) ) # create statistics for col fullcount = 0 for colkey in self.cols : colstatistics = {} colcount = 0 for rowkey in self.rows : for status in statistics[str(rowkey)][str(colkey)] : if not fullstatistics.has_key(status) : fullstatistics[status] = 0 if not colstatistics.has_key(status) : colstatistics[status] = 0 try: colstatistics[status] += statistics[str(rowkey)][str(colkey)][status] colcount += statistics[str(rowkey)][str(colkey)][status] fullstatistics[status] += statistics[str(rowkey)][str(colkey)][status] fullcount += statistics[str(rowkey)][str(colkey)][status] except: pass tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', colstatistics, '%s tickets' % (colcount,), height=chartheight)), title=getstatistictitle(colstatistics) )) # Col Summary tr(tag.td(tag.img(src=self.createGoogleChartFromDict('ColorForStatus', fullstatistics, '%s tickets' % (fullcount,), height=chartheight)), class_='ppstatistics', title=getstatistictitle(fullstatistics))) # Full Summary tfoot(tr) table(tfoot) return_div(table) return return_div
def expand_macro(self, formatter, name, args): context = formatter.context resource = formatter.context.resource # Bail out if we are in a no-float zone if hasattr(formatter, 'properties') and \ 'macro_no_float' in formatter.properties: return '' current_page = resource.id # Split the args args, kw = parse_args(args) # Options inline = False pagenames = [] default_heading = 'Table of Contents' params = {'min_depth': 1, 'max_depth': 6} # Global options for arg in args: arg = arg.strip() if arg == 'inline': inline = True elif arg == 'noheading': default_heading = '' elif arg == 'notitle': params['min_depth'] = 2 # Skip page title elif (arg == 'titleindex') or (arg == 'sectionindex'): # sectionindex is a page-context sensitive titleindex if arg == 'sectionindex': params['section_index'] = True params['title_index'] = True default_heading = default_heading and 'Page Index' elif arg == 'nofloat': return '' elif arg != '': pagenames.append(arg) heading = kw.pop('heading', '') or default_heading if 'depth' in kw: params['max_depth'] = int(kw['depth']) # Has the user supplied a list of pages? if not pagenames: # Be sure to test section_index first as title_index is also true in this case if 'section_index' in params: # Use 'parent' of current page (level delimiter is /), if any toks = re.match('^(?P<parent>.*)/[^/]*$', current_page) if toks: pagenames.append(toks.group('parent') + '/') else: pagenames.append('*') elif 'title_index' in params: pagenames.append('*') # A marker for 'all' else: pagenames.append(current_page) params['root'] = '' params['min_depth'] = 2 # Skip page title # Check for wildcards and expand lists temp_pagenames = [] for pagename in pagenames: if 'section_index' in params: # / is considered an equivalent to * in sectionindex if pagename == '/': pagename = '*' if not pagename.endswith('*'): pagename += '*' if pagename.endswith('*'): temp_pagenames.extend( sorted(WikiSystem(self.env).get_pages(pagename[:-1]))) else: temp_pagenames.append(pagename) pagenames = temp_pagenames base = tag.div(class_=inline and 'wiki-toc-inline' or 'wiki-toc') ol = tag.ol() base.append([heading and tag.h4(heading), ol]) active = len(pagenames) > 1 for pagename in pagenames: page_resource = resource(id=pagename) if not 'WIKI_VIEW' in context.perm(page_resource): # Not access to the page, so should not be included continue if 'title_index' in params: self._render_title_index(formatter, ol, page_resource, active and pagename == current_page, params['min_depth'] < 2) else: self._render_page_outline(formatter, ol, page_resource, active, params) return base
counttickets = {} currentDate = datetime.date.today() self.macroenv.tracenv.log.debug(repr(orderedtickets)) table = tag.table(class_="data pptableticketperday", border="1", style='width:auto;') # standard values mystyle_org = '' mytitle_org = '' myclass_org = '' # table header tr = tag.tr() tr(tag.th(tag.h4(self.rowtype))) # TODO: add today css class for segment in self.segments: mystyle = mystyle_org mytitle = mytitle_org myclass = myclass_org try: consideredDate = self.getDateOfSegment(segment) calendar[segment] = {} calendar[segment]['isocalendar'] = consideredDate.isocalendar() calendar[segment]['date'] = consideredDate subtitle = weekdays[calendar[segment]['isocalendar'] [2]] + ', week ' + str( calendar[segment]['isocalendar'][1]) if consideredDate == currentDate: myclass = 'today' # overwrite
def render(self, ticketset): return_div = tag.div(class_=self.cssclass + ' projectplanrender') # check for missing parameters missingparameter = False if self.rows == [] or self.rows == None: return_div( tag.div( 'Missing parameter "rows": use a semicolon-separated list to input the "' + self.rowtype + '".', class_='ppwarning')) missingparameter = True if self.rowtype == None or str(self.rowtype).strip() == '': return_div( tag.div( 'Missing parameter "rowtype": specifies the ticket attribute that should be showed at the rows.', class_='ppwarning')) missingparameter = True if self.cols == [] or self.cols == None: return_div( tag.div( 'Missing parameter: use a semicolon-separated list to input the "cols".', class_='ppwarning')) missingparameter = True if self.coltype == None or str(self.coltype).strip() == '': return_div( tag.div( 'Missing parameter "coltype": specifies the ticket attribute that should be showed in the columns.', class_='ppwarning')) missingparameter = True if missingparameter: return return_div #ul = tag.ul() #for tid in ticketset.getIDSortedList(): #ticket = ticketset.getTicket(tid) #ul( tag.li(tid, " ",ticket.getfield('component') , " ", ticket.getfield('owner') )) #return_div(ul) def getstatistictitle(statusdict): mytitle = '' mysum = 0 for status in statusdict: mytitle += "%s: %s\n" % (status, str(statusdict[status])) mysum += int(statusdict[status]) mytitle += "%s: %s" % ('number', mysum) return mytitle def setKV(myStruct, myKey, newValue): ''' shortcut to set the values correctly used to reduce the code needed while using a list as key of a dict ''' myStruct[str(myKey)] = newValue def tableKeyPrettyPrint(mylist): ''' transform a list of keys to a user readable string in: ['a','b'] --> out: 'a|b' ''' return '|'.join(mylist) def tableKeyQueryParameter(parameter, mylist): ''' transform a list of keys to a Trac query string parameter (OR) in: x, ['a','b'] --> out: 'x=a&x=b' ''' return '&'.join(["%s=%s" % (parameter, s) for s in mylist]) chartheight = 80 chartwidth = 170 data = {} statistics = {} # init table data for row in self.rows: colstatistics = {} colkeys = {} for col in self.cols: # colkeys[col] = [] setKV(colkeys, col, []) # colstatistics[col] = {} setKV(colstatistics, col, {}) # data[row] = colkeys setKV(data, row, colkeys) # statistics[row] = colstatistics setKV(statistics, row, colstatistics) for tid in ticketset.getIDSortedList(): ticket = ticketset.getTicket(tid) ticket_rowtype = ticket.getfield(self.rowtype) ticket_coltype = ticket.getfield(self.coltype) # determine the data cell where the ticket has to be added, keep in mind that rows and cols are list of lists for row in self.rows: for col in self.cols: if ticket_rowtype in row and ticket_coltype in col: data[str(row)][str(col)].append( ticket ) # save tickets at precise values of row and col self.log_debug('row:%s col:%s append:%s' % (row, col, tid)) # if ticket_rowtype in self.rows and ticket_coltype in self.cols : # create HTML table table = tag.table(class_="data pptableticketperday", border="1", style='width:auto;') # create HTML table head thead = tag.thead() tr = tag.tr() tr(tag.th("%s vs %s" % (self.rowtype, self.coltype))) for colkey in self.cols: tr( tag.th(tag.h4( tag.a(tableKeyPrettyPrint(colkey), href=self.macroenv.tracenv.href() + ('/query?%s&order=%s' % (tableKeyQueryParameter( self.coltype, colkey), self.rowtype)))), title="%s is %s" % (self.coltype, tableKeyPrettyPrint(colkey))) ) # first line with all colkeys if self.showsummarypiechart: tr(tag.th(tag.h4("Ticket Overview"))) thead(tr) table(thead) # create HTML table body tbody = tag.tbody() counter = 0 for rowkey in self.rows: # switch line color if counter % 2 == 1: class_ = 'odd' else: class_ = 'even' counter += 1 tr = tag.tr(class_=class_) # new line td = tag.td() # new cell td(tag.h5( tag.a(tableKeyPrettyPrint(rowkey), href=self.macroenv.tracenv.href() + ('/query?%s&order=%s' % (tableKeyQueryParameter( self.rowtype, rowkey), self.coltype)))), title="%s is %s" % (self.rowtype, tableKeyPrettyPrint(rowkey))) # first cell contains row key tr(td) for colkey in self.cols: td = tag.td() for ticket in data[str(rowkey)][str(colkey)]: td(tag.span(self.createTicketLink(ticket), class_='ticket_inner'), " ", mytitle="%s is %s and %s is %s" % (self.rowtype, rowkey, self.coltype, colkey)) # mytitle might be used later by javascript if not statistics[str(rowkey)][str(colkey)].has_key( ticket.getstatus()): statistics[str(rowkey)][str(colkey)][ ticket.getstatus()] = 0 statistics[str(rowkey)][str(colkey)][ ticket.getstatus()] += 1 tr(td) # compute statistics rowstatistics = {} count = 0 for colkey in statistics[str(rowkey)]: for status in statistics[str(rowkey)][str(colkey)]: if not rowstatistics.has_key(status): rowstatistics[status] = 0 try: rowstatistics[status] += statistics[str(rowkey)][str( colkey)][status] count += statistics[str(rowkey)][str(colkey)][status] except: pass if self.showsummarypiechart: tr( tag.td(tag.img(src=self.createGoogleChartFromDict( 'ColorForStatus', rowstatistics, '%s tickets' % (count, ), height=chartheight)), class_='ppstatistics', title=getstatistictitle(rowstatistics))) # Summary tbody(tr) table(tbody) # create HTML table foot if self.showsummarypiechart: fullstatistics = {} tfoot = tag.tfoot() tr = tag.tr() tr(tag.td(tag.h5('Ticket Overview'))) # create statistics for col fullcount = 0 for colkey in self.cols: colstatistics = {} colcount = 0 for rowkey in self.rows: for status in statistics[str(rowkey)][str(colkey)]: if not fullstatistics.has_key(status): fullstatistics[status] = 0 if not colstatistics.has_key(status): colstatistics[status] = 0 try: colstatistics[status] += statistics[str(rowkey)][ str(colkey)][status] colcount += statistics[str(rowkey)][str( colkey)][status] fullstatistics[status] += statistics[str(rowkey)][ str(colkey)][status] fullcount += statistics[str(rowkey)][str( colkey)][status] except: pass tr( tag.td( tag.img(src=self.createGoogleChartFromDict( 'ColorForStatus', colstatistics, '%s tickets' % (colcount, ), height=chartheight)), title=getstatistictitle(colstatistics))) # Col Summary tr( tag.td( tag.img(src=self.createGoogleChartFromDict( 'ColorForStatus', fullstatistics, '%s tickets' % (fullcount, ), height=chartheight)), class_='ppstatistics', title=getstatistictitle(fullstatistics))) # Full Summary tfoot(tr) table(tfoot) return_div(table) return return_div
def AddComment(macro, environ, data, *args, **kwargs): """Display an add comment form allowing users to post comments. This macro allows you to display an add comment form on the current page allowing users to post comments. The comments are added to the page's content itself. **Arguments:** //No Arguments// **Example(s):** {{{ <<AddComment>> }}} <<AddComment>> """ # Setup info and defaults parser = environ.parser request = environ.request page = data["page"] page_name = page["name"] page_text = page["text"] # Get the data from the POST comment = request.kwargs.get("comment", "") action = request.kwargs.get("action", "") author = request.kwargs.get("author", environ._user()) # Ensure <<AddComment>> is not present in comment, so that infinite # recursion does not occur. comment = re.sub("(^|[^!])(\<\<AddComment)", "\\1!\\2", comment) the_preview = None the_comment = None # If we are submitting or previewing, inject comment as it should look if action == "preview": the_preview = tag.div(tag.h1("Preview"), id="preview") the_preview += tag.div(parser.generate(comment, environ=(environ, data)), class_="article") # When submitting, inject comment before macro if comment and action == "save": new_text = "" comment_text = "\n==== Comment by %s on %s ====\n\n%s\n\n" % ( author, time.strftime('%c', time.localtime()), comment) for line in page_text.split("\n"): if line.find("<<AddComment") == 0: new_text += comment_text new_text += line + "\n" search = environ.search storage = environ.storage storage.reopen() search.update(environ) storage.save_text(page_name, new_text, author, "Comment added by %s" % author) search.update_page(environ.get_page(page_name), page_name, text=new_text) the_comment = tag.div(parser.generate(comment_text, environ=(environ, data)), class_="article") the_form = tag.form( tag.input(type="hidden", name="parent", value=page["node"]), tag.fieldset( tag.legend("Add Comment"), tag.p( tag.textarea( (not action in ("cancel", "save") and comment or ""), id="comment", name="comment", cols=80, rows=5 ), class_="text" ), tag.h4(tag.label("Your email or username:"******"author")), tag.p( tag.input(id="author", name="author", type="text", value=(not action in ("cancel", "save")) and author or "" ), class_="input" ), tag.p( tag.button("Preview", type="submit", name="action", value="preview"), tag.button("Save", type="submit", name="action", value="save"), tag.button("Cancel", type="submit", name="action", value="cancel"), class_="button" ), ), method="post", action="" ) return tag(the_preview, the_comment, the_form)
def AddComment(macro, environ, data, *args, **kwargs): """Display an add comment form allowing users to post comments. This macro allows you to display an add comment form on the current page allowing users to post comments. The comments are added to the page's content itself. **Arguments:** //No Arguments// **Example(s):** {{{ <<AddComment>> }}} <<AddComment>> """ # Setup info and defaults parser = environ.parser request = environ.request page = data["page"] page_name = page["name"] page_text = page["text"] # Get the data from the POST comment = request.kwargs.get("comment", "") action = request.kwargs.get("action", "") author = request.kwargs.get("author", environ._user()) # Ensure <<AddComment>> is not present in comment, so that infinite # recursion does not occur. comment = re.sub("(^|[^!])(\<\<AddComment)", "\\1!\\2", comment) the_preview = None the_comment = None # If we are submitting or previewing, inject comment as it should look if action == "preview": the_preview = tag.div(tag.h1("Preview"), id="preview") the_preview += tag.div(parser.generate(comment, environ=(environ, data)), class_="article") # When submitting, inject comment before macro if comment and action == "save": new_text = "" comment_text = "\n==== Comment by %s on %s ====\n\n%s\n\n" % ( author, time.strftime('%c', time.localtime()), comment) for line in page_text.split("\n"): if line.find("<<AddComment") == 0: new_text += comment_text new_text += line + "\n" search = environ.search storage = environ.storage storage.reopen() search.update(environ) storage.save_text(page_name, new_text, author, "Comment added by %s" % author) search.update_page(environ.get_page(page_name), page_name, text=new_text) the_comment = tag.div(parser.generate(comment_text, environ=(environ, data)), class_="article") the_form = tag.form( tag.input(type="hidden", name="parent", value=page["node"]), tag.fieldset( tag.legend("Add Comment"), tag.p(tag.textarea( (not action in ("cancel", "save") and comment or ""), id="comment", name="comment", cols=80, rows=5), class_="text"), tag.h4(tag.label("Your email or username:"******"author")), tag.p(tag.input(id="author", name="author", type="text", value=(not action in ("cancel", "save")) and author or ""), class_="input"), tag.p(tag.button("Preview", type="submit", name="action", value="preview"), tag.button("Save", type="submit", name="action", value="save"), tag.button("Cancel", type="submit", name="action", value="cancel"), class_="button"), ), method="post", action="") return tag(the_preview, the_comment, the_form)
def expand_macro(self, formatter, name, content): args, kw = parse_args(content) req = formatter.req context = formatter.context # Prevent multiple inclusions - store a temp in req if hasattr(req, 'addcommentmacro'): raise TracError('\'AddComment\' macro cannot be included twice.') req.addcommentmacro = True # Prevent it being used outside of wiki page context resource = context.resource if not resource.realm == 'wiki': raise TracError( '\'AddComment\' macro can only be used in Wiki pages.') # Setup info and defaults authname = req.authname page = WikiPage(self.env, resource) page_url = req.href.wiki(resource.id) wikipreview = req.args.get("preview", "") # Can this user add a comment to this page? appendonly = ('appendonly' in args) cancomment = False if page.readonly: if 'WIKI_ADMIN' in req.perm(resource): cancomment = True elif 'WIKI_MODIFY' in req.perm(resource): cancomment = True elif appendonly and 'WIKI_VIEW' in req.perm(resource): cancomment = True else: self.log.debug( 'Insufficient privileges for %s to AddComment to %s', req.authname, resource.id) # Get the data from the POST comment = req.args.get("addcomment", "") preview = req.args.get("previewaddcomment", "") cancel = req.args.get("canceladdcomment", "") submit = req.args.get("submitaddcomment", "") if not cancel and req.authname == 'anonymous': authname = req.args.get("authoraddcomment", authname) # Ensure [[AddComment]] is not present in comment, so that infinite # recursion does not occur. comment = to_unicode( re.sub('(^|[^!])(\[\[AddComment)', '\\1!\\2', comment)) the_preview = the_message = the_form = tag() # If we are submitting or previewing, inject comment as it should look if cancomment and comment and (preview or submit): heading = tag.h4("Comment by ", authname, " on ", to_unicode(time.strftime('%c', time.localtime())), id="commentpreview") if preview: the_preview = tag.div(heading, format_to_html(self.env, context, comment), class_="wikipage", id="preview") # Check the form_token form_ok = True if submit and req.args.get('__FORM_TOKEN', '') != req.form_token: form_ok = False the_message = tag.div(tag.strong("ERROR: "), "AddComment received incorrect form token. " "Do you have cookies enabled?", class_="system-message") # When submitting, inject comment before macro if comment and submit and cancomment and form_ok: submitted = False newtext = "" for line in page.text.splitlines(): if line.find('[[AddComment') == 0: newtext += "==== Comment by %s on %s ====\n%s\n\n" % ( authname, to_unicode(time.strftime('%c', time.localtime())), comment) submitted = True newtext += line + "\n" if submitted: page.text = newtext # Let the wiki page manipulators have a look at the # submission. valid = True req.args.setdefault('comment', 'Comment added.') try: for manipulator in WikiModule(self.env).page_manipulators: for field, message in manipulator.validate_wiki_page( req, page): valid = False if field: the_message += tag.div(tag.strong( "invalid field '%s': " % field), message, class_="system-message") else: the_message += tag.div(tag.strong("invalid: "), message, class_="system-message") # The TracSpamfilterPlugin does not generate messages, # but throws RejectContent. except TracError, s: valid = False the_message += tag.div(tag.strong("ERROR: "), s, class_="system-message") if valid: page.save(authname, req.args['comment'], req.environ['REMOTE_ADDR']) # We can't redirect from macro as it will raise RequestDone # which like other macro errors gets swallowed in the Formatter. # We need to re-raise it in a post_process_request instead. try: self.env.log.debug( "AddComment saved - redirecting to: %s" % page_url) req._outheaders = [] req.redirect(page_url) except RequestDone: req.addcomment_raise = True else: the_message = tag.div( tag.strong("ERROR: "), "[[AddComment]] " "macro call must be the only content on its line. " "Could not add comment.", class_="system-message")