def render_timeline_event(self, context, field, event): bp_resource, bp, bc = event[3] compat_format_0_11_2 = 'oneliner' if hasattr(context, '_hints'): compat_format_0_11_2 = None if bc: # A blog comment if field == 'url': return context.href.blog(bp.name) + '#comment-%d' % bc.number elif field == 'title': return tag('Blog: ', tag.em(bp.title), ' comment added') elif field == 'description': comment = compat_format_0_11_2 and shorten_line(bc.comment) \ or bc.comment return format_to(self.env, compat_format_0_11_2, context(resource=bp_resource), comment) else: # A blog post if field == 'url': return context.href.blog(bp.name) elif field == 'title': return tag('Blog: ', tag.em(bp.title), bp.version > 1 and ' edited' or ' created') elif field == 'description': comment = compat_format_0_11_2 and shorten_line(bp.version_comment) \ or bp.version_comment return format_to(self.env, compat_format_0_11_2, context(resource=bp_resource), comment)
def short_value(self): if self.is_scalar: if isinstance(self.value, basestring): value = self.value if not isinstance(self.value, unicode): value = unicode(self.value, 'utf-8', 'replace') return tag.q(shorten_line(value, 60)).generate() else: return shorten_line(repr(self.value), 60) elif self.is_collection: if isinstance(self.value, (dict, DictMixin)): return u'{…}' elif isinstance(self.value, list): return u'[…]' elif isinstance(self.value, tuple): return u'(…)' elif isinstance(self.value, set): return u'set([…])' elif isinstance(self.value, frozenset): return u'frozenset([…])' else: try: return tag.code(shorten_line(str(self.value), 60)) except: return '?'
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 render_timeline_event(self, context, field, event): ticket,summary,status,resolution,type, started, comment = event[4] if field == 'url': return context.href.ticket(ticket.id) elif field == 'title': title = TicketSystem(self.env).format_summary(summary, status, resolution, type) return tag('Work ', started and 'stopped' or 'started', ' on Ticket ', tag.em('#', ticket.id, title=title), ' (', shorten_line(summary), ') ') elif field == 'description': if self.config['timeline'].getbool('abbreviated_messages'): comment = shorten_line(comment) markup = format_to_oneliner(self.env, context(resource=ticket), comment) return markup
def train(self, req, log_id, spam=True): environ = {} for name, value in req.environ.items(): if not name.startswith('HTTP_'): environ[name] = value entry = LogEntry.fetch(self.env, log_id) if entry: self.log.debug('Marking as %s: %r submitted by "%s"', spam and 'spam' or 'ham', shorten_line(entry.content), entry.author) fakeenv = environ.copy() for header in entry.headers.splitlines(): name, value = header.split(':', 1) if name == 'Cookie': # breaks SimpleCookie somehow continue cgi_name = 'HTTP_%s' % name.strip().replace('-', '_').upper() fakeenv[cgi_name] = value.strip() fakeenv['REQUEST_METHOD'] = 'POST' fakeenv['PATH_INFO'] = entry.path fakeenv['wsgi.input'] = StringIO('') fakeenv['REMOTE_ADDR'] = entry.ipnr if entry.authenticated: fakeenv['REMOTE_USER'] = entry.author for strategy in self.strategies: strategy.train(Request(fakeenv, None), entry.author or 'anonymous', entry.content, spam=spam) entry.update(rejected=spam)
def get_search_results(self, req, terms, filters): """ Search through requirements. The search term may be <x y z> or x-y-z; both are interpreted as component, fp, and object. """ if not 'requirement' in filters: return if re.match(r'^([a-zA-Z_\d]+)-([a-zA-Z_\d]+)-([a-zA-Z_\d]+)$', terms[0]): terms = string.split(terms[0], '-') db = self.env.get_db_cnx() sql, args = search_to_sql(db, ['b.newvalue'], terms) sql2, args2 = search_to_sql(db, ['a.component', 'a.fp', 'a.object', 'a.description', 'a.creator'], terms) cursor = db.cursor() cursor.execute("SELECT DISTINCT a.component, a.fp, a.object, " "a.description, a.creator, a.time " "FROM requirement a " "LEFT JOIN requirement_change b " "ON a.component = b.component AND a.fp = b.fp AND a.object = b.object " "WHERE (b.field='comment' AND %s ) OR %s" % (sql, sql2), args + args2) for component, fp, object, desc, creator, date in cursor: requirement = '<%s %s %s> ' % (component, fp, object) yield (req.href.requirement('%s-%s-%s' % (component, fp, object)), requirement + shorten_line(desc), date, creator, shorten_result(desc, terms))
def get_search_results(self, req, terms, filters): if not 'wiki' in filters: return db = self.env.get_db_cnx() sql_query, args = search_to_sql(db, ['w1.name', 'w1.author', 'w1.text'], terms) cursor = db.cursor() cursor.execute("SELECT w1.name,w1.time,w1.author,w1.text " "FROM wiki w1," "(SELECT name,max(version) AS ver " "FROM wiki GROUP BY name) w2 " "WHERE w1.version = w2.ver AND w1.name = w2.name " "AND " + sql_query, args) wiki_realm = Resource('wiki') for name, ts, author, text in cursor: page = wiki_realm(id=name) if 'WIKI_VIEW' in req.perm(page): yield (get_resource_url(self.env, page, req.href), '%s: %s' % (name, shorten_line(text)), datetime.fromtimestamp(ts, utc), author, shorten_result(text, terms)) # Attachments for result in AttachmentModule(self.env).get_search_results( req, wiki_realm, terms): yield result
def changeset_added(self, repos, changeset): """Called after a changeset has been added to a repository.""" #Index the commit message so = FullTextSearchObject( self.project, changeset.resource, title=u'[%s]: %s' % (changeset.rev, shorten_line(changeset.message)), oneline=shorten_result(changeset.message), body=changeset.message, author=changeset.author, created=changeset.date, changed=changeset.date, ) self.backend.create(so, quiet=True) self._update_changeset(changeset) # Index the file contents of this revision, a changeset can involve # thousands of files - so submit in batches to avoid exceeding the # available file handles sos = (so for so in self._changes(repos, changeset)) for chunk in grouper(sos, 25): try: self.backend.add(chunk, quiet=True) self.log.debug("Indexed %i repository changes at revision %i", len(chunk), changeset.rev) finally: for so in chunk: if hasattr(so.body, 'close'): so.body.close()
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 _format_sha_link(self, formatter, sha, label): # FIXME: this function needs serious rethinking... reponame = '' context = formatter.context while context: if context.resource.realm in ('source', 'changeset'): reponame = context.resource.parent.id break context = context.parent try: repos = RepositoryManager(self.env).get_repository(reponame) if not repos: raise Exception("Repository '%s' not found" % reponame) sha = repos.normalize_rev(sha) # in case it was abbreviated changeset = repos.get_changeset(sha) return tag.a(label, class_='changeset', title=shorten_line(changeset.message), href=formatter.href.changeset(sha, repos.reponame)) except Exception as e: return tag.a(label, class_='missing changeset', title=to_unicode(e), rel='nofollow')
def get_search_results(self, req, terms, filters): if not 'wiki' in filters: return with self.env.db_query as db: sql_query, args = search_to_sql( db, ['w1.name', 'w1.author', 'w1.text'], terms) wiki_realm = Resource('wiki') for name, ts, author, text in db( """ SELECT w1.name, w1.time, w1.author, w1.text FROM wiki w1,(SELECT name, max(version) AS ver FROM wiki GROUP BY name) w2 WHERE w1.version = w2.ver AND w1.name = w2.name AND """ + sql_query, args): page = wiki_realm(id=name) if 'WIKI_VIEW' in req.perm(page): yield (get_resource_url(self.env, page, req.href), '%s: %s' % (name, shorten_line(text)), from_utimestamp(ts), author, shorten_result(text, terms)) # Attachments for result in AttachmentModule(self.env).get_search_results( req, wiki_realm, terms): yield result
def _link_tickets(self, req, tickets, fetch_tickets=False): items = [] for i, word in enumerate(re.split(r'([;,\s]+)', tickets or '')): if i % 2: items.append(word) elif word: try: ticketid = int(word) except ValueError: return None word = '#%s' % word if fetch_tickets: try: ticket = Ticket(self.env, ticketid) if 'TICKET_VIEW' in req.perm(ticket.resource): word = \ tag.a( '#%s' % ticket.id, class_=ticket['status'], href=req.href.ticket(int(ticket.id)), title=shorten_line(ticket['summary']) ) except ResourceNotFound: pass items.append(word) if items: return tag(items) else: return None
def _format_changeset_link(self, formatter, ns, chgset, label, fullmatch=None): intertrac = formatter.shorthand_intertrac_helper( ns, chgset, label, fullmatch) if intertrac: return intertrac chgset, params, fragment = formatter.split_link(chgset) sep = chgset.find('/') if sep > 0: rev, path = chgset[:sep], chgset[sep:] else: rev, path = chgset, None if 'CHANGESET_VIEW' in formatter.perm('changeset', rev): try: changeset = self.env.get_repository().get_changeset(rev) title = shorten_line(changeset.message) except TracError, e: title = None href = self._format_gitorious(path=path, rev=rev, obj_type="changeset") return tag.a(label, class_="changeset", href=href, title=title)
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 _link_tickets(self, req, tickets): items = [] for i, word in enumerate(re.split(r'([;,\s]+)', tickets)): if i % 2: items.append(word) elif word: ticketid = word word = '#%s' % word try: ticket = Ticket(self.env, ticketid) if 'TICKET_VIEW' in req.perm(ticket.resource): word = \ tag.a( '#%s' % ticket.id, class_=ticket['status'], href=req.href.ticket(int(ticket.id)), title=shorten_line(ticket['summary']) ) except ResourceNotFound: pass items.append(word) if items: return tag(items) else: return None
def format_summary(self, summary, status=None, resolution=None, type=None): summary = shorten_line(summary) if type: summary = type + ': ' + summary if status: if status == 'closed' and resolution: status += ': ' + resolution return "%s (%s)" % (summary, status) else: return summary
def render_timeline_event(self, context, field, event): bp_resource, bp, bc = event[3] compat_format_0_11_2 = "oneliner" if hasattr(context, "_hints"): compat_format_0_11_2 = None if bc: # A blog comment if field == "url": return context.href.blog(bp.name) + "#comment-%d" % bc.number elif field == "title": return tag("Blog: ", tag.em(bp.title), " comment added") elif field == "description": comment = compat_format_0_11_2 and shorten_line(bc.comment) or bc.comment return format_to(self.env, compat_format_0_11_2, context(resource=bp_resource), comment) else: # A blog post if field == "url": return context.href.blog(bp.name) elif field == "title": return tag("Blog: ", tag.em(bp.title), bp.version > 1 and " edited" or " created") elif field == "description": comment = compat_format_0_11_2 and shorten_line(bp.version_comment) or bp.version_comment return format_to(self.env, compat_format_0_11_2, context(resource=bp_resource), comment)
def _index_milestone(self, milestone): so = FullTextSearchObject( self.project, milestone.resource, title=u"%s: %s" % (milestone.name, shorten_line(milestone.description)), changed=milestone.completed or milestone.due or datetime.now(utc), involved=(), popularity=0, # FIXME oneline=shorten_result(milestone.description), body=milestone.description, ) self.backend.create(so, quiet=True)
def _link_textarea(self, req, refs_text): items = [] for ref_id in sorted(cnv_text2list(refs_text)): elem = u"#%s" % ref_id try: ticket = Ticket(self.env, ref_id) if "TICKET_VIEW" in req.perm(ticket.resource): title = shorten_line(ticket["summary"]) elem = u"#%s %s" % (ref_id, title) except ResourceNotFound: pass # not supposed to happen, just in case items.extend([elem, u", "]) return u"".join(item for item in items[:-1])
def test(self, req, author, content, ip): i = req.args.getfirst(self.name) h = req.args.getfirst(self.name_hidden) r = self.getlink(req) if i and h: i = shorten_line(javascript_quote(i), 50) h = shorten_line(javascript_quote(h), 50) return -abs(self.karma_points), \ N_("Both trap fields says this is spam (%s, %s)"), i, h elif i: i = shorten_line(javascript_quote(i), 50) return -abs(self.karma_points), \ N_("Invisible trap field says this is spam (%s)"), i elif h: h = shorten_line(javascript_quote(h), 50) return -abs(self.karma_points), \ N_("Hidden trap field says this is spam (%s)"), h elif r: r = shorten_line(javascript_quote(r), 50) return -abs(self.karma_points), \ N_("Register trap field starts with HTTP URL (%s)"), r
def _link(resource): if resource.realm == 'tag': # Keep realm selection in tag links. return builder.a(resource.id, href=self.get_href(req, tag=resource)) elif resource.realm == 'ticket': # Return resource link including ticket status dependend # class to allow for common Trac ticket link style. ticket = Ticket(env, resource.id) return builder.a('#%s' % ticket.id, class_=ticket['status'], href=formatter.href.ticket(ticket.id), title=shorten_line(ticket['summary'])) return render_resource_link(env, context, resource, 'compact')
def render_property(self, name, mode, context, props): repos, value = props[name] if name == 'transplant_source': try: chgset = MercurialChangeset(repos, value) link = tag.a(chgset.rev, class_="changeset", title=shorten_line(chgset.message), href=context.href.changeset(short(value), repos.reponame)) except LookupError: link = tag.a(hex(value), class_="missing changeset", title=_("no such changeset"), rel="nofollow") return RenderedProperty(name=_("Transplant:"), content=link, name_attributes=[("class", "property")])
def milestone_created(self, milestone): so = FullTextSearchObject( self.project, milestone.resource, title=u'%s: %s' % (milestone.name, shorten_line(milestone.description)), changed=milestone.completed or milestone.due or datetime.now(utc), involved=(), popularity=0, #FIXME oneline=shorten_result(milestone.description), body=milestone.description, ) self.backend.create(so, quiet=True) self.log.debug("Milestone created for indexing: %s", milestone)
def get_timeline_events(self, req, start, stop, filters): if 'changeset' in filters: format = req.args.get('format') wiki_format = self.wiki_format_messages show_files = self.timeline_show_files db = self.env.get_db_cnx() repos = self.env.get_repository(req.authname) for chgset in repos.get_changesets(start, stop): message = chgset.message or '--' if wiki_format: shortlog = wiki_to_oneliner(message, self.env, db, shorten=True) else: shortlog = shorten_line(message) if format == 'rss': title = Markup(u'변경사항 [%s]: %s', chgset.rev, shortlog) href = req.abs_href.changeset(chgset.rev) if wiki_format: message = wiki_to_html(message, self.env, req, db, absurls=True) else: message = html.PRE(message) else: title = Markup(u'변경사항 <em>[%s]</em> : %s에 의해 수정됨', chgset.rev, chgset.author) href = req.href.changeset(chgset.rev) if wiki_format: if self.timeline_long_messages: message = wiki_to_html(message, self.env, req, db, absurls=True) else: message = wiki_to_oneliner(message, self.env, db, shorten=True) else: message = shortlog if show_files and req.perm.has_permission('BROWSER_VIEW'): files = [] for chg in chgset.get_changes(): if show_files > 0 and len(files) >= show_files: files.append(html.LI(Markup('…'))) break files.append(html.LI(html.DIV(class_=chg[2]), chg[0] or '/')) message = html.UL(files, class_="changes") + message yield 'changeset', href, title, chgset.date, chgset.author,\ message
def get_timeline_events(self, req, start, stop, filters): if 'changeset' in filters: format = req.args.get('format') wiki_format = self.wiki_format_messages show_files = self.timeline_show_files db = self.env.get_db_cnx() repos = self.env.get_repository(req.authname) for chgset in repos.get_changesets(start, stop): message = chgset.message or '--' if wiki_format: shortlog = wiki_to_oneliner(message, self.env, db, shorten=True) else: shortlog = shorten_line(message) if format == 'rss': title = Markup('Changeset [%s]: %s', chgset.rev, shortlog) href = req.abs_href.changeset(chgset.rev) if wiki_format: message = wiki_to_html(message, self.env, req, db, absurls=True) else: message = html.PRE(message) else: title = Markup('Changeset <em>[%s]</em> by %s', chgset.rev, chgset.author) href = req.href.changeset(chgset.rev) if wiki_format: if self.timeline_long_messages: message = wiki_to_html(message, self.env, req, db, absurls=True) else: message = wiki_to_oneliner(message, self.env, db, shorten=True) else: message = shortlog if show_files and req.perm.has_permission('BROWSER_VIEW'): files = [] for chg in chgset.get_changes(): if show_files > 0 and len(files) >= show_files: files.append(html.LI(Markup('…'))) break files.append(html.LI(html.DIV(class_=chg[2]), chg[0] or '/')) message = html.UL(files, class_="changes") + message yield 'changeset', href, title, chgset.date, chgset.author,\ message
def get_changes(env, repos, revs, full=None, req=None, format=None): db = env.get_db_cnx() changes = {} for rev in revs: try: changeset = repos.get_changeset(rev) except NoSuchChangeset: changes[rev] = {} continue wiki_format = env.config['changeset'].getbool('wiki_format_messages') message = changeset.message or '--' absurls = (format == 'rss') if wiki_format: shortlog = wiki_to_oneliner(message, env, db, shorten=True, absurls=absurls) else: shortlog = Markup.escape(shorten_line(message)) if full: if wiki_format: message = wiki_to_html(message, env, req, db, absurls=absurls, escape_newlines=True) else: message = html.PRE(message) else: message = shortlog if format == 'rss': if isinstance(shortlog, Markup): shortlog = shortlog.plaintext(keeplinebreaks=False) message = unicode(message) changes[rev] = { 'date_seconds': changeset.date, 'date': format_datetime(changeset.date), 'age': pretty_timedelta(changeset.date), 'author': changeset.author or 'anonymous', 'message': message, 'shortlog': shortlog, } return changes
def get_search_results(self, req, terms, filters): if not 'changeset' in filters: return repos = self.env.get_repository(req.authname) db = self.env.get_db_cnx() sql, args = search_to_sql(db, ['message', 'author'], terms) cursor = db.cursor() cursor.execute("SELECT rev,time,author,message " "FROM revision WHERE " + sql, args) for rev, date, author, log in cursor: if not repos.authz.has_permission_for_changeset(rev): continue yield (req.href.changeset(rev), '[%s]: %s' % (rev, shorten_line(log)), date, author, shorten_result(log, terms))
def _link_ticket_by_id(self, req, ticketid): ret = None try: ticket = Ticket(self.env, ticketid) if 'TICKET_VIEW' in req.perm(ticket.resource): ret = \ tag.a( '#%s' % ticket.id, class_=ticket['status'], href=req.href.ticket(int(ticket.id)), title=shorten_line(ticket['summary']) ) except ResourceNotFound: pass return ret
def _format_revision_link(self, formatter, ns, reponame, rev, label, fullmatch=None): rev, params, fragment = formatter.split_link(rev) try: repos = RepositoryManager(self.env).get_repository(reponame) if repos: changeset = repos.get_changeset(rev) return tag.a(label, class_="changeset", title=shorten_line(changeset.message), href=(formatter.href.changeset(rev) + params + fragment)) except NoSuchChangeset: pass return tag.a(label, class_="missing changeset", rel="nofollow", href=formatter.href.changeset(rev))
def changeset_added(self, repos, changeset): """Called after a changeset has been added to a repository.""" #Index the commit message so = FullTextSearchObject( self.project, changeset.resource, title=u'[%s]: %s' % (changeset.rev, shorten_line(changeset.message)), oneline=shorten_result(changeset.message), body=changeset.message, author=changeset.author, created=changeset.date, changed=changeset.date, ) self.backend.create(so, quiet=True) self._update_changeset(changeset)
def format_subj(self, tickets_descr): template = self.config.get('notification', 'batch_subject_template') template = NewTextTemplate(template.encode('utf8')) prefix = self.config.get('notification', 'smtp_subject_prefix') if prefix == '__default__': prefix = '[%s]' % self.env.project_name data = { 'prefix': prefix, 'tickets_descr': tickets_descr, 'env': self.env, } subj = template.generate(**data).render('text', encoding=None).strip() return shorten_line(subj)
def _pydoc_formatter(self, formatter, ns, object, label): object = urllib.unquote(object) label = urllib.unquote(label) if not object or object == 'index': return html.a(label, class_='wiki', href=formatter.href.pydoc()) else: try: _, target = PyDoc(self.env).load_object(object) doc = pydoc.getdoc(target) if doc: doc = doc.strip().splitlines()[0] return html.a(label, class_='wiki', title=shorten_line(doc), href=formatter.href.pydoc(object)) except ImportError: return html.a(label, class_='missing wiki', href=formatter.href.pydoc(object))
def add_bulk_changesets(self, changesets): sos = [] for changeset in changesets: so = FullTextSearchObject( self.project, changeset.resource, title=u'[%s]: %s' % (changeset.rev, shorten_line(changeset.message)), oneline=shorten_result(changeset.message), body=changeset.message, author=changeset.author, created=changeset.date, changed=changeset.date, ) self._update_changeset(changeset) sos.append(so) self.backend.add(sos, quiet=True)
def get_search_results(self, req, terms, filters): if not 'wiki' in filters: return db = self.env.get_db_cnx() sql_query, args = search_to_sql(db, ['w1.name', 'w1.author', 'w1.text'], terms) cursor = db.cursor() cursor.execute("SELECT w1.name,w1.time,w1.author,w1.text " "FROM wiki w1," "(SELECT name,max(version) AS ver " "FROM wiki GROUP BY name) w2 " "WHERE w1.version = w2.ver AND w1.name = w2.name " "AND " + sql_query, args) for name, date, author, text in cursor: yield (req.href.wiki(name), '%s: %s' % (name, shorten_line(text)), date, author, shorten_result(text, terms))
def _format_subj_batchmodify(self, tickets): tickets_descr = ', '.join('#%s' % t for t in tickets) template = jinja2template(self.batch_subject_template, text=True) prefix = self.config.get('notification', 'smtp_subject_prefix') if prefix == '__default__': prefix = '[%s]' % self.env.project_name data = { 'prefix': prefix, 'tickets_descr': tickets_descr, 'env': self.env, } subj = template.render(**data).strip() return shorten_line(subj)
def sha_link(sha, label=None): # sha is assumed to be a non-abbreviated 40-chars sha id try: reponame = context.resource.parent.id repos = RepositoryManager(self.env).get_repository(reponame) cset = repos.get_changeset(sha) if label is None: label = repos.display_rev(sha) return tag.a(label, class_='changeset', title=shorten_line(cset.message), href=context.href.changeset(sha, repos.reponame)) except Exception as e: return tag.a(sha, class_='missing changeset', title=to_unicode(e), rel='nofollow')
def ticket_anchor(ticket): try: pvalue = ticket.get('product') or GLOBAL_PRODUCT envhref = hrefcache[pvalue] except KeyError: try: env = lookup_product_env(self.env, prefix= pvalue, name=pvalue) except LookupError: return tag.a('#%s' % ticket['id'], class_='missing product') hrefcache[pvalue] = envhref = resolve_product_href( to_env=env, at_env=self.env) return tag.a('#%s' % ticket['id'], class_=ticket['status'], href=envhref.ticket(int(ticket['id'])), title=shorten_line(ticket['summary']))
def _format_link(self, formatter, ns, target, label, fullmatch=None): intertrac = formatter.shorthand_intertrac_helper(ns, target, label, fullmatch) if intertrac: return intertrac try: cursor = formatter.db.cursor() cursor.execute("SELECT summary,status FROM ticket WHERE id=%s", (str(int(target)),)) row = cursor.fetchone() if row: return html.A(label, class_='%s ticket' % row[1], title=shorten_line(row[0]) + ' (%s)' % row[1], href=formatter.href.ticket(target)) except ValueError: pass return html.A(label, class_='missing ticket', rel='nofollow', href=formatter.href.ticket(target))
def _format_link(self, formatter, ns, target, label, fullmatch=None): intertrac = formatter.shorthand_intertrac_helper(ns, target, label, fullmatch) if intertrac: return intertrac try: cursor = formatter.db.cursor() cursor.execute("SELECT summary,status FROM ticket WHERE id=%s", (str(int(target)),)) row = cursor.fetchone() if row: return html.A( label, class_="%s ticket" % row[1], title=shorten_line(row[0]) + " (%s)" % row[1], href=formatter.href.ticket(target), ) except ValueError: pass return html.A(label, class_="missing ticket", rel="nofollow", href=formatter.href.ticket(target))
def _index_wiki_page(self, page): history = list(page.get_history()) so = FullTextSearchObject( self.project, page.resource, title=u"%s: %s" % (page.name, shorten_line(page.text)), author=page.author, changed=page.time, created=history[-1][1], # .time of oldest version tags=self._page_tags(page.resource.realm, page.name), involved=list(set(r[2] for r in history)), popularity=0, # FIXME oneline=shorten_result(page.text), body=page.text, comments=[r[3] for r in history], ) self.backend.create(so, quiet=True) self.log.debug("WikiPage created for indexing: %s", page.name)
def _index_changeset(self, repos, changeset): # Index the commit message so = FullTextSearchObject( self.project, changeset.resource, title=u"[%s]: %s" % (changeset.rev, shorten_line(changeset.message)), oneline=shorten_result(changeset.message), body=changeset.message, author=changeset.author, created=changeset.date, changed=changeset.date, ) success = self.backend.create(so, quiet=True) if not self.fulltext_index_svn_nodes: return def _changes(repos, changeset): for path, kind, change, base_path, base_rev in changeset.get_changes(): if change == Changeset.MOVE: yield FullTextSearchObject(self.project, "source", base_path, repos.resource, action="DELETE") elif change == Changeset.DELETE: yield FullTextSearchObject(self.project, "source", path, repos.resource, action="DELETE") if change in (Changeset.ADD, Changeset.EDIT, Changeset.COPY, Changeset.MOVE): node = repos.get_node(path, changeset.rev) so = FullTextSearchObject( self.project, node.resource, title=node.path, oneline=u"[%s]: %s" % (changeset.rev, shorten_result(changeset.message)), comments=[changeset.message], changed=node.get_last_modified(), author=changeset.author, created=changeset.date, ) if node.content_length <= self.max_size: stream = node.get_content() if stream: so.body = stream.read() so.extract = True yield so for so in _changes(repos, changeset): self.backend.create(so, quiet=True)
def get_search_results(self, req, terms, filters): if not 'wiki' in filters: return db = self.env.get_db_cnx() sql_query, args = search_to_sql(db, ['w1.name', 'w1.author', 'w1.text'], terms) cursor = db.cursor() cursor.execute( "SELECT w1.name,w1.time,w1.author,w1.text " "FROM wiki w1," "(SELECT name,max(version) AS ver " "FROM wiki GROUP BY name) w2 " "WHERE w1.version = w2.ver AND w1.name = w2.name " "AND " + sql_query, args) for name, date, author, text in cursor: yield (req.href.wiki(name), '%s: %s' % (name, shorten_line(text)), date, author, shorten_result(text, terms))
def _format_link(self, formatter, ns, rev, label): repos = self.env.get_repository() if ns == 'branch': for b, head in repos.get_branches(): if b == rev: rev = head break try: chgset = repos.get_changeset(rev) return html.a(label, class_="changeset", title=shorten_line(chgset.message), href=formatter.href.changeset(rev)) except NoSuchChangeset, e: return html.a(label, class_="missing changeset", title=to_unicode(e), rel="nofollow", href=formatter.href.changeset(rev))
def format(self, text, out, shorten=False): if not text: return self.out = out self._open_tags = [] # Simplify code blocks in_code_block = 0 processor = None buf = StringIO() for line in text.strip().splitlines(): if line.strip() == WikiParser.STARTBLOCK: in_code_block += 1 elif line.strip() == WikiParser.ENDBLOCK: if in_code_block: in_code_block -= 1 if in_code_block == 0: if processor != 'comment': buf.write(' ![...]' + os.linesep) processor = None elif in_code_block: if not processor: if line.startswith('#!'): processor = line[2:].strip() else: buf.write(line + os.linesep) result = buf.getvalue()[:-1] if shorten: result = shorten_line(result) result = re.sub(self.my_rules, self.replace, result) result = result.replace('[...]', '[…]') if result.endswith('...'): result = result[:-3] + '…' # Close all open 'one line'-tags result += self.close_tag(None) # Flush unterminated code blocks if in_code_block > 0: result += '[…]' out.write(result)
def wiki_page_added(self, page): history = list(page.get_history()) so = FullTextSearchObject( self.project, page.resource, title=u'%s: %s' % (page.name, shorten_line(page.text)), author=page.author, changed=page.time, created=history[-1][1], # .time of oldest version tags=self._page_tags(page.resource.realm, page.name), involved=list(set(r[2] for r in history)), popularity=0, #FIXME oneline=shorten_result(page.text), body=page.text, comments=[r[3] for r in history], ) self.backend.create(so, quiet=True) self._update_wiki(page) self.log.debug("WikiPage created for indexing: %s", page.name)
def _format_changeset_link(self, formatter, ns, match): self.env.log.debug("format changeset link") if int(self.enable_revmap) == 0: self.env.log.debug("revmap disabled, skipping thingy") return match.group(0) self.env.log.debug("revmap enabled: formatting links") commit_data = self._get_commit_data(match.group(0)) if len(commit_data) == 1: self.env.log.debug(commit_data) if int(self.long_tooltips): title = commit_data[0]['msg'] else: title = shorten_line(commit_data[0]['msg']) return tag.a(match.group(0), href="%s/%s" % (formatter.href.changeset(), commit_data[0]['id']), title=title, class_="changeset") elif len(commit_data) > 1: #try to figure out something better when an id is ambiguous return match.group(0) return match.group(0)
def _format_changeset_link(self, formatter, ns, chgset, label, fullmatch=None): intertrac = formatter.shorthand_intertrac_helper(ns, chgset, label, fullmatch) if intertrac: return intertrac sep = chgset.find('/') if sep > 0: rev, path = chgset[:sep], chgset[sep:] else: rev, path = chgset, None try: changeset = self.env.get_repository().get_changeset(rev) return html.A(label, class_="changeset", title=shorten_line(changeset.message), href=formatter.href.changeset(rev, path)) except NoSuchChangeset: return html.A(label, class_="missing changeset", href=formatter.href.changeset(rev, path), rel="nofollow")
def annotate(self, row, lineno): if lineno > len(self.annotations): row.append(tag.th()) return rev = self.annotations[lineno - 1] chgset = self.changesets[lineno - 1] path = self.paths.get(rev, None) # Note: path will be None if copy/rename is not supported # by get_history # -- compute anchor and style once per revision if rev not in self.chgset_data: chgset_href = \ self.context.href.changeset(rev, self.repos.reponame or None, path) short_author = chgset.author.split(' ', 1)[0] title = shorten_line('%s: %s' % (short_author, chgset.message)) anchor = tag.a( '[%s]' % self.repos.short_rev(rev), # shortname title=title, href=chgset_href) color = self.colorize_age(self.timerange.relative(chgset.date)) style = 'background-color: rgb(%d, %d, %d);' % color self.chgset_data[rev] = (anchor, style) else: anchor, style = self.chgset_data[rev] if self.prev_chgset != chgset: self.prev_style = style # optimize away the path if there's no copy/rename info if not path or path == self.path: path = '' # -- produce blame column, eventually with an anchor style = self.prev_style if lineno < len(self.changesets) and self.changesets[lineno] == chgset: style += ' border-bottom: none;' blame_col = tag.th(style=style, class_='blame r%s' % rev) if self.prev_chgset != chgset: blame_col.append(anchor) self.prev_chgset = chgset row.append(blame_col)
def get_search_results(self, req, terms, filters): if not 'ticket' in filters: return db = self.env.get_db_cnx() sql, args = search_to_sql(db, ['b.newvalue'], terms) sql2, args2 = search_to_sql(db, ['summary', 'keywords', 'description', 'reporter', 'cc'], terms) cursor = db.cursor() cursor.execute("SELECT DISTINCT a.summary,a.description,a.reporter, " "a.keywords,a.id,a.time,a.status FROM ticket a " "LEFT JOIN ticket_change b ON a.id = b.ticket " "WHERE (b.field='comment' AND %s ) OR %s" % (sql, sql2), args + args2) for summary, desc, author, keywords, tid, date, status in cursor: ticket = '#%d: ' % tid if status == 'closed': ticket = Markup('<span style="text-decoration: line-through">' '#%s</span>: ', tid) yield (req.href.ticket(tid), ticket + shorten_line(summary), date, author, shorten_result(desc, terms))