def filter_stream(self, req, method, filename, stream, data): # check preconditions if filename != 'ticket.html': return stream transformer = Transformer() # build 'Hide these fields' Area hide_names = req.session.get('hidefieldchanges', []) hide_fields = [] for field in data['fields']: name = field['name'] checkbox = name in hide_names \ and tag.input(type='checkbox', checked=True, name=name) \ or tag.input(type='checkbox', name=name) hide_fields.append(tag.label(checkbox, field['label'])) hide_fields.append(tag.br) hide_fields.append(tag.input(name='submit', type='submit', value='Hide these fields')) transformer = transformer \ .select('//div[@id="changelog"]') \ .before(tag.form(tag.input(value='hide changes', id='hidechangesbutton', type='button', style_='float: right;'), tag.div(hide_fields, style='display: none', id='hidefields'), action='#', class_='inlinebuttons hidechanges')).end() # build 'show all changes' button # showallbutton = tag.input(value='show all', name='showall', class_='showallbutton', type='submit', style_='float: right;') # showallbutton = tag.form(showallbutton, action='#', method='get', class_='inlinebuttons hidechanges') # transformer = transformer.select('//div[@id="changelog"]').before(showallbutton).end() # build 'hide customfield' buttons hidebutton = tag.input(value='hide', name="hide", class_='hidebutton', style_='display: none', type='submit') hidebutton = tag.form(hidebutton, action='#', method='get', class_='inlinebuttons hidefieldchanges') transformer = transformer \ .select('//div[@id="changelog"]/div[@class="change"]/ul[@class="changes"]/li') \ .prepend(hidebutton).end() # return filtered stream return stream | transformer
def filter_stream(self, req, method, filename, stream, data): # Add delete buttons to the ticket form ticket = data.get("ticket") if filename == "ticket.html" and "TICKET_ADMIN" in req.perm(ticket.resource): # Add Delete button to ticket description if data["ticket"].values["description"]: # Reply button and associated elements are present filter = Transformer("//div[@class='description']//div[@class='inlinebuttons']") stream |= filter.append( tag.input(type="submit", name="delete", title="Delete this ticket", value="Delete") ) else: # Reply button and associated elements not present filter = Transformer("//div[@class='description']/h3") stream |= filter.after( tag.form( tag.div( tag.input(type="submit", name="delete", title="Delete this ticket", value="Delete"), class_="inlinebuttons", ), name="addreply", method="get", action="#comment", ) ) # Add Delete buttons to ticket comments stream |= Transformer("//div[@id='changelog']//div[@class='inlinebuttons']").append( tag.input(type="submit", name="delete", title="Delete this comment", value="Delete") ) return stream
def filter_stream(self, req, method, filename, stream, data): if filename != 'report_view.html': return stream page_name = 'report:%s' % data['context'].resource.id page_label = data['title'] page = WikiPage(self.env, page_name) if 'WIKI_MODIFY' not in req.perm(page.resource): return stream text = '= Snapshot of [%s %s]: =\n' % (page_name, page_label) text += '{{{#!QueryResults\n' cols = [header['col'] for header in data.get('header_groups', [[]])[0] if not header['hidden']] cols_work = [t for t in cols] # copy if 'ticket' in cols_work: cols_work[cols_work.index('ticket')] = 'id' # replace 'ticket' to 'id' text += '||= href =||= %s\n' % ' =||= '.join(cols_work) for groupindex, row_group in data.get('row_groups', []): text += '|| group: %s\n' % groupindex for row in row_group: row = row['cell_groups'][0] ticket = {} for value in row: ticket[value['header']['col']] = value['value'] ticket['href'] = get_resource_url(self.env, Resource('ticket', ticket.get('ticket', 0)), self.env.href) text += '|| %s || %s\n' % (ticket['href'], ' || '.join([self.formatter(col, ticket[col]) for col in cols])) text += '}}}' div = tag.div(tag.input(value='Save as wiki:', type='submit'), tag.input(name='action', value='edit', type='hidden'), tag.input(name='text', value=text, type='hidden'), tag.input(name='page', value=page_name)) return stream | Transformer('//div[@id="content"]/div[@class="buttons"]') \ .append(tag.form(div, action=get_resource_url(self.env, Resource('wiki'), self.env.href)))
def filter_stream(self, req, method, filename, stream, data): if filename != 'query.html': return stream query_string = 'query:' + '&'.join(['%s=%s' % (key, '|'.join([cond for cond in values])) for constraint in data['query'].constraints for key, values in constraint.items()]) page_name = 'report_resource' in data and \ 'report:%s' % data['report_resource'].id or query_string if 'page_name' in req.args: page_name = req.args['page_name'] query_string += '&page_name=%s' % page_name page = WikiPage(self.env, page_name) if 'WIKI_MODIFY' not in req.perm(page.resource): return stream cols = [header['name'] for header in data['headers']] text = '= Snapshot of [%s the query]: =\n' % query_string text += '{{{#!QueryResults(group=%s) \n' % data['query'].group text += '||= href =||= %s\n' % ' =||= '.join(cols) for (group_name, tickets) in data['groups']: text += '|| group: %s\n' % group_name for ticket in tickets: text += '|| %s || %s\n' % (ticket['href'], ' || '.join([self.formatter(ticket[col]) for col in cols])) text += '}}}' div = tag.div(tag.input(value='Save as wiki:', type='submit'), tag.input(name='action', value='edit', type='hidden'), tag.input(name='text', value=text, type='hidden'), tag.input(name='page', value=page_name)) return stream | Transformer('//div[@id="content"]/div[@class="buttons"]') \ .append(tag.form(div, action=get_resource_url(self.env, Resource('wiki'), self.env.href)))
def filter_stream(self, req, method, filename, stream, data): # Get path if filename == 'browser.html': # self.req_han = SupoSERequestHandler() path = data.get('created_path') repo = self.env.get_repository(authname=req.authname) node = get_existing_node(req, repo, path, repo.youngest_rev) file = "" if node: if node.isfile: file = posixpath.basename(path) path = posixpath.dirname(path) #raise Exception( path ) filter = Transformer('//div[@id="jumprev"]') search = tag.div( tag.form( # tag.div( "Repository search" ), tag.input( type = "text", id = "suquery", name = "q", size = 13, value = ""), tag.input( type = "hidden", id = "suquerypath", name = "p", size = 13, value = path), tag.input( type = "hidden", id = "suqueryfile", name = "f", size = 13, value = file), tag.input( type = "submit", value="Repo Search"), action=req.href.reposearch(), method="get", id="reposearch" ) ) return stream | filter.after(search) return stream
def _clone_form(self, req, ticket, data): fields = {} for f in data.get("fields", []): name = f["name"] if name == "summary": fields["summary"] = _("%(summary)s (cloned)", summary=ticket["summary"]) elif name == "description": fields["description"] = _( "Cloned from #%(id)s:\n----\n%(description)s", id=ticket.id, description=ticket["description"] ) else: fields[name] = ticket[name] return tag.form( tag.div( tag.input( type="submit", name="clone", value=captioned_button(req, "+#", _("Clone")), title=_("Create a copy of this ticket"), ), [tag.input(type="hidden", name="field_" + n, value=v) for n, v in fields.iteritems()], tag.input(type="hidden", name="preview", value=""), class_="inlinebuttons", ), method="post", action=req.href.newticket(), )
class Aggregator(Component): implements(ITemplateStreamFilter, IRequestFilter) # IRequestFilter methods def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type): if not 'aggregate' in req.args \ or not data \ or not 'ticket' in data \ or not 'changes' in data: return template, data, content_type ticket = data['ticket'] if not 'TICKET_MODIFY' in req.perm(ticket.resource): return template, data, content_type cnum = int(req.args['aggregate']) changes = iter(data['changes']) for change in changes: if 'cnum' in change and change['cnum'] == cnum: self._aggregate(ticket.id, change, changes.next()) req.redirect(req.href.ticket(ticket.id) + '#comment:%d' % cnum) return template, data, content_type # ITemplateStreamFilter methods def filter_stream(self, req, method, filename, stream, data): if filename != 'ticket.html': return stream if 'cnum_edit' in req.args: # comment editing return stream ticket = data.get('ticket') if not 'TICKET_MODIFY' in req.perm(ticket.resource): return stream transformer = Transformer() if data.has_key('changes'): changes = data['changes'] # 前のコメントと, field の重複がなく, authorが一致していて, 時間が離れていない場合, Aggregateボタンを出す aggregatable = set() last = {'date': datetime.now(), 'fields': {}, 'author': None} for change in changes: try: delta = change['date'].replace(tzinfo=None) - last['date'].replace(tzinfo=None) if last['author'] == change['author'] \ and len(set(last['fields'].keys()) & set(change['fields'].keys())) == 0 \ and delta.days == 0 and delta.seconds <= 3600: aggregatable.add(last['cnum']) except KeyError, e: pass except AttributeError, e: pass last = change self.log.debug('aggregatable: %s' % aggregatable) # Build transformer for cnum in aggregatable: transformer = transformer \ .select('//div[@id="changelog"]/div[@id="trac-change-%s"]/h3[@class="change"])' % cnum) \ .after(tag.form(tag.input(type='hidden', name='aggregate', value=cnum), tag.div(tag.input(type='submit', value='Aggregate', title="to next"), class_='inlinebuttons'))) \ .end()
def get_navigation_items(self, req): if req.authname and req.authname != 'anonymous': # Use the same names as LoginModule to avoid duplicates. yield ('metanav', 'login', _('logged in as %(user)s', user=req.authname)) logout_href = req.href('%s/logout' % self.auth_path_prefix) from pkg_resources import parse_version if parse_version(trac.__version__) < parse_version('1.0.2'): yield ('metanav', 'logout', tag.a(_('Logout'), logout_href)) else: yield ('metanav', 'logout', tag.form(tag.div( tag.button(_('Logout'), name='logout', type='submit')), action=logout_href, method='post', id='logout', class_='trac-logout')) else: text = _('GitHub Login') if self.fontawesome_url: add_script(req, self.fontawesome_url) text = tag(tag.i(class_='fab fa-github-alt'), ' ', text) yield ('metanav', 'github_login', tag.a(text, href=req.href('%s/login' % self.auth_path_prefix)))
def filter_stream(self, req, method, filename, stream, data): if filename != 'query.html': return stream query_string = 'query:' + '&'.join([ '%s=%s' % (key, '|'.join([cond for cond in values])) for constraint in data['query'].constraints for key, values in constraint.items() ]) page_name = 'report_resource' in data and \ 'report:%s' % data['report_resource'].id or query_string if 'page_name' in req.args: page_name = req.args['page_name'] query_string += '&page_name=%s' % page_name page = WikiPage(self.env, page_name) if 'WIKI_MODIFY' not in req.perm(page.resource): return stream cols = [header['name'] for header in data['headers']] text = '= Snapshot of [%s the query]: =\n' % query_string text += '{{{#!QueryResults(group=%s) \n' % data['query'].group text += '||= href =||= %s\n' % ' =||= '.join(cols) for (group_name, tickets) in data['groups']: text += '|| group: %s\n' % group_name for ticket in tickets: text += '|| %s || %s\n' % (ticket['href'], ' || '.join( [self.formatter(ticket[col]) for col in cols])) text += '}}}' div = tag.div(tag.input(value='Save as wiki:', type='submit'), tag.input(name='action', value='edit', type='hidden'), tag.input(name='text', value=text, type='hidden'), tag.input(name='page', value=page_name)) return stream | Transformer('//div[@id="content"]/div[@class="buttons"]') \ .append(tag.form(div, action=get_resource_url(self.env, Resource('wiki'), self.env.href)))
def _clone_form(self, req, ticket, data): fields = {} for f in data.get('fields', []): name = f['name'] if name == 'summary': fields['summary'] = _("%(summary)s (cloned)", summary=ticket['summary']) elif name == 'description': fields['description'] = \ _("Cloned from #%(id)s:\n----\n%(description)s", id=ticket.id, description=ticket['description']) else: fields[name] = ticket[name] return tag.form(tag.div(tag.input( type="submit", name="clone", value=captioned_button(req, '+#', _("Clone")), title=_("Create a copy of this ticket")), [ tag.input(type="hidden", name='field_' + n, value=v) for n, v in fields.iteritems() ], tag.input(type="hidden", name='preview', value=''), class_="inlinebuttons"), method="post", action=req.href.newticket())
def filter_stream(self, req, method, filename, stream, data): # Add delete buttons to the ticket form ticket = data.get('ticket') if filename == 'ticket.html' and 'TICKET_ADMIN' in req.perm(ticket.resource): # Add Delete button to ticket description if data['ticket'].values['description']: # Reply button and associated elements are present filter = Transformer("//div[@class='description']//div[@class='inlinebuttons']") stream |= filter.append(tag.input(type='submit', name='delete', title="Delete this ticket", value='Delete')) else: # Reply button and associated elements not present filter = Transformer("//div[@class='description']/h3") stream |= filter.after( \ tag.form(tag.div(tag.input(type='submit', name='delete', title="Delete this ticket", value='Delete'), class_='inlinebuttons' ), name='addreply', method='get', action='#comment') ) # Add Delete buttons to ticket comments stream |= Transformer("//div[@id='changelog']//div[@class='inlinebuttons']") \ .append(tag.input(type='submit', name='delete', title="Delete this comment", value='Delete')) return stream
def delete_ticket(): return tag.form( tag.div( tag.input(type='hidden', name='action', value='delete'), tag.input(type='submit', value=_('Delete'), title=_('Delete ticket')), class_='inlinebuttons'), action='#', method='get')
def delete_ticket(): return tag.form(tag.div(tag.input(type='hidden', name='action', value='delete'), tag.input(type='submit', value=_('Delete'), title=_('Delete ticket')), class_='inlinebuttons'), action='#', method='get')
def delete_ticket(): return tag.form( tag.div( tag.input(type='hidden', name='action', value='delete'), tag.input(type='submit', value=captioned_button(req, u'–', # 'EN DASH' _("Delete")), title=_('Delete ticket'), class_="trac-delete"), class_="inlinebuttons"), action='#', method='get')
def filter_stream(self, req, method, filename, stream, data): # check preconditions if filename != 'ticket.html': return stream transformer = Transformer() # build 'Hide these fields' Area hide_names = req.session.get('hidefieldchanges', []) hide_fields = [] for field in data['fields']: name = field['name'] checkbox = name in hide_names \ and tag.input(type='checkbox', checked=True, name=name) \ or tag.input(type='checkbox', name=name) hide_fields.append(tag.label(checkbox, field['label'])) hide_fields.append(tag.br) hide_fields.append( tag.input(name='submit', type='submit', value='Hide these fields')) transformer = transformer \ .select('//div[@id="changelog"]') \ .before(tag.form(tag.input(value='hide changes', id='hidechangesbutton', type='button', style_='float: right;'), tag.div(hide_fields, style='display: none', id='hidefields'), action='#', class_='inlinebuttons hidechanges')).end() # build 'show all changes' button # showallbutton = tag.input(value='show all', name='showall', class_='showallbutton', type='submit', style_='float: right;') # showallbutton = tag.form(showallbutton, action='#', method='get', class_='inlinebuttons hidechanges') # transformer = transformer.select('//div[@id="changelog"]').before(showallbutton).end() # build 'hide customfield' buttons hidebutton = tag.input(value='hide', name="hide", class_='hidebutton', style_='display: none', type='submit') hidebutton = tag.form(hidebutton, action='#', method='get', class_='inlinebuttons hidefieldchanges') transformer = transformer \ .select('//div[@id="changelog"]/div[@class="change"]/ul[@class="changes"]/li') \ .prepend(hidebutton).end() # return filtered stream return stream | transformer
def _clone_form(self, req, ticket, data): fields = self.ticket_cloner.build_clone_form(req, ticket, data) return tag.form( tag.div( tag.input(type="submit", name="clone", value=_("Clone"), title=_("Create a copy of this ticket")), [tag.input(type="hidden", name='field_' + n, value=v) for n, v in fields.iteritems()], tag.input(type="hidden", name='preview', value=''), class_="inlinebuttons"), method="post", action=req.href.newticket())
def _ccme_form(self, req, ticket, data): # pylint: disable=no-self-use return tag.form(tag.div(tag.input( type="submit", name="ccme", value=captioned_button(req, u'\u2709', _("Cc Me!")), title=_("Add/remove yourself to/from the Cc list")), tag.input(type="hidden", name='ticket', value=ticket.id), class_="inlinebuttons"), method="post", action=req.href('/ccme'))
def get_navigation_items(self, req): if req.authname and req.authname != 'anonymous': yield ('metanav', 'login', _('logged in as %(user)s', user=req.authname)) yield ('metanav', 'logout', tag.form(tag.div(tag.button(_('Logout'), name='logout', type='submit')), action=req.href.logout(), method='post', id='logout', class_='trac-logout')) else: yield ('metanav', 'login', tag.a(_('Login'), href=req.href.login()))
def get_navigation_items(self, req): if req.authname and req.authname != 'anonymous': 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')), action=req.href.logout(), method='post', id='logout', class_='trac-logout')) else: yield ('metanav', 'login', tag.a(_("Login"), href=req.href.login()))
def delete_comment(): for event in buffer: cnum = event[1][1].get('id')[12:] return tag.form( tag.div( tag.input(type='hidden', name='action', value='delete-comment'), tag.input(type='hidden', name='cnum', value=cnum), tag.input(type='submit', value=_('Delete'), title=_('Delete comment %(num)s', num=cnum)), class_='inlinebuttons'), action='#', method='get')
def _reminder_add_form(self, req): if 'TICKET_REMINDER_MODIFY' not in req.perm and 'TICKET_ADMIN' not in req.perm: return None return \ tag.form( tag.div( tag.input(type="hidden", name="action", value="addreminder"), tag.input(type="submit", value="Add reminder"), ), method="get", action="", id="addreminder", )
def _logout_form(href, **kwargs): '''Return "Logout" "link" This version returns a form — styled to look like a link — as used by trac >= 1.0.2 (for CSRF protection.) Unfortunately, this does not render nicely in older tracs, since ``trac.css`` does not include the proper styling for ``form.trac-logout``. ''' fields = [tag.button(_('Logout'), name='logout', type='submit')] for name, value in kwargs.items(): fields.append(tag.input(type='hidden', name=name, value=value)) return tag.form(tag.div(*fields), action=href('logout'), id='logout', class_='trac-logout')
def _reminder_delete_form(self, req, reminder_id): if 'TICKET_REMINDER_MODIFY' not in req.perm and 'TICKET_ADMIN' not in req.perm: return None return \ tag.form( tag.div( tag.input(type="hidden", name="action", value="deletereminder"), tag.input(type="hidden", name="reminder", value=reminder_id), tag.input(type="submit", value="Delete"), class_="inlinebuttons", ), method="get", action="", )
def delete_comment(): for event in buffer: cnum, cdate = event[1][1].get('id')[12:].split('-', 1) return tag.form( tag.div( tag.input(type='hidden', name='action', value='delete-comment'), tag.input(type='hidden', name='cnum', value=cnum), tag.input(type='hidden', name='cdate', value=cdate), tag.input(type='submit', value=captioned_button(req, u'–', # 'EN DASH' _("Delete")), title=_('Delete comment %(num)s', num=cnum), class_="trac-delete"), class_="inlinebuttons"), action='#', method='get')
def delete_comment(): for event in buffer: cnum = event[1][1].get('id')[12:] return tag.form(tag.div(tag.input(type='hidden', name='action', value='delete-comment'), tag.input(type='hidden', name='cnum', value=cnum), tag.input(type='submit', value=_('Delete'), title=_( 'Delete comment %(num)s', num=cnum)), class_='inlinebuttons'), action='#', method='get')
def filter_stream(self, req, method, filename, stream, data): if req.path_info.startswith('/browser') and not data.get('tortoise-svn-message'): # add a hidden dialog div for the tortoisve svn message message = tag.p("TortoiseSVN is a Windows explorer client you can use to browse your Subversion repository.", tag.p("If you have not installed TortoiseSVN, you can download it now from the ", tag.a("TortoiseSVN website.", href="http://tortoisesvn.net/downloads.html", target="_blank" ), ), tag.p("If you have installed TortoiseSVN, please select continue.", ), tag.p("If your local network requires a proxy to access the Internet, note that ", tag.a("TortoiseSVN has proxy settings ", href="http://tortoisesvn.net/docs/nightly/TortoiseSVN_en/tsvn-dug-settings.html#tsvn-dug-settings-network" ), "which are configured separately to your normal Windows browser proxy.", class_="info-light" ), tag.p("This message will not appear again if you click continue.", class_="info-light" ), ) form = tag.form( tag.div( tag.input( type="hidden", name="__FORM_TOKEN", value=req.form_token ), ), tag.input( name="tortoise-svn-message", value="True", ), id_="tortoise-svn-message-form", class_="hidden" ) stream = stream | Transformer("//*[@id='dirlist']").after(tag.div(message, form, id_='tortoise-svn-message-dialog', class_='hidden' ) ) return stream
def _clone_form(self, req, ticket, data): fields = self.ticket_cloner.build_clone_form(req, ticket, data) action = self.ticket_clone_form_action or req.href.newticket() method = self.ticket_clone_form_method if method == "GET": field_name_fn = lambda name: name else: field_name_fn = lambda name: "field_%s" % name return tag.form( tag.div( tag.input(type="submit", name="clone", value=_("Clone"), title=_("Create a copy of this ticket")), [tag.input(type="hidden", name=field_name_fn(n), value=v) for n, v in fields.iteritems()], tag.input(type="hidden", name='preview', value=''), class_="inlinebuttons"), method=method, action=action)
def _create_button(self, b, req, ticket, data): # Text for button label=self.config.get('ticket-create-buttons','%s.label' % b) title=self.config.get('ticket-create-buttons','%s.title' % b) # Field values for new ticket fields = {} # Values inherited from the current ticket # No setting: all, blank setting: none, Otherwise: the fields listed inherit=self.config.getlist('ticket-create-buttons', '%s.inherit' % b, default=data.keys()) for f in inherit: fields[f]=ticket[f] # Fields that link the new ticket to the current ticket # Missing or empty, no links. link=self.config.getlist('ticket-create-buttons','%s.link' % b, default=[]) for l in link: to, fr = l.split(':') if fr == 'id': fields[to] = ticket.id else: fields[to]=ticket[fr] # Specific value assignments. E.g., a button could always create a test set=self.config.getlist('ticket-create-buttons','%s.set' % b, default=[]) for s in set: n, v = s.split(':') fields[n]=v # Build the form with the values set up above. return tag.form( tag.div( tag.input(type="submit", name="create_"+b, value=label, title=title), # With name='field_'+n here the field prefilled for post but not for get [tag.input(type="hidden", name=n, value=v) for n, v in fields.items()], class_="inlinebuttons"), # With "post" here instead of "get" the ticket is previewed and # we get a warning about the missing summary. method="get", action=req.href.newticket())
def _clone_form(self, req, ticket, data): fields = {} for f in data.get('fields', []): name = f['name'] if name == 'summary': fields['summary'] = ticket['summary'] + u" (複製)" elif name == 'description': fields['description'] = u"次のチケットの複製: #%s: \n----\n%s" % \ (ticket.id, ticket['description']) else: fields[name] = ticket[name] return tag.form( tag.div( tag.input(type="submit", name="clone", value=u"複製", title=u"このチケットの複製を作成"), [tag.input(type="hidden", name='field_'+n, value=v) for n, v in fields.items()], tag.input(type="hidden", name='preview', value=''), class_="inlinebuttons"), method="post", action=req.href.newticket())
def get_navigation_items(self, req): if req.authname and req.authname != 'anonymous': # Use the same names as LoginModule to avoid duplicates. yield ('metanav', 'login', _('logged in as %(user)s', user=req.authname)) from pkg_resources import parse_version if parse_version(trac.__version__) < parse_version('1.0.2'): yield ('metanav', 'logout', tag.a(_('Logout'), href=req.href.github('logout'))) else: yield ('metanav', 'logout', tag.form(tag.div(tag.button(_('Logout'), name='logout', type='submit')), action=req.href.github('logout'), method='post', id='logout', class_='trac-logout')) else: # Use a different name from LoginModule to allow both in parallel. yield ('metanav', 'github_login', tag.a(_('GitHub Login'), href=req.href.github('login')))
def _generate_attachmentflags_fieldset(self, readonly=True, current_flags=None, form=False): fields = Fragment() for flag in self.known_flags: flagid = 'flag_' + flag if current_flags and flag in current_flags: date = datetime.datetime.fromtimestamp( current_flags[flag]["updated_on"], utc) text = tag.span( tag.strong(flag), " set by ", tag.em(current_flags[flag]["updated_by"]), ", ", tag.span(pretty_timedelta(date), title=format_datetime(date)), " ago") if readonly == True: fields += tag.input(text, \ type='checkbox', id=flagid, \ name=flagid, checked="checked", disabled="true") + tag.br() else: fields += tag.input(text, \ type='checkbox', id=flagid, \ name=flagid, checked="checked") + tag.br() else: if readonly == True: fields += tag.input(flag, \ type='checkbox', id=flagid, \ name=flagid, disabled="true") + tag.br() else: fields += tag.input(flag, \ type='checkbox', id=flagid, \ name=flagid) + tag.br() if form and not readonly: return tag.form(tag.fieldset( tag.legend("Attachment Flags") + fields, tag.input(type="hidden", name="action", value="update_flags"), tag.input(type="submit", value="Update flags")), method="POST") return tag.fieldset(tag.legend("Attachment Flags") + fields)
def _contruct_buttons(self, req, ticket): # Always pass these fields default_child_fields = ( tag.input(type="hidden", name="parent", value=str(ticket.id)), ) #Pass extra fields defined in inherit parameter of parent inherited_child_fields = [ tag.input(type="hidden",name="%s"%field,value=ticket[field]) for field in self.config.getlist('childtickets','parent.%s.inherit' % ticket['type']) ] # If child types are restricted then create a set of buttons for the allowed types (This will override 'default_child_type). restrict_child_types = self.config.getlist('childtickets','parent.%s.restrict_child_type' % ticket['type'],default=[]) if not restrict_child_types: # trac.ini : Default 'type' of child tickets? default_child_type = self.config.get('childtickets', 'parent.%s.default_child_type' % ticket['type'], default=self.config.get('ticket','default_type')) # ... create a default submit button if ticket['status'] == 'closed': submit_button_fields = ( tag.input(type="submit",disabled="disabled",name="childticket",value="New Child Ticket",title="Create a child ticket"), tag.input(type="hidden", name="type", value=default_child_type), ) else: submit_button_fields = ( tag.input(type="submit",name="childticket",value="New Child Ticket",title="Create a child ticket"), tag.input(type="hidden",name="type",value=default_child_type), ) else: if ticket['status'] == 'closed': submit_button_fields = [ tag.input(type="submit",disabled="disabled",name="type",value="%s" % ticket_type,title="Create a %s child ticket" % ticket_type) for ticket_type in restrict_child_types ] else: submit_button_fields = [ tag.input(type="submit",name="type",value="%s" % ticket_type,title="Create a %s child ticket" % ticket_type) for ticket_type in restrict_child_types ] buttondiv = tag.form( tag.div(default_child_fields, inherited_child_fields, submit_button_fields, class_="buttons"), method="get", action=req.href.newticket(), ) return buttondiv
def _clone_form(self, req, ticket, data): fields = {} for f in data.get('fields', []): name = f['name'] if name == 'summary': fields['summary'] = _("%(summary)s (cloned)", summary=ticket['summary']) elif name == 'description': fields['description'] = \ _("Cloned from #%(id)s:\n----\n%(description)s", id=ticket.id, description=ticket['description']) else: fields[name] = ticket[name] return tag.form( tag.div( tag.input(type="submit", name="clone", value=_("Clone"), title=_("Create a copy of this ticket")), [tag.input(type="hidden", name='field_' + n, value=v) for n, v in fields.iteritems()], tag.input(type="hidden", name='preview', value=''), class_="inlinebuttons"), method="post", action=req.href.newticket())
def filter_stream(self, req, method, filename, stream, data): if filename != 'report_view.html': return stream page_name = 'report:%s' % data['context'].resource.id page_label = data['title'] page = WikiPage(self.env, page_name) if 'WIKI_MODIFY' not in req.perm(page.resource): return stream text = '= Snapshot of [%s %s]: =\n' % (page_name, page_label) text += '{{{#!QueryResults\n' cols = [ header['col'] for header in data.get('header_groups', [[]])[0] if not header['hidden'] ] cols_work = [t for t in cols] # copy if 'ticket' in cols_work: cols_work[cols_work.index( 'ticket')] = 'id' # replace 'ticket' to 'id' text += '||= href =||= %s\n' % ' =||= '.join(cols_work) for groupindex, row_group in data.get('row_groups', []): text += '|| group: %s\n' % groupindex for row in row_group: row = row['cell_groups'][0] ticket = {} for value in row: ticket[value['header']['col']] = value['value'] ticket['href'] = get_resource_url( self.env, Resource('ticket', ticket.get('ticket', 0)), self.env.href) text += '|| %s || %s\n' % (ticket['href'], ' || '.join( [self.formatter(col, ticket[col]) for col in cols])) text += '}}}' div = tag.div(tag.input(value='Save as wiki:', type='submit'), tag.input(name='action', value='edit', type='hidden'), tag.input(name='text', value=text, type='hidden'), tag.input(name='page', value=page_name)) return stream | Transformer('//div[@id="content"]/div[@class="buttons"]') \ .append(tag.form(div, action=get_resource_url(self.env, Resource('wiki'), self.env.href)))
def _clone_form(self, req, ticket, data): fields = self.ticket_cloner.build_clone_form(req, ticket, data) action = self.ticket_clone_form_action or req.href.newticket() method = self.ticket_clone_form_method if method == "GET": field_name_fn = lambda name: name else: field_name_fn = lambda name: "field_%s" % name return tag.form(tag.div(tag.input( type="submit", name="clone", value=_("Clone"), title=_("Create a copy of this ticket")), [ tag.input(type="hidden", name=field_name_fn(n), value=v) for n, v in fields.iteritems() ], tag.input(type="hidden", name='preview', value=''), class_="inlinebuttons"), method=method, action=action)
def _review_attrs(self, req, changeset): review = Review.get(self.env.get_db_cnx(),changeset.rev, self.author(changeset)) if req.perm.has_permission('CODE_REVIEW'): comment = tag.textarea(review.comment, name="review_comment", rows=6, cols=100 ) if review.status=="ACCEPTED": checkbox = tag.input(type="checkbox", name="review_passed", checked="true") else: checkbox = tag.input(type="checkbox", name="review_passed") submit = tag.input(type="hidden", name="review_rev", value=changeset.rev)+ \ tag.input(type="hidden", name="review_author", value=self.author(changeset))+ \ tag.input(type="submit", name="review", value="Review") else: comment = tag.span(review.comment) checkbox = tag.span(review.status) submit = ""; return tag.form( tag.dt("Reviewer:",class_="property author"), tag.dd( req.authname,class_="author"), tag.dt("Comment:",class_="property author"), tag.dd( comment ), tag.dt("Passed:",class_="property author"), tag.dd(checkbox+submit) )
def filter_stream(self, req, method, filename, stream, data): """Return a filtered Genshi event stream, or the original unfiltered stream if no match. `req` is the current request object, `method` is the Genshi render method (xml, xhtml or text), `filename` is the filename of the template to be rendered, `stream` is the event stream and `data` is the data for the current template. See the Genshi documentation for more information. """ if filename == 'ticket.html': ticket = data['ticket'] if ticket.exists: sensitive = (ticket.values.get('sensitive') == '1') if req.perm.has_permission('SENSITIVE_VIEW'): action = data['ticket'].exists and \ req.href.ticket(data['ticket'].id) or \ req.href.newticket() form = tag.form( tag.input( id="field-sensitive", name="field_sensitive", value=sensitive and '0' or '1', type='hidden'), tag.input( type="hidden", name="ts", value=data['timestamp']), tag.input( type="hidden", name="action", value=data['action']), tag.input( type="submit", name="submit", class_='btn', # TODO: translations value=sensitive and 'make public' or 'make private'), method="post", id="sensitiveform", action="%s#trac-modify-sensitive" % action, ) if sensitive: div = tag.div( # TODO: translations tag.div( form, # XXX i18n TODO tag.span(_("trac_por_ticket_sensitive"), tag.span(u'Il ticket è riservato ai developer e non visibile al cliente', class_="sensitive-message"), class_="alert alert-success"), id='sensitiveticket') else: div = tag.div( # TODO: translations tag.div( form, # XXX i18n TODO tag.span(_("trac_por_ticket_public"), tag.span(u'Ticket condiviso con il cliente', class_="sensitive-message"), class_="alert alert-error"), id='sensitiveticket') return stream | \ Transformer("//div[@id='ticket']").before(div) return stream
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 enter_secret(macro, environ, *secrets): """Macro for entering a secret. Takes a several secrets as args. Requires the following keys in the environ: ``user`` An instance of :class:`django.contrib.auth.models.User`. Will be used to generate a security token of a secret that is only valid for this user. ``enter_secret_target`` An url for the action attribute of the form element. Submitting the form will generate a POST request with the following data: ``secret`` The secret which was entered by the user ``secret_token`` Occurs several times, one time for each secret that is valid for this form. It is a security token that is build by generating a HMAC with ``settings.SECRET_KEY`` as key. The message is the user id and the valid secret divided by a colon. ``all_secrets`` A list of strings containing all available secrets for this scenario. ``submitted_secrets`` A list of strings containing all secrets submitted by the user for this scenario. ``secret_token_function`` A function that calculates the secret's security token. Takes an user and a secret. ``csrf_token`` Django's CSRF token. Use :func:`django.middleware.csrf.get_token` to get it. """ target = environ['enter_secret_target'] user = environ['user'] # If all secrets are already submitted, change css class solved = all(secret in environ['submitted_secrets'] for secret in secrets) css_class = 'enter_secret secret_solved' if solved else 'enter_secret' secret_div = tag.div(macro.parsed_body(), class_=css_class) if not solved: # If there are no secrets in the arguments, we will accept all secrets if not secrets: secrets = environ['all_secrets'] form = tag.form(method='post', action=target) for secret in secrets: secret_token = environ['secret_token_function'](user, secret) form.append( tag.input(name='secret_token', value=secret_token, type='hidden')) form.append( tag.input(type='hidden', name='csrfmiddlewaretoken', value=environ['csrf_token'])) p = tag.p(tag.strong(_('Enter secret:')), ' ') p.append(tag.input(name='secret', type='text')) p.append( tag.input(type='submit', name='enter_secret', value=_('Submit'))) form.append(p) secret_div.append(form) form_submitted_secrets = [ secret for secret in secrets if secret in environ['submitted_secrets'] ] if form_submitted_secrets: submitted_div = tag.div(tag.p(_('Already submitted secrets:')), _class='submitted_secrets') secret_list = tag.ul() for secret in form_submitted_secrets: secret_list.append(tag.li(secret)) submitted_div.append(secret_list) secret_div.append(submitted_div) return secret_div
def filter_stream(self, req, method, filename, stream, data): if not req.path_info.startswith('/ticket/'): return stream div = None link = None button = None if 'ticket' in data: # get parents data ticket = data['ticket'] # title div = tag.div(class_='description') if 'TICKET_CREATE' in req.perm(ticket.resource) \ and ticket['status'] != 'closed': opt_inherit = self.env.config.getlist( 'subtickets', 'type.%(type)s.child_inherits' % ticket) if self.opt_add_style == 'link': inh = {f: ticket[f] for f in opt_inherit} link = tag.a(_('add'), href=req.href.newticket(parents=ticket.id, **inh)) link = tag.span('(', link, ')', class_='addsubticket') else: inh = [ tag.input(type='hidden', name=f, value=ticket[f]) for f in opt_inherit ] button = tag.form(tag.div(tag.input( type="submit", value=_("Create"), title=_("Create a child ticket")), inh, tag.input(type="hidden", name="parents", value=str(ticket.id)), class_="inlinebuttons"), method="get", action=req.href.newticket()) div.append(button) div.append(tag.h3(_('Subtickets '), link)) if 'subtickets' in data: # table tbody = tag.tbody() div.append(tag.table(tbody, class_='subtickets')) # tickets self._create_subtickets_table(req, data['subtickets'], tbody) if div: add_stylesheet(req, 'subtickets/css/subtickets.css') ''' If rendered in preview mode, DIV we're interested in isn't a child but the root and transformation won't succeed. According to HTML specification, id's must be unique within a document, so it's safe to omit the leading '.' in XPath expression to select all matching regardless of hierarchy their in. ''' stream |= Transformer('//div[@id="ticket"]').append(div) return stream
def filter_stream(self, req, method, filename, stream, data): # Tickets will be modified to show the child tickets as a list under the 'Description' section. if filename == 'ticket.html': # Add our own styles for the ticket lists. add_stylesheet(req, 'ct/css/childtickets.css') # Get the ticket info. ticket = data.get('ticket') # Modify ticket.html with sub-ticket table, create button, etc... # As follows: # - If ticket has no child tickets and child tickets are NOT allowed then skip. # - If ticket has child tickets and child tickets are NOT allowed (ie. rules changed or ticket type changed after children were assigned), # print list of tickets but do not allow any tickets to be created. # - If child tickets are allowed then print list of child tickets or 'No Child Tickets' if non are currently assigned. # if ticket and ticket.exists: # The additional section on the ticket is built up of (potentially) three parts: header, ticket table, buttons. These # are all 'wrapped up' in a 'div' with the 'attachments' id (we'll just pinch this to make look and feel consistent with any # future changes!) filter = Transformer('//div[@id="ticket"]') snippet = tag.div() # Are there any child tickets to display? childtickets = [ Ticket(self.env,n) for n in self.childtickets.get(ticket.id,[]) ] # (tempish) fix for #8612 : force sorting by ticket id childtickets = sorted(childtickets, key=lambda t: t.id) # Are child tickets allowed? childtickets_allowed = self.config.getbool('childtickets', 'parent.%s.allow_child_tickets' % ticket['type']) # If there are no childtickets and the ticket should not have any child tickets, we can simply drop out here. if not childtickets_allowed and not childtickets: return stream # Our 'main' display consists of two divs. buttondiv = tag.div() tablediv = tag.div() # Test if the ticket has children: If so, then list in pretty table. if childtickets: # trac.ini : Which columns to display in child ticket listing? columns = self.config.getlist('childtickets', 'parent.%s.table_headers' % ticket['type'], default=['summary','owner']) tablediv = tag.div( tag.table( tag.thead( tag.tr( tag.th("Ticket",class_="id"), [ tag.th(s.title(),class_=s) for s in columns ]) ), tag.tbody([ self._table_row(req,tkt,columns) for tkt in childtickets ]), class_="listing tickets", ), tag.br(), ) # trac.ini : child tickets are allowed - Set up 'create new ticket' buttons. if childtickets_allowed: # Can user create a new ticket? If not, just display title (ie. no 'create' button). if 'TICKET_CREATE' in req.perm(ticket.resource): # Always pass these fields default_child_fields = ( tag.input(type="hidden", name="parent", value='#'+str(ticket.id)), ) #Pass extra fields defined in inherit parameter of parent inherited_child_fields = [ tag.input(type="hidden",name="%s"%field,value=ticket[field]) for field in self.config.getlist('childtickets','parent.%s.inherit' % ticket['type']) ] # If child types are restricted then create a set of buttons for the allowed types (This will override 'default_child_type). restrict_child_types = self.config.getlist('childtickets','parent.%s.restrict_child_type' % ticket['type'],default=[]) if not restrict_child_types: # trac.ini : Default 'type' of child tickets? default_child_type = self.config.get('childtickets', 'parent.%s.default_child_type' % ticket['type'], default=self.config.get('ticket','default_type')) # ... create a default submit button if ticket['status'] == 'closed': submit_button_fields = ( tag.input(type="submit",disabled="disabled",name="childticket",value="New Child Ticket",title="Create a child ticket"), tag.input(type="hidden", name="type", value=default_child_type), ) else: submit_button_fields = ( tag.input(type="submit",name="childticket",value="New Child Ticket",title="Create a child ticket"), tag.input(type="hidden",name="type",value=default_child_type), ) else: if ticket['status'] == 'closed': submit_button_fields = [ tag.input(type="submit",disabled="disabled",name="type",value="%s" % ticket_type,title="Create a %s child ticket" % ticket_type) for ticket_type in restrict_child_types ] else: submit_button_fields = [ tag.input(type="submit",name="type",value="%s" % ticket_type,title="Create a %s child ticket" % ticket_type) for ticket_type in restrict_child_types ] buttondiv = tag.form( tag.div( default_child_fields, inherited_child_fields, submit_button_fields), method="get", action=req.href.newticket(), ) snippet.append(tag.h2("Child Tickets",class_="foldable")) snippet.append(tag.div(tablediv, buttondiv, id="childtickets")) return stream | filter.after(snippet) return stream
def expand_macro(self, formatter, name, args): req = formatter.req tag_system = TagSystem(self.env) all_releases = natural_sort([r.id for r, _ in tag_system.query(req, 'realm:wiki release')]) all_categories = sorted([r.id for r, _ in tag_system.query(req, 'realm:wiki type')]) hide_release_picker = False hide_fieldset_legend = False hide_fieldset_description = False other = [] if args: categories = [] releases = [] for arg in args.split(): if arg in all_releases: hide_release_picker = True releases.append(arg) elif arg in all_categories: categories.append(arg) else: other.append(arg) if len(categories) or len(releases): hide_fieldset_description = True if not len(categories): categories = all_categories elif len(categories) == 1: hide_fieldset_legend = True if not len(releases): releases = all_releases else: categories = all_categories releases = all_releases if 'update_th_filter' in req.args: show_releases = req.args.get('release', ['0.11']) if isinstance(show_releases, basestring): show_releases = [show_releases] req.session['th_release_filter'] = ','.join(show_releases) else: show_releases = req.session.get('th_release_filter', '0.11').split(',') output = "" if not hide_release_picker: style = "text-align:right; padding-top:1em; margin-right:5em;" form = builder.form('\n', style=style, method="get") style = "font-size:xx-small;" span = builder.span("Show hacks for releases:", style=style) for version in releases: inp = builder.input(version, type_="checkbox", name="release", value=version) if version in show_releases: inp(checked="checked") span(inp, '\n') style = "font-size:xx-small; padding:0; border:solid 1px black;" span(builder.input(name="update_th_filter", type_="submit", style=style, value="Update"), '\n') form('\n', span, '\n') output = "%s%s\n" % (output, form) def link(resource): return render_resource_link(self.env, formatter.context, resource, 'compact') for category in categories: page = WikiPage(self.env, category) match = self.title_extract.search(page.text) if match: cat_title = '%s' % match.group(1).strip() cat_body = self.title_extract.sub('', page.text, 1) else: cat_title = '%s' % category cat_body = page.text cat_body = self.self_extract.sub('', cat_body).strip() style = "padding:1em; margin:0em 5em 2em 5em; border:1px solid #999;" fieldset = builder.fieldset('\n', style=style) if not hide_fieldset_legend: legend = builder.legend(style="color: #999;") legend(builder.a(cat_title, href=self.env.href.wiki(category))) fieldset(legend, '\n') if not hide_fieldset_description: fieldset(builder.p(wiki_to_html(cat_body, self.env, req))) ul = builder.ul('\n', class_="listtagged") query = 'realm:wiki (%s) %s %s' % \ (' or '.join(show_releases), category, ' '.join(other)) lines = 0 for resource, tags in tag_system.query(req, query): # filter out the page used to make important tags # persistent if resource.id == "tags/persistent": continue lines += 1 li = builder.li(link(resource), ': ') page = WikiPage(self.env, resource) match = self.title_extract.search(page.text) description = "''no description available''" if match: if match.group(1): description = match.group(1).strip() li(wiki_to_oneliner(description, self.env, req=req)) if tags: if hide_fieldset_legend == False and category in tags: tags.remove(category) self.log.debug("hide %s: no legend" % category) for o in other: if o in tags: tags.remove(o) rendered_tags = [ link(resource('tag', tag)) for tag in natural_sort(tags) ] span = builder.span(style="font-size:xx-small;") span(' (tags: ', rendered_tags[0], [(', ', tag) for tag in rendered_tags[1:]], ')') li(span) ul(li, '\n') if lines: fieldset(ul, '\n') else: message = "No results for %s." % \ (hide_release_picker and "this version" or "your selection") fieldset(builder.p(builder.em(message)), '\n') output = "%s%s\n" % (output, fieldset) return output
def get_workflow_markup(self, req, base_href, realm, resource): rws = ResourceWorkflowState(self.env, resource.id, realm) # action_controls is an ordered list of "renders" tuples, where # renders is a list of (action_key, label, widgets, hints) representing # the user interface for each action action_controls = [] sorted_actions = self.get_available_actions(req, realm, resource=resource) if len(sorted_actions) > 0: for action in sorted_actions: first_label = None hints = [] widgets = [] label, widget, hint = self.get_action_markup( req, realm, action[1], resource) if not first_label: first_label = label widgets.append(widget) hints.append(hint) action_controls.append( (action[1], first_label, tag(widgets), hints)) form = tag.form(id='resource_workflow_form', name='resource_workflow_form', action=base_href + '/workflowtransition', method='get')(tag.input(name='id', type='hidden', value=resource.id), tag.input(name='res_realm', type='hidden', value=realm)) form.append(tag.div()(tag.span()( "Current state: %s" % rws['state']), tag.br(), tag.br())) for i, ac in enumerate(action_controls): # The default action is the first in the action_controls list. if i == 0: is_checked = 'true' else: is_checked = None form.append( tag.input(name='selected_action', type='radio', value=ac[0], checked=is_checked)(ac[1], tag.div()(ac[2], ac[3]))) form.append(tag.span()( tag.br(), tag.input(id='resource_workflow_form_submit_button', type='submit', value='Perform Action'))) else: form = tag('') return form
def filter_stream(self, req, method, filename, stream, data): # Tickets will be modified to show the child tickets as a list under the 'Description' section. if filename == 'ticket.html': # Get the ticket info. ticket = data.get('ticket') # Modify ticket.html with sub-ticket table, create button, etc... # As follows: # - If ticket has no child tickets and child tickets are NOT allowed then skip. # - If ticket has child tickets and child tickets are NOT allowed (ie. rules changed or ticket type changed after children were assigned), # print list of tickets but do not allow any tickets to be created. # - If child tickets are allowed then print list of child tickets or 'No Child Tickets' if non are currently assigned. # if ticket and ticket.exists: filter = Transformer('//div[@class="description"]') snippet = tag() # Are there any child tickets to display? childtickets = [ Ticket(self.env, n) for n in self.env.childtickets.get(ticket.id, []) ] # (tempish) fix for #8612 : force sorting by ticket id childtickets = sorted(childtickets, key=lambda t: t.id) # trac.ini : Which columns to display in child ticket listing? columns = self.config.getlist('childtickets', 'parent.%s.table_headers' % ticket['type'], default=['summary', 'owner']) # trac.ini : child tickets are allowed. if self.config.getbool( 'childtickets', 'parent.%s.allow_child_tickets' % ticket['type']): # trac.ini : Default 'type' of child tickets? default_child_type = self.config.get( 'childtickets', 'parent.%s.default_child_type' % ticket['type'], default=self.config.get('ticket', 'default_type')) self.env.log.debug( "TracchildticketsModule : default_child_type: %s" % default_child_type) # Can user create a new ticket? If not, just display title (ie. no 'create' button). if 'TICKET_CREATE' in req.perm(ticket.resource): # Always pass these fields default_child_fields = (tag.input(type="hidden", name="parent", value='#' + str(ticket.id)), ) #Pass extra fields defined in inherit parameter of parent inherited_child_fields = [ tag.input(type="hidden", name="%s" % field, value=ticket[field]) for field in self.config.getlist( 'childtickets', 'parent.%s.inherit' % ticket['type']) ] # If child types are restricted then create a set of buttons for the allowed types (This will override 'default_child_type). restrict_child_types = self.config.getlist( 'childtickets', 'parent.%s.restrict_child_type' % ticket['type'], default=[]) if not restrict_child_types: # ... create a default submit button submit_button_fields = ( tag.input(type="submit", name="childticket", value="New Child Ticket", title="Create a child ticket"), tag.input(type="hidden", name="type", value=default_child_type), ) else: submit_button_fields = [ tag.input(type="submit", name="type", value="%s" % ticket_type, title="Create a %s child ticket" % ticket_type) for ticket_type in restrict_child_types ] snippet.append( tag.div( tag.form( tag.div(default_child_fields, inherited_child_fields, submit_button_fields, class_="inlinebuttons"), method="get", action=req.href.newticket(), ), tag.h3("Child Tickets", id="comment:child_tickets"), )) else: snippet.append( tag.div( tag.h3("Child Tickets", id="comment:child_tickets"))) # trac.ini : child tickets are NOT allowed but (somehow?!) this parent ticket has children assigned. elif childtickets: snippet.append( tag.div( tag.h3("Child Tickets", id="comment:child_tickets"))) # Test if the ticket has children: If so, then list in pretty table. if childtickets: snippet.append( tag.div( tag.table( tag.thead( tag.tr(tag.th("Ticket", class_="id"), [ tag.th(s.title(), class_=s) for s in columns ])), tag.tbody([ self._table_row(req, tkt, columns) for tkt in childtickets ]), class_="listing tickets", ), )) elif self.config.getbool( 'childtickets', 'parent.%s.allow_child_tickets' % ticket['type']): snippet.append(tag.div(tag.p("NO SUB-TICKETS."))) return stream | filter.append(snippet) return stream
def filter_stream(self, req, method, filename, stream, data): """ Quick and dirty solution - modify page on the fly to inject special field. It would be nicer if we can do it by creating custom field as this depends on page structure. """ #embed(header='Ticket Stream Filter') if filename == 'ticket.html': # Disable any direct bounty input filter = Transformer('.//input[@id="field-bounty"]') stream |= filter.attr("disabled", "disabled") ticket = data.get('ticket') if ticket and ticket.exists: identifier = ticket.id user = req.authname if req.authname != 'anonymous' else None request = self.call_api('GET', '/issue/%s' % identifier) fragment = tag() sponsorships = {} status = self.convert_status(ticket.values['status']) owner = ticket.values['owner'] tooltip = None if request != None and (request.status_code == 200 or request.status_code == 404): sponsorships = self.get_sponsorships(identifier) pledged_amount = sum_amounts(sponsorships.values()) user_sponsorship = sponsorships.get(user, Sponsorship()) # Bounty tooltip = u"Pledged: %d\u20ac" % pledged_amount if status == 'STARTED' or status == 'COMPLETED': confirmed_amount = sum_amounts(sponsorships.values(), ('CONFIRMED', 'VALIDATED', 'REJECTED', 'TRANSFERRED', 'REFUNDED')) tooltip += u" \nConfirmed: %d\u20ac" % confirmed_amount if status == 'COMPLETED': validated_amount = sum_amounts(sponsorships.values(), 'VALIDATED') tooltip += u" \nValidated: %d\u20ac" % validated_amount # Action action = None if (((status == 'STARTED' or status == 'COMPLETED') and user_sponsorship.status == 'PLEDGED') or (status == 'STARTED' and user != None and user != owner and user_sponsorship.status == None)): response = self.call_api('GET', '/config/payment_gateways') gateways = response.json().get('gateways') gateway_tags = [] if 'DUMMY' in gateways: gateway_tags.append(tag.input(type="submit", value="Payment Card", name='DUMMY')) if 'PAYPAL_STANDARD' in gateways: gateway_tags.append(tag.input(type="submit", value="PayPal", name='PAYPAL_STANDARD')) if 'PAYPAL_ADAPTIVE' in gateways: gateway_tags.append(tag.input(type="submit", value="PayPal", name='PAYPAL_ADAPTIVE')) if user_sponsorship.status == 'PLEDGED': action = tag.form( tag.input(type="button", name="confirm", value=u"Confirm %d\u20ac" % user_sponsorship.amount, id="confirm-button"), tag.span(gateway_tags, id="confirm-options"), tag.input(type="submit", name="delete", value="Delete"), method="post", action=req.href.ticket(identifier, "confirm")) else: #TODO: should be separate action action = tag.form( tag.input(name="amount", type="text", size="3", value="0", pattern="[0-9]*", title="money amount"), tag.input(type="button", value="Pledge & Confirm", id="confirm-button"), tag.span(gateway_tags, id="confirm-options"), method="post", action=req.href.ticket(identifier, "confirm")) elif status == 'COMPLETED' and user_sponsorship.status in ('CONFIRMED', 'REJECTED', 'VALIDATED'): action = tag.form(method="post", action=req.href.ticket(identifier, "validate")) if user_sponsorship.status == 'CONFIRMED' or user_sponsorship.status == 'REJECTED': action.append(tag.input(type="submit", name='validate', value=u"Validate %d\u20ac" % user_sponsorship.amount)) if user_sponsorship.status == 'CONFIRMED' or user_sponsorship.status == 'VALIDATED': action.append(tag.input(type="submit", name='reject', value="Reject")) elif (status == 'READY' and user != None): if user_sponsorship.status == None: action = tag.form(tag.input(name="amount", type="text", size="3", value=user_sponsorship.amount, pattern="[0-9]*", title="money amount"), tag.input(type="submit", value="Pledge"), method="post", action=req.href.ticket(identifier, "sponsor")) elif user_sponsorship.status == 'PLEDGED': action = tag.form(tag.input(name="amount", type="text", size=3, value=user_sponsorship.amount, pattern="[0-9]*", title="money amount"), tag.input(type="submit", name="update", value="Update"), tag.input(type="submit", name="delete", value="Delete"), method="post", action=req.href.ticket(identifier, "update_sponsorship")) elif (user == None): action = tag.span(u"\u00A0", tag.a("Login", href=req.href.login()), " or ", tag.a("Register", href=req.href.register()), " to sponsor") if action != None: fragment.append(" ") fragment.append(action) else: error = "Connection error" if request: error = request.json().get("error", "Unknown error") fragment.append(tag.span("[BountyFunding Error]", title=error)) #chrome = Chrome(self.env) #chrome.add_jquery_ui(req) add_stylesheet(req, 'htdocs/styles/bountyfunding.css') add_script(req, 'htdocs/scripts/bountyfunding.js') if tooltip != None: filter = Transformer('.//td[@headers="h_bounty"]/text()') stream |= filter.wrap(tag.span(title=tooltip)) filter = Transformer('.//td[@headers="h_bounty"]') stream |= filter.attr("class", "bountyfunding") stream |= filter.append(fragment) return stream
def filter_stream(self, req, method, filename, stream, data): # Tickets will be modified to show the child tickets as a list under the 'Description' section. if filename == 'ticket.html': # Get the ticket info. ticket = data.get('ticket') # Modify ticket.html with sub-ticket table, create button, etc... # As follows: # - If ticket has no child tickets and child tickets are NOT allowed then skip. # - If ticket has child tickets and child tickets are NOT allowed (ie. rules changed or ticket type changed after children were assigned), # print list of tickets but do not allow any tickets to be created. # - If child tickets are allowed then print list of child tickets or 'No Child Tickets' if non are currently assigned. # if ticket and ticket.exists: filter = Transformer('//div[@class="description"]') snippet = tag() # Are there any child tickets to display? childtickets = [ Ticket(self.env,n) for n in self.env.childtickets.get(ticket.id,[]) ] # (tempish) fix for #8612 : force sorting by ticket id childtickets = sorted(childtickets, key=lambda t: t.id) # trac.ini : Which columns to display in child ticket listing? columns = self.config.getlist('childtickets', 'parent.%s.table_headers' % ticket['type'], default=['summary','owner']) # trac.ini : child tickets are allowed. if self.config.getbool('childtickets', 'parent.%s.allow_child_tickets' % ticket['type']): # trac.ini : Default 'type' of child tickets? default_child_type = self.config.get('childtickets', 'parent.%s.default_child_type' % ticket['type'], default=self.config.get('ticket','default_type')) self.env.log.debug("TracchildticketsModule : default_child_type: %s" % default_child_type) # Can user create a new ticket? If not, just display title (ie. no 'create' button). if 'TICKET_CREATE' in req.perm(ticket.resource): # Always pass these fields default_child_fields = ( tag.input(type="hidden", name="parent", value='#'+str(ticket.id)), ) #Pass extra fields defined in inherit parameter of parent inherited_child_fields = [ tag.input(type="hidden",name="%s"%field,value=ticket[field]) for field in self.config.getlist('childtickets','parent.%s.inherit' % ticket['type']) ] # If child types are restricted then create a set of buttons for the allowed types (This will override 'default_child_type). restrict_child_types = self.config.getlist('childtickets','parent.%s.restrict_child_type' % ticket['type'],default=[]) if not restrict_child_types: # ... create a default submit button submit_button_fields = ( tag.input(type="submit",name="childticket",value="New Child Ticket",title="Create a child ticket"), tag.input(type="hidden", name="type", value=default_child_type), ) else: submit_button_fields = [ tag.input(type="submit",name="type",value="%s" % ticket_type,title="Create a %s child ticket" % ticket_type) for ticket_type in restrict_child_types ] snippet.append(tag.div( tag.form( tag.div( default_child_fields, inherited_child_fields, submit_button_fields, class_="inlinebuttons"), method="get", action=req.href.newticket(), ), tag.h3("Child Tickets",id="comment:child_tickets"), )) else: snippet.append(tag.div(tag.h3("Child Tickets",id="comment:child_tickets"))) # trac.ini : child tickets are NOT allowed but (somehow?!) this parent ticket has children assigned. elif childtickets: snippet.append(tag.div(tag.h3("Child Tickets",id="comment:child_tickets"))) # Test if the ticket has children: If so, then list in pretty table. if childtickets: snippet.append( tag.div( tag.table( tag.thead( tag.tr( tag.th("Ticket",class_="id"), [ tag.th(s.title(),class_=s) for s in columns ]) ), tag.tbody([ self._table_row(req,tkt,columns) for tkt in childtickets ]), class_="listing tickets", ), ) ) elif self.config.getbool('childtickets', 'parent.%s.allow_child_tickets' % ticket['type']): snippet.append(tag.div(tag.p("NO SUB-TICKETS."))) return stream | filter.append(snippet) return stream
def enter_secret(macro, environ, *secrets): """Macro for entering a secret. Takes a several secrets as args. Requires the following keys in the environ: ``user`` An instance of :class:`django.contrib.auth.models.User`. Will be used to generate a security token of a secret that is only valid for this user. ``enter_secret_target`` An url for the action attribute of the form element. Submitting the form will generate a POST request with the following data: ``secret`` The secret which was entered by the user ``secret_token`` Occurs several times, one time for each secret that is valid for this form. It is a security token that is build by generating a HMAC with ``settings.SECRET_KEY`` as key. The message is the user id and the valid secret divided by a colon. ``all_secrets`` A list of strings containing all available secrets for this scenario. ``submitted_secrets`` A list of strings containing all secrets submitted by the user for this scenario. ``secret_token_function`` A function that calculates the secret's security token. Takes an user and a secret. ``csrf_token`` Django's CSRF token. Use :func:`django.middleware.csrf.get_token` to get it. """ target = environ['enter_secret_target'] user = environ['user'] # If all secrets are already submitted, change css class solved = all(secret in environ['submitted_secrets'] for secret in secrets) css_class = 'enter_secret secret_solved' if solved else 'enter_secret' secret_div = tag.div(macro.parsed_body(), class_=css_class) if not solved: # If there are no secrets in the arguments, we will accept all secrets if not secrets: secrets = environ['all_secrets'] form = tag.form(method='post', action=target) for secret in secrets: secret_token = environ['secret_token_function'](user, secret) form.append(tag.input(name='secret_token', value=secret_token, type='hidden')) form.append(tag.input(type='hidden', name='csrfmiddlewaretoken', value=environ['csrf_token'])) p = tag.p(tag.strong(_('Enter secret:')), ' ') p.append(tag.input(name='secret', type='text')) p.append(tag.input(type='submit', name='enter_secret', value=_('Submit'))) form.append(p) secret_div.append(form) form_submitted_secrets = [secret for secret in secrets if secret in environ['submitted_secrets']] if form_submitted_secrets: submitted_div = tag.div(tag.p(_('Already submitted secrets:')), _class='submitted_secrets') secret_list = tag.ul() for secret in form_submitted_secrets: secret_list.append(tag.li(secret)) submitted_div.append(secret_list) secret_div.append(submitted_div) return secret_div
def filter_stream(self, req, method, filename, stream, data): """ Quick and dirty solution - modify page on the fly to inject special field. It would be nicer if we can do it by creating custom field as this depends on page structure. """ #embed(header='Ticket Stream Filter') if filename == 'ticket.html': # Disable any direct bounty input filter = Transformer('.//input[@id="field-bounty"]') stream |= filter.attr("disabled", "disabled") ticket = data.get('ticket') if ticket and ticket.exists: identifier = ticket.id user = req.authname if req.authname != 'anonymous' else None request = self.call_api('GET', '/issue/%s' % identifier) fragment = tag() sponsorships = {} status = self.convert_status(ticket.values['status']) owner = ticket.values['owner'] tooltip = None if request != None and (request.status_code == 200 or request.status_code == 404): sponsorships = self.get_sponsorships(identifier) pledged_amount = sum_amounts(sponsorships.values()) user_sponsorship = sponsorships.get(user, Sponsorship()) # Bounty tooltip = u"Pledged: %d\u20ac" % pledged_amount if status == 'STARTED' or status == 'COMPLETED': confirmed_amount = sum_amounts( sponsorships.values(), ('CONFIRMED', 'VALIDATED', 'REJECTED', 'TRANSFERRED', 'REFUNDED')) tooltip += u" \nConfirmed: %d\u20ac" % confirmed_amount if status == 'COMPLETED': validated_amount = sum_amounts(sponsorships.values(), 'VALIDATED') tooltip += u" \nValidated: %d\u20ac" % validated_amount # Action action = None if (((status == 'STARTED' or status == 'COMPLETED') and user_sponsorship.status == 'PLEDGED') or (status == 'STARTED' and user != None and user != owner and user_sponsorship.status == None)): response = self.call_api('GET', '/config/payment_gateways') gateways = response.json().get('gateways') gateway_tags = [] if 'DUMMY' in gateways: gateway_tags.append( tag.input(type="submit", value="Payment Card", name='DUMMY')) if 'PAYPAL_STANDARD' in gateways: gateway_tags.append( tag.input(type="submit", value="PayPal", name='PAYPAL_STANDARD')) if 'PAYPAL_ADAPTIVE' in gateways: gateway_tags.append( tag.input(type="submit", value="PayPal", name='PAYPAL_ADAPTIVE')) if user_sponsorship.status == 'PLEDGED': action = tag.form( tag.input(type="button", name="confirm", value=u"Confirm %d\u20ac" % user_sponsorship.amount, id="confirm-button"), tag.span(gateway_tags, id="confirm-options"), tag.input(type="submit", name="delete", value="Delete"), method="post", action=req.href.ticket(identifier, "confirm")) else: #TODO: should be separate action action = tag.form( tag.input(name="amount", type="text", size="3", value="0", pattern="[0-9]*", title="money amount"), tag.input(type="button", value="Pledge & Confirm", id="confirm-button"), tag.span(gateway_tags, id="confirm-options"), method="post", action=req.href.ticket(identifier, "confirm")) elif status == 'COMPLETED' and user_sponsorship.status in ( 'CONFIRMED', 'REJECTED', 'VALIDATED'): action = tag.form(method="post", action=req.href.ticket( identifier, "validate")) if user_sponsorship.status == 'CONFIRMED' or user_sponsorship.status == 'REJECTED': action.append( tag.input(type="submit", name='validate', value=u"Validate %d\u20ac" % user_sponsorship.amount)) if user_sponsorship.status == 'CONFIRMED' or user_sponsorship.status == 'VALIDATED': action.append( tag.input(type="submit", name='reject', value="Reject")) elif (status == 'READY' and user != None): if user_sponsorship.status == None: action = tag.form( tag.input(name="amount", type="text", size="3", value=user_sponsorship.amount, pattern="[0-9]*", title="money amount"), tag.input(type="submit", value="Pledge"), method="post", action=req.href.ticket(identifier, "sponsor")) elif user_sponsorship.status == 'PLEDGED': action = tag.form( tag.input(name="amount", type="text", size=3, value=user_sponsorship.amount, pattern="[0-9]*", title="money amount"), tag.input(type="submit", name="update", value="Update"), tag.input(type="submit", name="delete", value="Delete"), method="post", action=req.href.ticket(identifier, "update_sponsorship")) elif (user == None): action = tag.span( u"\u00A0", tag.a("Login", href=req.href.login()), " or ", tag.a("Register", href=req.href.register()), " to sponsor") if action != None: fragment.append(" ") fragment.append(action) else: error = "Connection error" if request: error = request.json().get("error", "Unknown error") fragment.append( tag.span("[BountyFunding Error]", title=error)) #chrome = Chrome(self.env) #chrome.add_jquery_ui(req) add_stylesheet(req, 'htdocs/styles/bountyfunding.css') add_script(req, 'htdocs/scripts/bountyfunding.js') if tooltip != None: filter = Transformer('.//td[@headers="h_bounty"]/text()') stream |= filter.wrap(tag.span(title=tooltip)) filter = Transformer('.//td[@headers="h_bounty"]') stream |= filter.attr("class", "bountyfunding") stream |= filter.append(fragment) return stream
class AddCommentMacro(WikiMacroBase): """A macro to add comments to a page. Usage: {{{ [[AddComment]] }}} The macro accepts one optional argument that allows appending to the wiki page even though user may not have modify permission: {{{ [[AddComment(appendonly)]] }}} """ implements(IWikiMacroProvider, IRequestFilter, IMacroPoster) 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") the_form = tag.form( tag.fieldset( tag.legend("Add comment"), tag.div((wikipreview and "Page preview..." or None), tag.textarea((not cancel and comment or ""), class_="wikitext", id="addcomment", name="addcomment", cols=80, rows=5, disabled=(not cancomment and "disabled" or None)), class_="field"), (req.authname == 'anonymous' and tag.div( tag.label("Your email or username:"******"authoraddcomment"), tag.input(id="authoraddcomment", type="text", size=30, value=authname, name="authoraddcomment", disabled=(not cancomment and "disabled" or None))) or None), tag.input(type="hidden", name="__FORM_TOKEN", value=req.form_token), tag.div(tag.input(value="Add comment", type="submit", name="submitaddcomment", size=30, disabled=(not cancomment and "disabled" or None)), tag.input(value="Preview comment", type="submit", name="previewaddcomment", disabled=(not cancomment and "disabled" or None)), tag.input(value="Cancel", type="submit", name="canceladdcomment", disabled=(not cancomment and "disabled" or None)), class_="buttons"), ), method="post", action=page_url + "#commenting", ) if not wikipreview: # Wiki edit preview already adds this javascript file add_script(req, 'common/js/wikitoolbar.js') return tag.div(the_preview, the_message, the_form, id="commenting")