def _render_conrol_panel(): return tag.div(tag.span(tag.a(' ', class_='link-expanded', href='#'), tag.a(_('Collapse Control Panel'), href='#')), tag.span(tag.a(' ', class_='link-collapsed', href='#'), tag.a(_('Expand Control Panel'), href='#'), style="display: none;"), class_='control-panel')
def expand_macro(self, formatter, name, content, args): add_stylesheet(formatter.req, 'text_boxes/css/text_boxes.css') # TODO(holtgrew): Actually, we would like to add a style sheet but this does not work. Thus we use a style tag below. #add_stylesheet(formatter.req, 'text_boxes/css/text_boxes.css') className = CLASSES.get(name, 'ShellBox') if name in ['TextIcon']: args = trac.wiki.parse_args(content) if not args or not args[0]: # Handle case of empty entry. return None DEFAULT = 'gray' COLOR_CLASSES = ['green', 'red', 'yellow', 'black', 'gray', 'blue'] color_class_name = args[1].get('color', DEFAULT) if not color_class_name in COLOR_CLASSES: color_class_name = DEFAULT return tag.span(args[0], class_=('text_icon %s' % color_class_name)) elif name in ['MenuTrace']: args = trac.wiki.parse_args(content) if not args[0]: return None result = tag.span(args[0][0], class_='menu_item') for text in args[0][1:]: result += tag.span(u' \u25B8 ', class_='arrow') result += tag.span(text, class_='menu_item') return tag.span(result, class_='menu_trace') elif name in [ 'WarningBox', 'InfoBox', 'ImportantBox', 'AssignmentBox' ]: content_html = self.format_wiki(formatter, content) return tag.div(genshi.core.Markup(content_html), class_=className) else: return tag.pre(content, class_='wiki ' + className)
def prevnext_ctxnav(self, req, prev_label, next_label, up_label=None): links = req.chrome["links"] prev_link = next_link = None if not any(lnk in links for lnk in ("prev", "up", "next")): # Short circuit return if "prev" in links: prev = links["prev"][0] prev_link = tag.a(prev_label, href=prev["href"], title=prev["title"], class_="prev") add_ctxtnav( req, tag.span("", prev_link or prev_label, id="leftarrow", class_=not prev_link and "missing" or None) ) if up_label and "up" in links: up = links["up"][0] add_ctxtnav(req, tag.a(up_label, href=up["href"], title=up["title"])) if "next" in links: next_ = links["next"][0] next_link = tag.a(next_label, href=next_["href"], title=next_["title"], class_="next") add_ctxtnav( req, tag.span(next_link or next_label, "", id="rightarrow", class_=not next_link and "missing" or None) )
def render_statistics(self,ticketlist): # fallback if preconditions are not holding if len(ticketlist) == 0 or self.statistics_fields == []: return tag.span() # create a new map statistics_values = {} for field in self.statistics_fields: statistics_values[field] = 0 # map containing titles field_titles = {} for field in self.statistics_fields: field_titles[field] = 'sum of "%s"' % (field,) # summarize the field values of each ticket html = tag.div() for ticket in ticketlist: for field in self.statistics_fields: try: statistics_values[field] += int(ticket.getfield(field)) except: field_titles[field] = '"%s" could not be parsed to number' % (field,) # create html construct separator = '' for field in self.statistics_fields: html(separator, tag.span('%s' % (statistics_values[field],), title=field_titles[field]) ) separator = '/' return tag.div(html, class_='pptableticketperdaystatistics')
def filter_stream(self, req, method, filename, stream, data): project_id = self.env.config.get('por-dashboard', 'project-id') if project_id: project = DBSession().query(Project).get(project_id) # XXX se project is None, 404 stream |= Transformer(".//div[@id='trac-before-subnav']").prepend(tag.ul( tag.li(tag.a("Home", href="/")), tag.li( tag.span(" / ", class_="divider"), tag.a(project.customer.name, href="/admin/Customer/%s" % project.customer.id) ), tag.li( tag.span(" / ", class_="divider"), tag.a(project.name, href="/admin/Project/%s" % project.id) ), tag.li( tag.span(" / ", class_="divider"), tag.a('Trac', href="/trac/%s" % project.id), class_='active' ), class_="breadcrumb noprint", )) return stream
def _ticket_links(env, formatter, t, a_class=""): """Build links to tickets.""" tkt_id = str(t.get("id")) status = t.get("status") summary = to_unicode(t.get("summary")) owner = to_unicode(t.get("owner")) description = to_unicode(t.get("description")) url = t.get("href") if status == "closed": a_class = a_class + "closed" else: a_class = a_class + "open" # Reduce content for tooltips. markup = format_to_html(env, formatter.context, description) extractor = TextExtractor() extractor.feed(markup) tip = tag.span(shorten_line(extractor.getvalue())) ticket = tag.a("#" + tkt_id, href=url) ticket(tip, class_="tip", target="_blank") ticket = tag.div(ticket, class_=a_class, align="left") # Fix stripping of regular leading space in IE. blank = " " ticket(Markup(blank), summary, " (", owner, ")") summary = tag(summary, " (", owner, ")") ticket_short = tag.span(tag.a("#" + tkt_id, href=url, target="_blank", title_=summary), class_=a_class) return ticket, ticket_short
def get_dependency_field_values(self, tkt): # post_process_requestから呼ばれる # 通常のチケット表示ページに使われる. self.load_intertrac_setting() tkt_id = str(tkt.id) tkt_id_l = self.__get_current_project_name() + ':#' + tkt_id sub_ticket = self.__get_tickets_point_to( \ self.__get_subticket_other_prj_alias \ (self.__get_current_project_name(), tkt_id), \ self.__get_subticket(tkt_id) ) subsequentticket = self.__get_tickets_point_to( \ self.__get_subsequentticket_other_prj_alias( \ self.__get_current_project_name(), tkt_id), \ self.__get_subsequentticket(tkt_id) ) data_summary = [] data_depend = [] data_summary.append(LABEL_SUMMARY) self.__linkify_ids_p(tkt['summary_ticket'], data_summary) data_summary.append(LABEL_SUB) self.__linkify_ids_n(sub_ticket, data_summary) data_depend.append(LABEL_PRECEDING) self.__linkify_ids_p(tkt['dependencies'], data_depend) data_depend.append(LABEL_SUBSEQUENT) self.__linkify_ids_n(subsequentticket, data_depend) return {'summary_ticket': tag.span(*data_summary), 'dependencies': tag.span(*data_depend)}
def _do_account(self, req): assert(req.authname and req.authname != 'anonymous') action = req.args.get('action') delete_enabled = self.acctmgr.supports('delete_user') and \ self.acctmgr.allow_delete_account data = {'delete_enabled': delete_enabled, 'delete_msg_confirm': _( "Are you sure you want to delete your account?"), } force_change_password = req.session.get('force_change_passwd', False) if req.method == 'POST': if action == 'save': data.update(self._do_change_password(req)) if force_change_password: del(req.session['force_change_passwd']) req.session.save() chrome.add_notice(req, Markup(tag.span(tag_( "Thank you for taking the time to update your password." )))) force_change_password = False elif action == 'delete' and delete_enabled: data.update(self._do_delete(req)) else: data.update({'error': 'Invalid action'}) if force_change_password: chrome.add_warning(req, Markup(tag.span(_( "You are required to change password because of a recent " "password change request. "), tag.b(_("Please change your password now."))))) return data
def expand_macro(self, formatter, name, content, args): add_stylesheet(formatter.req, 'text_boxes/css/text_boxes.css') # TODO(holtgrew): Actually, we would like to add a style sheet but this does not work. Thus we use a style tag below. #add_stylesheet(formatter.req, 'text_boxes/css/text_boxes.css') className = CLASSES.get(name, 'ShellBox') if name in ['TextIcon']: args = trac.wiki.parse_args(content) if not args or not args[0]: # Handle case of empty entry. return None DEFAULT = 'gray' COLOR_CLASSES = ['green', 'red', 'yellow', 'black', 'gray', 'blue'] color_class_name = args[1].get('color', DEFAULT) if not color_class_name in COLOR_CLASSES: color_class_name = DEFAULT return tag.span(args[0], class_=('text_icon %s' % color_class_name)) elif name in ['MenuTrace']: args = trac.wiki.parse_args(content) if not args[0]: return None result = tag.span(args[0][0], class_='menu_item') for text in args[0][1:]: result += tag.span(u' \u25B8 ', class_='arrow') result += tag.span(text, class_='menu_item') return tag.span(result, class_='menu_trace') elif name in ['WarningBox', 'InfoBox', 'ImportantBox', 'AssignmentBox']: content_html = self.format_wiki(formatter, content) return tag.div(genshi.core.Markup(content_html), class_=className) else: return tag.pre(content, class_='wiki ' + className)
def prevnext_ctxnav(self, req, prev_label, next_label, up_label=None): links = req.chrome['links'] prev_link = next_link = None if not any(lnk in links for lnk in ('prev', 'up', 'next')): # Short circuit return if 'prev' in links: prev = links['prev'][0] prev_link = tag.a(prev_label, href=prev['href'], title=prev['title'], class_='prev') add_ctxtnav(req, tag.span('', prev_link or prev_label, id='leftarrow', class_=not prev_link and 'missing' or None)) if up_label and 'up' in links: up = links['up'][0] add_ctxtnav(req, tag.a(up_label, href=up['href'], title=up['title'])) if 'next' in links: next_ = links['next'][0] next_link = tag.a(next_label, href=next_['href'], title=next_['title'], class_='next') add_ctxtnav(req, tag.span(next_link or next_label, '', id='rightarrow', class_=not next_link and 'missing' or None))
def save(self, req): if req.args and req.args.has_key('action') \ and req.args['action'] == 'save': for key in SESSION_KEYS.values(): if req.args.has_key(key): if key == 'wiki.href': wiki_href = req.args[key] if wiki_href == '': req.session[key] = '' continue validated = WikiSystem(self.env).has_page(wiki_href) if validated: req.session[key] = req.args[key] else: add_warning(req, Markup(tag.span(Markup(_( "%(page)s is not a valid Wiki page", page=tag.b(wiki_href) ))))) elif key == 'tickets.href': ticket_href = req.args[key] if ticket_href == '': req.session[key] = '' continue reports = self.get_report_list() self.log.info('reports: %s' % reports) if ticket_href in ('report', 'query') \ or as_int(ticket_href, 0) in reports: req.session[key] = req.args[key] else: add_warning(req, Markup(tag.span(Markup(_( "%(report)s is not a valid report", report=tag.b(ticket_href) ))))) else: req.session[key] = req.args[key]
def format(self): if not self.changesets: message = _("No changesets for #%s" % self.tkt_id) yield tag.span(format_to_oneliner(self.env, self.context, message, shorten=False), class_='ticketchangesets hint') return n = len(self.changesets) ix = 0 # current index for adding separation markers between repos for (reponame, changesets) in self.changesets: if n > 1: if self.hint == 'ticket': if reponame and reponame != '(default)': yield tag.h3(reponame, class_='change') else: yield tag.h3(_("Default Repository"), class_='change') elif ix > 0: yield ', ' revs = changesets.wiki_revs(reponame, self.compact) log = changesets.wiki_log(reponame) message = revs + ' (' + log + ')' yield tag.span(format_to_oneliner(self.env, self.context, message, shorten=False), class_='ticketchangesets') ix += 1
def expand_macro(self, formatter, name, args): summary = [] # Lines with the summary, above the horizontal rule. body = [] # Lines with the body, below the horizontal rule. sawRule = False # Flag: Has seen a horizontal rule line. # Iterate over the lines in args and split at first line with a horizontal # rule. for line in args.splitlines(): if line.startswith('----'): sawRule = True continue if sawRule: body.append(line) else: summary.append(line) # Build HTML with summary and toggle'able body. hidden_id = uuid.uuid4() body_html = self.format_wiki(formatter, '\n'.join(body)) hidden = tag.div(genshi.core.Markup(body_html), id=hidden_id, style='display:none;') toggle_class = uuid.uuid4() toggle_js = genshi.core.Markup( u'$(\'#%s\').toggle();$(\'.%s\').toggle();return false;') % ( hidden_id, toggle_class) toggle_link = tag.a( tag.span(ARROW_RIGHT + ' more...', class_=toggle_class) + tag.span(ARROW_DOWN + ' less...', class_=toggle_class, style='display:none;'), onclick=toggle_js, href='#') summary_html = self.format_wiki(formatter, '\n'.join(summary)) return genshi.core.Markup( summary_html) + toggle_link + genshi.core.Markup(hidden)
def _ticket_links(env, formatter, t, a_class=''): """Build links to tickets.""" tkt_id = str(t.get('id')) status = t.get('status') summary = to_unicode(t.get('summary')) owner = to_unicode(t.get('owner')) description = to_unicode(t.get('description')) url = t.get('href') if status == 'closed': a_class = a_class + 'closed' else: a_class = a_class + 'open' # Reduce content for tooltips. markup = format_to_html(env, formatter.context, description) extractor = TextExtractor() extractor.feed(markup) tip = tag.span(shorten_line(extractor.getvalue())) ticket = tag.a('#' + tkt_id, href=url) ticket(tip, class_='tip', target='_blank') ticket = tag.div(ticket, class_=a_class, align='left') # Fix stripping of regular leading space in IE. blank = ' ' ticket(Markup(blank), summary, ' (', owner, ')') summary = tag(summary, ' (', owner, ')') ticket_short = tag.span(tag.a('#' + tkt_id, href=url, target='_blank', title_=summary), class_=a_class) return ticket, ticket_short
def createTicketLink(self, ticket, markupOn = True): ''' create a link to a ticket ''' tid = ticket.getfield('id') status = ticket.getfield('status') priority = ticket.getfield('priority') white = '#FFFFFF' # fallback color cssclass = 'ticket ticket_inner draggable' cssclassouter = '' style = '' if markupOn: if status == 'closed': cssclass += ' closed' elif status == 'in_QA': # enterprise workflow cssclass += ' in_QA' if self.macroenv.get_bool_arg('useimages', False ): cssclassouter += 'ppuseimages ' img = os.path.join( self.macroenv.tracreq.href.chrome( 'projectplan', self.macroenv.PPConstant.RelDocPath ), self.macroenv.conf.get_map_val('ImageForStatus', status) ) #self.macroenv.tracenv.log.debug('ppuseimages: '+repr(img)+' '+repr(status) ) style += 'background-image:url('+img+');' if self.macroenv.get_bool_arg('usecolors', False ): cssclassouter += 'ppusecolors ' #style += 'background-color: '+self.macroenv.conf.get_map_defaults('ColorForPriority', priority, white) style += 'background-color: '+self.macroenv.conf.get_map_val('ColorForPriority', priority ) return tag.span( tag.span( tag.a(tag.span('#%s'%(tid,), class_='ticketnr'), href=self.macroenv.tracenv.href.ticket(tid), class_ = cssclass, style = style ), class_ = cssclassouter ), class_ = 'ppticket' )
def _format_exomine_link(self, formatter, ns, target, label): # Wiki support for short exomine links: # exomine:3234 -> https://secure.exocad.com/exomine/issues/3234 # exomine:3234:12 -> https://secure.exocad.com/exomine/issues/3234#note-12 def get_url(ticket, comment=None): base_exomine_url = "" href = "https://secure.exocad.com/exomine/issues/{0}".format(ticket) if comment is not None: href += "#note-{0}".format(comment) return href try: if ":" in target: arr = target.split(":") if len(arr) == 2: href = get_url(arr[0], arr[1]) title = _("Comment %(cnum)s for exomine ticket #%(id)s", cnum=arr[1], id=arr[0]) return tag.a(tag.span(class_="icon") + label, href=href, title=title, class_="ext-link") else: href = get_url(target) title = _("exomine ticket #%(id)s", id=target) return tag.a(tag.span(class_="icon") + label, href=href, title=title, class_="ext-link") except ValueError: pass return tag.a(label, class_="unable to parse") # Todo: Add this class
def _render_ticket_event(self, field, context): if (field == 'url'): self._read_idx += 1 #next index now #call the original render function output = self._old_render_fn[self._read_idx](field, context) if field == 'title': #now it's time to insert the project name #split the whole string until we can insert splitted_output = to_unicode(output).split("</em>") tooltip = splitted_output[0].split('\"') ticket_no = splitted_output[0].split('>') if len(tooltip) == 3: #it's a ticket #now rebuild the puzzle by inserting the name output = tag( 'Ticket' + ' ', tag.em(ticket_no[1], title=tooltip[1]), ' ', tag.span(self._current_project[self._read_idx], style="background-color: #ffffd0;"), splitted_output[1]) elif len(tooltip) == 1 and len( splitted_output) == 3: #it's an attachment output += tag( ' ', tag.span(self._current_project[self._read_idx], style="background-color: #ffffd0;")) return output
def _render_property(self, name, mode, context, props): repos, revs = props[name] def link(rev): chgset = repos.get_changeset(rev) return tag.a(rev, class_="changeset", title=shorten_line(chgset.message), href=context.href.changeset(rev, repos.reponame)) if name == 'Parents' and len(revs) == 2: # merge new = context.resource.id parent_links = [ (link(rev), ' (', tag.a('diff', title=_("Diff against this parent " "(show the changes merged from the other parents)"), href=context.href.changeset(new, repos.reponame, old=rev)), ')') for rev in revs] return tag([(parent, ', ') for parent in parent_links[:-1]], parent_links[-1], tag.br(), tag.span(tag_("Note: this is a %(merge)s changeset, " "the changes displayed below correspond " "to the merge itself.", merge=tag.strong('merge')), class_='hint'), tag.br(), # TODO: only keep chunks present in both parents # (conflicts) or in none (extra changes) # tag.span('No changes means the merge was clean.', # class_='hint'), tag.br(), tag.span(tag_("Use the %(diff)s links above to see all " "the changes relative to each parent.", diff=tag.tt('(diff)')), class_='hint')) return tag([tag(link(rev), ', ') for rev in revs[:-1]], link(revs[-1]))
def _link_refs(self, req, refs_text, verbose_link=False): items_tag = None items, verbose_items = [], [] elem = verbose_elem = "#%s" % refs_text try: c = self.cursor c.execute("SELECT id,name FROM assets_feature WHERE id ='%s'" % refs_text) row = c.fetchone() if row: title = shorten_line(row[1]) attr = { "class_": "assigned", "href": "/splice/tractab/SPLICE/projects/feature/" + str(row[0]), "title": title, } elem = tag.a("#%s %s" % (refs_text, title), **attr) verbose_elem = tag.a("#%s %s" % (refs_text, title), **attr) except ResourceNotFound: pass # not supposed to happen, just in case items.extend([elem, ", "]) verbose_items.extend([verbose_elem, tag.br()]) if items: items_tag = [tag.span(items[:-1], id="tref_ticketid")] if verbose_link: vattr = {"id": "tref_summary", "class_": "tref-display-none"} items_tag.append(tag.span(verbose_items[:-1], **vattr)) return tag(items_tag)
def get_dependency_field_values(self, tkt): # post_process_requestから呼ばれる # 通常のチケット表示ページに使われる. self.load_intertrac_setting() tkt_id = str(tkt.id) tkt_id_l = self.__get_current_project_name() + ':#' + tkt_id sub_ticket = self.__get_tickets_point_to( \ self.__get_subticket_other_prj_alias \ (self.__get_current_project_name(), tkt_id), \ self.__get_subticket(tkt_id) ) subsequentticket = self.__get_tickets_point_to( \ self.__get_subsequentticket_other_prj_alias( \ self.__get_current_project_name(), tkt_id), \ self.__get_subsequentticket(tkt_id) ) data_summary = [] data_depend = [] data_summary.append(LABEL_SUMMARY) self.__linkify_ids_p(tkt['summary_ticket'], data_summary) data_summary.append(LABEL_SUB) self.__linkify_ids_n(sub_ticket, data_summary) data_depend.append(LABEL_PRECEDING) self.__linkify_ids_p(tkt['dependencies'], data_depend) data_depend.append(LABEL_SUBSEQUENT) self.__linkify_ids_n(subsequentticket, data_depend) return { 'summary_ticket': tag.span(*data_summary), 'dependencies': tag.span(*data_depend) }
def render_voter(self, req): resource = self.normalise_resource(req.path_info) vote = self.get_vote(req, resource) up = tag.img(src=req.href.chrome('vote/' + self.image_map[vote][0]), alt='Up-vote') down = tag.img(src=req.href.chrome('vote/' + self.image_map[vote][1]), alt='Down-vote') if 'VOTE_MODIFY' in req.perm and get_reporter_id(req) != 'anonymous': down = tag.a(down, id='downvote', href=req.href.vote('down', resource), title='Down-vote') up = tag.a(up, id='upvote', href=req.href.vote('up', resource), title='Up-vote') add_script(req, 'vote/js/tracvote.js') shown = req.session.get('shown_vote_message') if not shown: add_notice(req, 'You can vote for resources on this Trac ' 'install by clicking the up-vote/down-vote arrows ' 'in the context navigation bar.') req.session['shown_vote_message'] = '1' body, title = self.format_votes(resource) votes = tag.span(body, id='votes') add_stylesheet(req, 'vote/css/tracvote.css') elm = tag.span(up, votes, down, id='vote', title=title) req.chrome.setdefault('ctxtnav', []).insert(0, elm)
def expand_macro(self, formatter, name, args): args = tuple(args.split(',')) if len(args) == 2 : return tag.span(format_to_oneliner(self.env, formatter.context, args[1]), style='background-color: %s' % args[0]) else: return tag.span(format_to_oneliner(self.env, formatter.context, args[2]), style='background-color: %s; color: %s' % args[0:2])
def visit_classifier(self, node): ''' Classifier should remain beside the previous element ''' term = self.context.pop() term(' ', tag.span(':', class_='classifier-delimiter'), ' ', tag.span(node.astext(), class_='classifier')) self.context.append(term) raise nodes.SkipNode
def _gen_ticket_entry(self, t, a_class=''): id = str(t.get('id')) status = t.get('status') priority = t.get('priority') hours = t.get(self.hours_field_name) summary = to_unicode(t.get('summary')) owner = to_unicode(t.get('owner')) description = to_unicode(t.get('description')[:1024]) url = t.get('href') if status == 'closed': a_class = a_class + 'closed' else: a_class = a_class + 'open' a_class += " ticket priority-" + priority markup = format_to_html(self.env, self.ref.context, description) # Escape, if requested if self.sanitize is True: try: description = HTMLParser(StringIO(markup) ).parse() | HTMLSanitizer() except ParseError: description = escape(markup) else: description = markup # Replace tags that destruct tooltips too much desc = self.end_RE.sub(']', Markup(description)) desc = self.del_RE.sub('', desc) # need 2nd run after purging newline in table cells in 1st run desc = self.del_RE.sub('', desc) desc = self.item_RE.sub('X', desc) desc = self.tab_RE.sub('[|||]', desc) description = self.open_RE.sub('[', desc) tip = tag.span(Markup(description)) ticket = '#' + id ticket = tag.a(ticket, href=url) ticket(tip, class_='tip', target='_blank') ticket = tag.div(ticket) ticket(class_=a_class, align='left', **{"data-ticketid": id}) # fix stripping of regular leading space in IE blank = ' ' ticket(Markup(blank), summary, ' (', owner, ')') ticket(tag.span(str(hours) + "h", class_="hours")) summary = tag(summary, ' (', owner, ')') ticket_short = '#' + id ticket_short = tag.a(ticket_short, href=url) ticket_short(target='_blank', title_=summary) ticket_short = tag.span(ticket_short) ticket_short(class_=a_class) return ticket,ticket_short
def moreless(text, length): """Turns `text` into HTML code where everything behind `length` can be uncovered using a ''show more'' link and later covered again with a ''show less'' link.""" try: if len(text) <= length: return tag(text) except: return tag(text) return tag(tag.span(text[:length]),tag.a(' [', tag.strong(Markup('…')), ']', class_="more"), tag.span(text[length:],class_="moretext"),tag.a(' [', tag.strong('-'), ']', class_="less"))
def expand_macro(self, formatter, name, args): args = tuple(args.split(',')) if len(args) == 2: return tag.span(format_to_oneliner(self.env, formatter.context, args[1]), style='background-color: %s' % args[0]) else: return tag.span( format_to_oneliner(self.env, formatter.context, args[2]), style='background-color: %s; color: %s' % args[0:2])
def process_request(self, req): acctmgr = self.acctmgr if req.authname != 'anonymous': req.redirect(req.href.prefs('account')) action = req.args.get('action') name = req.args.get('name', '').strip() username = acctmgr.handle_username_casing(req.args.get('username', '').strip()) data = { '_dgettext': dgettext, 'acctmgr': dict(name=name, username=username), 'ignore_auth_case': self.config.getbool('trac', 'ignore_auth_case') } verify_enabled = is_enabled(self.env, EmailVerificationModule) and \ EmailVerificationModule(self.env).verify_email data['verify_account_enabled'] = verify_enabled if req.method == 'POST' and action == 'create': try: # Check request and prime account on success. acctmgr.validate_account(req, True) except RegistrationError, e: # Attempt deferred translation. message = gettext(e.message) # Check for (matching number of) message arguments before # attempting string substitution. if e.msg_args and \ len(e.msg_args) == len(re.findall('%s', message)): message = message % e.msg_args chrome.add_warning(req, Markup(message)) else: if self.require_approval: set_user_attribute(self.env, username, 'approval', N_('pending')) # Notify admin user about registration pending for review. acctmgr._notify('registration_approval_required', username) chrome.add_notice(req, Markup(tag.span(Markup(_( "Your username has been registered successfully, but " "your account requires administrative approval. " "Please proceed according to local policy.")))) ) if verify_enabled: chrome.add_notice(req, Markup(tag.span(Markup(_( """Your username has been successfully registered but your account still requires activation. Please login as user %(user)s, and follow the instructions.""", user=tag.b(username))))) ) req.redirect(req.href.login()) chrome.add_notice(req, Markup(tag.span(Markup(_( """Registration has been finished successfully. You may log in as user %(user)s now.""", user=tag.b(username))))) ) req.redirect(req.href.login())
def _create_milestone_item(self, milestone): icon = tag.span(tag.span('', class_='ui-icon %s' % self.mod.milestone_icon or ''), class_='ui-icon-w') anchor = tag.a(milestone.name, href=self.req.href('milestone', milestone.name)) item = tag.li(icon, anchor, style='background-color: %s;' % self.mod.milestone_background_color, class_='milestone') return item
def _render_conrol_panel(): return tag.div( tag.span( tag.a(' ', class_='link-expanded', href='#'), tag.a(_('Collapse Control Panel'), href='#')), tag.span( tag.a(' ',class_='link-collapsed', href='#'), tag.a(_('Expand Control Panel'), href='#'), style="display: none;"), class_='control-panel' )
def moreless(text, length): """Turns `text` into HTML code where everything behind `length` can be uncovered using a ''show more'' link and later covered again with a ''show less'' link.""" try: if len(text) <= length: return tag(text) except: return tag(text) return tag(tag.span(text[:length]), tag.a(' [', tag.strong(Markup('…')), ']', class_="more"), tag.span(text[length:], class_="moretext"), tag.a(' [', tag.strong('-'), ']', class_="less"))
def process_request(self, req): acctmgr = self.acctmgr if req.authname != 'anonymous': req.redirect(req.href.prefs('account')) action = req.args.get('action') name = req.args.get('name', '').strip() username = acctmgr.handle_username_casing( req.args.get('username', '').strip()) data = { '_dgettext': dgettext, 'acctmgr': dict(name=name, username=username), 'ignore_auth_case': self.config.getbool('trac', 'ignore_auth_case') } verify_enabled = is_enabled(self.env, EmailVerificationModule) and \ acctmgr.verify_email data['verify_account_enabled'] = verify_enabled if req.method == 'POST' and action == 'create': try: # Check request and prime account on success. acctmgr.validate_registration(req) except RegistrationError, e: # Attempt deferred translation. message = gettext(e.message) # Check for (matching number of) message arguments before # attempting string substitution. if e.msg_args and \ len(e.msg_args) == len(re.findall('%s', message)): message = message % e.msg_args chrome.add_warning(req, Markup(message)) else: if verify_enabled: chrome.add_notice( req, Markup( tag.span( Markup( _("""Your username has been successfully registered but your account still requires activation. Please login as user %(user)s, and follow the instructions.""", user=tag.b(username)))))) req.redirect(req.href.login()) chrome.add_notice( req, Markup( tag.span( Markup( _("""Registration has been finished successfully. You may log in as user %(user)s now.""", user=tag.b(username)))))) req.redirect(req.href.login())
def formattime(self, time): """Return formatted time for ListOfWikiPages table.""" time = int(time) return [ tag.span(format_datetime(time)), tag.span( " (", tag.a(pretty_timedelta(time), href=self.href('timeline', precision='seconds', from_=quote_plus( format_datetime(time, 'iso8601')))), " ago)") ]
def get_html(self, macroenv, req, content): def get_time(starttime, macroenv): ''' computes the computing time of the macro returned as HTML construct to be embeeded in HTML output ''' duration = (datetime.now() - starttime).microseconds / 1000 macroenv.tracenv.log.debug('macro computation time: %s ms: %s ' % (duration, macroenv.macrokw)) return (tag.span('It took %s ms to generate this visualization. ' % (duration, ), class_='ppstat')) #macroenv = PPEnv( env, req, content ) macrostart = datetime.now() if content == None: content = '' ts = ppFilter(macroenv).get_tickets() if macroenv.get_args('ppforcereload') == '1': noteForceReload = tag.span('The visualization was recreated.', class_='ppforcereloadinfo') else: noteForceReload = tag.span() renderer = ppRender(macroenv) # show text in the headline moretitle = '' macroenv.tracenv.log.debug( 'macroenv label=%s (%s)' % (macroenv.get_args('label'), macroenv.tracreq.args)) if macroenv.macrokw.get('label', None) != None: # use parameter: label moretitle = macroenv.macrokw.get('label', '') else: moretitle = renderer.getHeadline() # get the pre-defined headline return tag.div( tag.h5(tag.a(name=macroenv.macroid)('%s' % (moretitle, ))), renderer.render(ts), tag.div( tag.div( get_time(macrostart, macroenv), noteForceReload, tag.span( tag.a('Force recreation of the visualization.', href='?ppforcereload=1', class_='ppforcereload')))), style=macroenv.macrokw.get('style', '') # CSS style )
def expand_macro(self, formatter, name, content): argv, kwargs = parse_args(content, strict=False) # parse args and kwargs # Grab the format needed. if len(argv) > 0 and not 'format' in kwargs: # 0.10 compatibility hack kwargs['format'] = argv[0] fmt = kwargs.pop('format', 'list').strip().lower() # Get the requested fmt type kwargs['col'] = self._check_cols(kwargs.get( 'col', ''), fmt) # define the kwargs and set some defaults # Build the ticket query and retrieve the tickets. query_string = self._get_querystring( kwargs) # Construct the querystring. query = self._get_query(query_string) # Get the Query Object. tickets = self._get_tickets(query, formatter.req) # Get the tickets if not tickets: # If no tickets are returned return tag.span(("No results"), class_='query_no_results') # 'table' format had its own permission checks, here we need to # do it explicitly: if fmt != 'table': tickets = [ t for t in tickets if 'TICKET_VIEW' in formatter.req.perm('ticket', t['id']) ] # Return based on format requested. switch = { 'count': self._count_tickets(tickets), 'total': self._sp_total(tickets), 'completed': self._sp_completed(tickets), 'remaining': self._sp_remaining(tickets), 'storypoints': self._display_storypoints(tickets), 'list': self._display_list(tickets, kwargs['col'], formatter.req), 'compact': self._display_compact_list(tickets, formatter.req), 'table': self._display_table(tickets, formatter, query) } try: # little fall back if they select an unsupported format output = switch[fmt] except KeyError: output = tag.span(("Invalid output format: '%s'" % fmt), class_='error') return output
def formattime(self,time): """Return formatted time for ListOfWikiPages table.""" time = int(time) return [ tag.span( format_datetime ( time ) ), tag.span( " (", tag.a( pretty_timedelta ( time ), href = self.href('timeline', precision='seconds', from_= quote_plus( format_datetime (time,'iso8601') ) ) ), " ago)" ) ]
def _gen_ticket_entry(self, t, a_class=''): id = str(t.get('id')) status = t.get('status') summary = to_unicode(t.get('summary')) owner = to_unicode(t.get('owner')) description = to_unicode(t.get('description')[:1024]) url = t.get('href') if status == 'closed': a_class = a_class + 'closed' else: a_class = a_class + 'open' markup = format_to_html(self.env, self.ref.context, description) # Escape, if requested if self.sanitize is True: try: description = HTMLParser(StringIO(markup) ).parse() | HTMLSanitizer() except ParseError: description = escape(markup) else: description = markup # Replace tags that destruct tooltips too much desc = self.end_RE.sub(']', Markup(description)) desc = self.del_RE.sub('', desc) # need 2nd run after purging newline in table cells in 1st run desc = self.del_RE.sub('', desc) desc = self.item_RE.sub('X', desc) desc = self.tab_RE.sub('[|||]', desc) description = self.open_RE.sub('[', desc) tip = tag.span(Markup(description)) ticket = '#' + id ticket = tag.a(ticket, href=url) ticket(tip, class_='tip', target='_blank') ticket = tag.div(ticket) ticket(class_=a_class, align='left') # fix stripping of regular leading space in IE blank = ' ' ticket(Markup(blank), summary, ' (', owner, ')') summary = tag(summary, ' (', owner, ')') ticket_short = '#' + id ticket_short = tag.a(ticket_short, href=url) ticket_short(target='_blank', title_=summary) ticket_short = tag.span(ticket_short) ticket_short(class_=a_class) return ticket,ticket_short
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 prevnext_nav(req, label, uplabel=None): """Add Previous/Up/Next navigation links `req` a Request object `label` the label to use after the Previous/Next words `uplabel` the label to use for the Up link """ links = req.chrome['links'] if 'prev' not in links and \ 'up' not in links and \ 'next' not in links: # Short circuit return if 'prev' in links: link = links['prev'][0] add_ctxtnav(req, tag.span(Markup('← '), tag.a(_('Previous %(label)s', label=label), href=link['href'], title=link['title'], class_='prev' ))) else: add_ctxtnav(req, tag.span(Markup('← '), _('Previous %(label)s', label=label), class_='missing')) if uplabel and 'up' in links: link = links['up'][0] add_ctxtnav(req, tag.a(uplabel, href=link['href'], title=link['title'])) if 'next' in links: link = links['next'][0] add_ctxtnav(req, tag.span(tag.a(_('Next %(label)s', label=label), href=link['href'], title=link['title'], class_='next'), Markup(' →'))) else: add_ctxtnav(req, tag.span(_('Next %(label)s', label=label), Markup(' →'), class_='missing'))
def render_bookmarker(self, req): if 'action' in req.args and \ req.args['action'] in self.nonbookmarkable_actions: return resource = self._get_resource_uri(req) bookmark = self.get_bookmark(req, resource) if bookmark: class_ = 'bookmark_on' title = _('Delete Bookmark') href = req.href.bookmark('delete', resource) else: class_ = 'bookmark_off' title = _('Bookmark this page') href = req.href.bookmark('add', resource) anchor = tag.a(u'\u200b', id='bookmark_this', class_=class_, title=title, href=href, data_list=req.href.bookmark()) req.chrome.setdefault('ctxtnav', []).insert(0, anchor) add_script(req, 'bookmark/js/tracbookmark.js') add_stylesheet(req, 'bookmark/css/tracbookmark.css') menu = self._get_bookmarks_menu(req) item = tag.span(tag.a(_('Bookmarks'), href=req.href.bookmark()), menu, id='bookmark_menu') add_ctxtnav(req, item)
def render_reviewlink(self, req): #add_stylesheet(req, 'icucodetools/css/icuxtn.css') els = [] ticket_mgr = TicketManager(self.compmgr) db = self.env.get_db_cnx() repos = self.env.get_repository() if not repos: raise TracError("Could not get repository for %s" % (req.authname)) revs = ticket_mgr.tkt2revs(self.log, db, repos, req, req.args['ticket']) if not revs: str = 'No commits.' li = tag.li(str) els.append(li) else: str = ' %d commits.' % len(revs) href = req.href.review(req.args['ticket']) a = tag.a('Review', href=href) li = tag.li(a + str) els.append(li) ul = tag.ul(els, class_='review') className = '' title = "Reviews" add_ctxtnav(req, tag.span(tag.object(ul), id='icureview', title=title, class_=className))
def post_process_request(self, req, template, data, content_type): if not req.session.authenticated: # Don't start the email verification procedure on anonymous users. return template, data, content_type email = req.session.get('email') # Only send verification if the user entered an email address. if self.verify_email and self.email_enabled is True and email and \ email != req.session.get('email_verification_sent_to') and \ not req.perm.has_permission('ACCTMGR_ADMIN'): req.session['email_verification_token'] = self._gen_token() req.session['email_verification_sent_to'] = email AccountManager(self.env)._notify( 'email_verification_requested', req.authname, req.session['email_verification_token'] ) # TRANSLATOR: An email has been sent to <%(email)s> # with a token to ... (the link label for following message) link = tag.a(_("verify your new email address"), href=req.href.verify_email() ) # TRANSLATOR: ... verify your new email address chrome.add_notice(req, Markup(tag.span(Markup(_( """An email has been sent to <%(email)s> with a token to %(link)s.""", email=email, link=link)))) ) return template, data, content_type
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 pretty_dateinfo(date, format=None, dateonly=False): if not date: return '' if format == 'date': absolute = user_time(req, format_date, date) else: absolute = user_time(req, format_datetime, date) now = datetime.datetime.now(localtz) relative = pretty_timedelta(date, now) if not format: format = req.session.get('dateinfo', self.default_dateinfo_format) in_or_ago = _("in %(relative)s", relative=relative) \ if date > now else \ _("%(relative)s ago", relative=relative) if format == 'relative': label = in_or_ago if not dateonly else relative title = absolute else: if dateonly: label = absolute elif req.lc_time == 'iso8601': label = _("at %(iso8601)s", iso8601=absolute) else: label = _("on %(date)s at %(time)s", date=user_time(req, format_date, date), time=user_time(req, format_time, date)) title = in_or_ago return tag.span(label, title=title)
def process_request(self, req): if not req.session.authenticated: chrome.add_warning( req, Markup( tag.span( tag_( "Please log in to finish email verification procedure." )))) req.redirect(req.href.login()) if 'email_verification_token' not in req.session: chrome.add_notice(req, _("Your email is already verified.")) elif req.method == 'POST' and 'resend' in req.args: AccountManager(self.env)._notify( 'email_verification_requested', req.authname, req.session['email_verification_token']) chrome.add_notice( req, _("A notification email has been resent to <%s>."), req.session.get('email')) elif 'verify' in req.args: # allow via POST or GET (the latter for email links) if req.args['token'] == req.session['email_verification_token']: del req.session['email_verification_token'] chrome.add_notice( req, _("Thank you for verifying your email address.")) req.redirect(req.href.prefs()) else: chrome.add_warning(req, _("Invalid verification token")) data = {'_dgettext': dgettext} if 'token' in req.args: data['token'] = req.args['token'] if 'email_verification_token' not in req.session: data['button_state'] = {'disabled': 'disabled'} return 'verify_email.html', data, None
def post_process_request(self, req, template, data, content_type): if not req.session.authenticated: # Don't start the email verification precedure on anonymous users. return template, data, content_type email = req.session.get('email') # Only send verification if the user entered an email address. acctmgr = AccountManager(self.env) if acctmgr.verify_email and self.email_enabled is True and email and \ email != req.session.get('email_verification_sent_to') and \ not req.perm.has_permission('ACCTMGR_ADMIN'): req.session['email_verification_token'] = self._gen_token() req.session['email_verification_sent_to'] = email acctmgr._notify('email_verification_requested', req.authname, req.session['email_verification_token']) # TRANSLATOR: An email has been sent to %(email)s # with a token to ... (the link label for following message) link = tag.a(_("verify your new email address"), href=req.href.verify_email()) # TRANSLATOR: ... verify your new email address chrome.add_notice( req, Markup( tag.span( Markup( _("""An email has been sent to %(email)s with a token to %(link)s.""", email=email, link=link))))) return template, data, content_type
def process_request(self, req): if req.authname != 'anonymous': req.redirect(req.href.prefs('account')) action = req.args.get('action') data = { 'acctmgr': { 'username': None, 'name': None, 'email': None, }, '_dgettext': dgettext, } data['verify_account_enabled'] = is_enabled( self.env, EmailVerificationModule) and self.acctmgr.verify_email if req.method == 'POST' and action == 'create': try: _create_user(req, self.env) except TracError, e: data['registration_error'] = e.message data['acctmgr'] = getattr(e, 'acctmgr', '') else: chrome.add_notice( req, Markup( tag.span( Markup( _("""Registration has been finished successfully. You may login as user %(user)s now.""", user=tag.b(req.args.get('username'))))))) req.redirect(req.href.login())
def render_reviewlink(self, req): """Render the "143 commits." box that shows in the topnav.""" #add_stylesheet(req, 'icucodetools/css/icuxtn.css') els = [] ticket_mgr = TicketManager(self.compmgr) db = self.env.get_db_cnx() repos = self.env.get_repository() if not repos: raise TracError("Could not get repository for %s" % (req.authname)) revs = ticket_mgr.tkt2revs(self.log, db, repos, req, req.args['ticket']) if not revs: str = 'No commits.' li = tag.li(str) els.append(li) else: str = ' %d commits.' % len(revs) href = req.href.review(req.args['ticket']) a = tag.a('Review' + str, href=href) li = tag.li(a) els.append(li) ul = tag.ul(els, class_='review') className = '' title = "Reviews" add_ctxtnav(req, tag.span(ul, id='icureview', title=title, class_=className))
def expand_macro(self, formatter, name, content): attachment_type = "" if content: argv = [arg.strip() for arg in content.split(',')] if len(argv) > 0: attachment_type = argv[0] db = self.env.get_db_cnx() if db == None: return "No DB connection" attachmentFormattedList="" cursor = db.cursor() if attachment_type == None or attachment_type == "": cursor.execute("SELECT type,id,filename,size,time," "description,author,ipnr FROM attachment") else: cursor.execute("SELECT type,id,filename,size,time," "description,author,ipnr FROM attachment " "WHERE type=%s", (attachment_type, )) formatters={"wiki": formatter.href.wiki, "ticket": formatter.href.ticket} types={"wiki": "", "ticket": "ticket "} return tag.ul( [tag.li( tag.a(filename, href=formatter.href.attachment(type + "/" + id + "/" + filename)), " (", tag.span(pretty_size(size), title=size), ") - added by ", tag.em(author), " to ", tag.a(types[type] + " " + id, href=formatters[type](id)), " ") for type,id,filename,size,time,description,author,ipnr in cursor if self._has_perm(type, id, filename, formatter.context)]) return attachmentFormattedList
def expand_macro(self, formatter, name, content, args=None): style_args = {'fg': 'color', 'bg': 'background-color', 'size': 'font-size'} style_values = {'color': '', 'background-color': '', 'font-size': ''} space_start = '' space_end = '' if args: text = content for k in args.keys(): style = style_args[k] if k in style_args else k style_values[style] = args.get(k) html = format_to_html(self.env, formatter.context, text) else: args = content.split(',') text = ','.join(args[:-1]) args = args[-1].split('/') + ['']*3 style_values['color'] = args.pop(0).strip() # background color is optional arg = args.pop(0).strip() if len(arg) > 0 and arg[0].isdigit(): style_values['font-size'] = arg else: style_values['background-color'] = arg style_values['font-size'] = args.pop(0).strip() html = format_to_oneliner(self.env, formatter.context, text) if text.startswith(u' '): space_start = Markup(' ') if text.endswith(u' '): space_end = Markup(' ') if style_values['font-size'].isdigit(): style_values['font-size'] += '%' style = ';'.join('%s:%s' % (k, v) for (k, v) in style_values.iteritems() if v) return tag.span(space_start, html, space_end, style=style)
def process_request(self, req): if not req.session.authenticated: chrome.add_warning(req, Markup(tag.span(tag_( "Please log in to finish email verification procedure."))) ) req.redirect(req.href.login()) if 'email_verification_token' not in req.session: chrome.add_notice(req, _("Your email is already verified.")) elif req.method == 'POST' and 'resend' in req.args: AccountManager(self.env)._notify( 'email_verification_requested', req.authname, req.session['email_verification_token'] ) chrome.add_notice(req, _("A notification email has been resent to <%s>."), req.session.get('email') ) elif 'verify' in req.args: # allow via POST or GET (the latter for email links) if req.args['token'] == req.session['email_verification_token']: del req.session['email_verification_token'] chrome.add_notice( req, _("Thank you for verifying your email address.") ) req.redirect(req.href.prefs()) else: chrome.add_warning(req, _("Invalid verification token")) data = {'_dgettext': dgettext} if 'token' in req.args: data['token'] = req.args['token'] if 'email_verification_token' not in req.session: data['button_state'] = { 'disabled': 'disabled' } return 'verify_email.html', data, None
def _format_reminder(self, req, ticket, id, time, author, origin, description, delete_button=True): now = to_datetime(None) time = to_datetime(time) if now >= time: when = tag(tag.strong("Right now"), " (pending)") else: when = tag("In ", tag.strong(pretty_timedelta(time)), " (", format_date(time), ")") if description: context = Context.from_request(req, ticket.resource) desc = tag.div(format_to_oneliner(self.env, context, description), class_="description") else: desc = tag() return tag( self._reminder_delete_form(req, id) if delete_button else None, when, " - added by ", tag.em(Chrome(self.env).authorinfo(req, author)), " ", tag.span(pretty_timedelta(origin), title=format_datetime( origin, req.session.get('datefmt', 'iso8601'), req.tz)), " ago.", desc)