def get_build_ref_markup(nav_url, jobs, content): '''Return build reference markup expanded by RefHudsonBuild macro. ex1. [[RefHudsonBuild(j3, 1)] >>> str(get_build_ref_markup('http://example.com/hudson/', ['j1','j2'], 'j3,1')) '<a class="ext-link" href="http://example.com/hudson/job/j3/1/"><span class="icon"></span>Hudson: j3#1</a>' ex2. [[RefHudsonBuild(1)] ; jobs = [j1, j2] >>> str(get_build_ref_markup('http://example.com/hudson/', ['j1','j2'], '1')) '<a class="ext-link" href="http://example.com/hudson/job/j1/1/"><span class="icon"></span>Hudson: j1#1</a>' Also, _markup functions must be charcter-escaped. >>> str(get_build_ref_markup('spam/', ['j1','j2'], '><",1')) '<a class="ext-link" href="spam/job/><"/1/"><span class="icon"></span>Hudson: ><"#1</a>' >>> str(get_build_ref_markup('spam/', ['><"','j2'], '1')) '<a class="ext-link" href="spam/job/><"/1/"><span class="icon"></span>Hudson: ><"#1</a>' ''' FORMAT = '<a class="ext-link" href="%sjob/%s/%s/"><span class="icon"></span>Hudson: %s#%s</a>' args = map(lambda x: x.strip(), str(content).split(',')) if len(args) == 1: if len(jobs) == 0: return '' job_name = Markup.escape(jobs[0].strip()) job_no = Markup.escape(args[0]) else: job_name = Markup.escape(args[0]) job_no = Markup.escape(args[1]) return Markup(FORMAT % (nav_url, job_name, job_no, job_name, job_no))
def get_navi_markup(disp, url, label): """Return the navigation element markup. If nav_url is true, make an element to open other window. >>> str(get_navi_markup(True, 'url', 'label')) '<a class="ext-link" href="url" target="hudson"><span class="icon"></span>label</a>' If nav_url is false, make an element to link only. >>> str(get_navi_markup(False, 'url', 'label')) '<a class="ext-link" href="url" ><span class="icon"></span>label</a>' Also, _markup functions must be charcter-escaped. >>> str(get_navi_markup(False, '"<>', 'label')) '<a class="ext-link" href=""<>" ><span class="icon"></span>label</a>' >>> str(get_navi_markup(False, 'url', '"<>')) '<a class="ext-link" href="url" ><span class="icon"></span>"<></a>' """ FORMAT = '<a class="ext-link" href="%s" %s><span class="icon"></span>%s</a>' escaped_url = Markup.escape(url) escaped_label = Markup.escape(label) if disp: target = 'target="hudson"' else: target = '' return Markup(FORMAT % (escaped_url, target, escaped_label))
def get_build_title_markup(job, build): '''Return build title for timeline. >>> str(get_build_title_markup({'name': 'jobname'}, {'number':1, 'result':'SUCCESS'})) '<img src="chrome/common/extlink.gif">jobname #1 - build-success</a>' Also, _markup functions must be charcter-escaped. >>> str(get_build_title_markup({'name': 'jobname'}, {'number':'><"', 'result':'SUCCESS'})) '<img src="chrome/common/extlink.gif">jobname #><" - build-success</a>' >>> str(get_build_title_markup({'name': '><"'}, {'number':1, 'result':'SUCCESS'})) '<img src="chrome/common/extlink.gif">><" #1 - build-success</a>' ''' FORMAT = '<img src="chrome/common/extlink.gif">%s #%s - %s</a>' build_number = Markup.escape(str(build['number'])) job_name = Markup.escape(job['name']) return Markup(FORMAT % (job_name, build_number, get_build_kind(build)))
def process_request(self, req): req.hdf['trac.href.blog'] = req.href.blog() entries = [] for page_name in WikiSystem(self.env).get_pages(prefix='Blog'): page = WikiPage(self.env, page_name) title = page_name text = page.text match = title_split_match(page.text) if match: title = match.group(1) text = match.group(2) comments = text.count('[[SimpleBlogComment(') cutoff = text.find('[[SimpleBlogComment(') if cutoff >= 0: text = text[:cutoff].rstrip() description = wiki_to_html(text, self.env, req) original = self._get_original_post_info(page_name) event = { 'href': self.env.href.wiki(page_name), 'title': title, 'description': description, 'escaped': Markup.escape(unicode(description)), 'date': format_datetime(original['time']), 'rfcdate': http_date(original['time']), 'author': original['author'], 'comment': original['comment'], 'comments': comments, } if page.version > 1: event['updated.version'] = page.version event['updated.date'] = format_datetime(page.time) event['updated.rfcdate'] = http_date(page.time) event['updated.author'] = page.author event['updated.comment'] = page.comment entries.append((original['time'], event)) entries.sort() entries.reverse() max_count = 20 if len(entries) > max_count: entries = entries[:max_count] events = [] for date, event in entries: events.append(event) req.hdf['blog.events'] = events format = req.args.get('format') if format == 'rss': return 'blog_rss.cs', 'application/rss+xml' add_link(req, 'alternate', self.env.href.blog(format='rss'), 'RSS Feed', 'application/rss+xml', 'rss') return 'blog.cs', None
def get_timeline_events(self, req, start, stop, filters): format = req.args.get('format') href = format == 'rss' and req.abs_href or req.href # Ticket changes if 'worklog' in filters: add_stylesheet(req, "worklog/worklogplugin.css") db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute( """SELECT wl.user,wl.ticket,wl.time,wl.starttime,wl.comment,wl.kind,wl.humankind,t.summary,t.status FROM ( SELECT user, ticket, starttime AS time, starttime, comment, 'workstart' AS kind, 'started' AS humankind FROM work_log UNION SELECT user, ticket, endtime AS time, starttime, comment, 'workstop' AS kind, 'stopped' AS humankind FROM work_log ) AS wl INNER JOIN ticket t ON t.id = wl.ticket AND wl.time>=%s AND wl.time<=%s ORDER BY wl.time""" % (start, stop)) previous_update = None for user, ticket, time, starttime, comment, kind, humankind, summary, status in cursor: summary = Markup.escape(summary) time = float(time) starttime = float(starttime) if format == 'rss': title = Markup('%s %s working on Ticket #%s (%s): %s' % \ (user, humankind, ticket, summary, comment)) else: title = Markup('%s %s working on Ticket <em title="%s">#%s</em>' % \ (user, humankind, summary, ticket)) message = '' if kind == 'workstop': started = datetime.fromtimestamp(starttime) finished = datetime.fromtimestamp(time) if comment: message = wiki_to_oneliner( comment, self.env, db, shorten=True) + Markup( '<br />(Time spent: %s)' % pretty_timedelta(started, finished)) else: message = 'Time spent: %s' % pretty_timedelta( started, finished) yield kind, href.ticket(ticket), title, time, user, message
def _make_js(self, req): """Generate the needed Javascript.""" adds = [] for adder in self.ctxtnav_adders: if adder.match_ctxtnav_add(req): for add in adder.get_ctxtnav_adds(req): if isinstance(add, Markup): adds.append(Markup(add.replace("'","\\'"))) else: href, text = add adds.append(Markup('<a href="%s">%s</a>'%(href,Markup.escape(text,False)))) js = "" for add in adds: js += "add_ctxtnav('%s');\n"%add return """<script type="text/javascript">%s</script>"""%js
def get_timeline_events(self, req, start, stop, filters): format = req.args.get('format') href = format == 'rss' and req.abs_href or req.href # Ticket changes if 'worklog' in filters: add_stylesheet(req, "worklog/worklogplugin.css") db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute("""SELECT wl.user,wl.ticket,wl.time,wl.starttime,wl.comment,wl.kind,wl.humankind,t.summary,t.status FROM ( SELECT user, ticket, starttime AS time, starttime, comment, 'workstart' AS kind, 'started' AS humankind FROM work_log UNION SELECT user, ticket, endtime AS time, starttime, comment, 'workstop' AS kind, 'stopped' AS humankind FROM work_log ) AS wl INNER JOIN ticket t ON t.id = wl.ticket AND wl.time>=%s AND wl.time<=%s ORDER BY wl.time""" % (start, stop)) previous_update = None for user,ticket,time,starttime,comment,kind,humankind,summary,status in cursor: summary = Markup.escape(summary) time = float(time) starttime = float(starttime) if format == 'rss': title = Markup('%s %s working on Ticket #%s (%s): %s' % \ (user, humankind, ticket, summary, comment)) else: title = Markup('%s %s working on Ticket <em title="%s">#%s</em>' % \ (user, humankind, summary, ticket)) message = '' if kind == 'workstop': started = datetime.fromtimestamp(starttime) finished = datetime.fromtimestamp(time) if comment: message = wiki_to_oneliner(comment, self.env, db, shorten=True) + Markup('<br />(Time spent: %s)' % pretty_timedelta(started, finished)) else: message = 'Time spent: %s' % pretty_timedelta(started, finished) yield kind, href.ticket(ticket), title, time, user, message
def _make_js(self, req): """Generate the needed Javascript.""" adds = [] for adder in self.ctxtnav_adders: if adder.match_ctxtnav_add(req): for add in adder.get_ctxtnav_adds(req): if isinstance(add, Markup): adds.append(Markup(add.replace("'", "\\'"))) else: href, text = add adds.append( Markup('<a href="%s">%s</a>' % (href, Markup.escape(text, False)))) js = "" for add in adds: js += "add_ctxtnav('%s');\n" % add return """<script type="text/javascript">%s</script>""" % js
def _generate_blog(self, req, *args, **kwargs): """Extract the blog pages and fill the HDF. *args is a list of tags to use to limit the blog scope **kwargs are any aditional keyword arguments that are needed """ tallies = {} tags = TagEngine(self.env).tagspace.wiki try: union = kwargs['union'] except KeyError: union = False # Formatting read_post = "[wiki:%s Read Post]" entries = {} if not len(args): tlist = [self.env.config.get('blog', 'default_tag', 'blog')] else: tlist = args if union: blog = tags.get_tagged_names(tlist, operation='union') else: blog = tags.get_tagged_names(tlist, operation='intersection') macropage = req.args.get('page', None) poststart, postend, default_times = self._get_time_range(req, **kwargs) mark_updated = self._choose_value('mark_updated', req, kwargs, convert=bool_val) if not mark_updated and (not isinstance(mark_updated, bool)): mark_updated = bool_val( self.env.config.get('blog', 'mark_updated', True)) macro_bl = self.env.config.get('blog', 'macro_blacklist', '').split(',') macro_bl = [name.strip() for name in macro_bl if name.strip()] macro_bl.append('BlogShow') # Get the email addresses of all known users and validate the "poster" # BlogShow optional argument at the same time (avoids looping the user # list twice). is_poster = None limit_poster = self._choose_value('poster', req, kwargs, convert=None) email_map = {} for username, name, email in self.env.get_known_users(): if email: email_map[username] = email if limit_poster != None: if username == limit_poster: is_poster = username num_posts = self._choose_value('num_posts', req, kwargs, convert=int) if num_posts and default_times: poststart = sys.maxint postend = 0 for blog_entry in blog: if blog_entry == macropage: continue try: page = WikiPage(self.env, version=1, name=blog_entry) version, post_time, author, comment, ipnr = page.get_history( ).next() # if we're limiting by poster, do so now so that the calendar # only shows the number of entries the specific poster made. if is_poster != None: if is_poster != author: continue self._add_to_tallies(tallies, post_time, blog_entry) page = WikiPage(self.env, name=blog_entry) version, modified, author, comment, ipnr = page.get_history( ).next() except: self.log.debug("Error loading wiki page %s" % blog_entry, exc_info=True) continue if poststart >= post_time >= postend: time_format = self.env.config.get('blog', 'date_format') \ or '%x %X' timeStr = format_datetime(post_time, format=time_format) fulltext = page.text # remove comments in blog view: del_comments = re.compile('==== Comment.*\Z', re.DOTALL) fulltext = del_comments.sub('', fulltext) # remove the [[AddComment...]] tag, otherwise it would appeare # more than one and crew up the blog view: del_addcomment = re.compile('\[\[AddComment.*\Z', re.DOTALL) fulltext = del_addcomment.sub('', fulltext) # limit length of preview: post_size = self._choose_value('post_size', req, kwargs, int) if not post_size and (not isinstance(post_size, int)): post_size = int( self.env.config.get('blog', 'post_size', 1024)) text = self._trim_page(fulltext, blog_entry, post_size) pagetags = [ x for x in tags.get_name_tags(blog_entry) if x not in tlist ] tagtags = [] for i, t in enumerate(pagetags[:3]): d = { 'link': t, 'name': t, 'last': i == (len(pagetags[:3]) - 1), } tagtags.append(d) continue # extract title from text: match = _title_split_match(fulltext) if match: title = match.group(1) fulltext = match.group(2) else: title = blog_entry html_text = wiki_to_html(fulltext, self.env, req) rss_text = Markup.escape(to_unicode(html_text)) data = { 'name': blog_entry, 'title': title, 'href': self.env.href.wiki(blog_entry), 'wiki_link': wiki_to_oneliner(read_post % blog_entry, self.env), 'time': timeStr, 'date': http_date(post_time), # 'date' : http_date(page.time), 'author': author, 'wiki_text': wiki_to_nofloat_html(text, self.env, req, macro_blacklist=macro_bl), 'rss_text': rss_text, 'comment': wiki_to_oneliner(comment, self.env), 'tags': { 'present': len(pagetags), 'tags': tagtags, 'more': len(pagetags) > 3 or 0, }, } if author: # For RSS, author must be an email address if author.find('@') != -1: data['author.email'] = author elif email_map.has_key(author): data['author.email'] = email_map[author] if (modified != post_time) and mark_updated: data['modified'] = 1 mod_str = format_datetime(modified, format=time_format) data['mod_time'] = mod_str entries[post_time] = data continue tlist = entries.keys() tlist.sort() tlist.reverse() if num_posts and (num_posts <= len(tlist)): tlist = tlist[:num_posts] if tlist: entries[tlist[-1]]['last'] = 1 req.hdf['blog.entries'] = [entries[x] for x in tlist] bloglink = self.env.config.get('blog', 'new_blog_link', 'New Blog Post') req.hdf['blog.newblog'] = bloglink hidecal = self._choose_value('hidecal', req, kwargs) if not hidecal: self._generate_calendar(req, tallies) req.hdf['blog.hidecal'] = hidecal # Insert /wiki/BlogHeader into /blog. If the page does not exist, # this'll be a no-op blog_header = WikiPage(self.env, name='BlogHeader').text req.hdf['blog.header'] = Mimeview(self.env).render( req, 'text/x-trac-wiki', blog_header)
def _generate_blog(self, req, *args, **kwargs): """Extract the blog pages and fill the HDF. *args is a list of tags to use to limit the blog scope **kwargs are any aditional keyword arguments that are needed """ tallies = {} tags = TagEngine(self.env).tagspace.wiki try: union = kwargs['union'] except KeyError: union = False # Formatting read_post = "[wiki:%s Read Post]" entries = {} if not len(args): tlist = [self.env.config.get('blog', 'default_tag', 'blog')] else: tlist = args if union: blog = tags.get_tagged_names(tlist, operation='union') else: blog = tags.get_tagged_names(tlist, operation='intersection') macropage = req.args.get('page', None) poststart, postend, default_times = self._get_time_range(req, **kwargs) mark_updated = self._choose_value('mark_updated', req, kwargs, convert=bool_val) if not mark_updated and (not isinstance(mark_updated, bool)): mark_updated = bool_val(self.env.config.get('blog', 'mark_updated', True)) macro_bl = self.env.config.get('blog', 'macro_blacklist', '').split(',') macro_bl = [name.strip() for name in macro_bl if name.strip()] macro_bl.append('BlogShow') # Get the email addresses of all known users and validate the "poster" # BlogShow optional argument at the same time (avoids looping the user # list twice). is_poster = None limit_poster = self._choose_value('poster', req, kwargs, convert=None) email_map = {} for username, name, email in self.env.get_known_users(): if email: email_map[username] = email if limit_poster != None: if username == limit_poster: is_poster = username num_posts = self._choose_value('num_posts', req, kwargs, convert=int) if num_posts and default_times: poststart = sys.maxint postend = 0 for blog_entry in blog: if blog_entry == macropage: continue try: page = WikiPage(self.env, version=1, name=blog_entry) version, post_time, author, comment, ipnr = page.get_history( ).next() # if we're limiting by poster, do so now so that the calendar # only shows the number of entries the specific poster made. if is_poster != None: if is_poster != author: continue self._add_to_tallies(tallies, post_time, blog_entry) page = WikiPage(self.env, name=blog_entry) version, modified, author, comment, ipnr = page.get_history( ).next() except: self.log.debug("Error loading wiki page %s" % blog_entry, exc_info=True) continue if poststart >= post_time >= postend: time_format = self.env.config.get('blog', 'date_format') \ or '%x %X' timeStr = format_datetime(post_time, format=time_format) fulltext = page.text # remove comments in blog view: del_comments = re.compile('==== Comment.*\Z', re.DOTALL) fulltext = del_comments.sub('', fulltext) # remove the [[AddComment...]] tag, otherwise it would appeare # more than one and crew up the blog view: del_addcomment = re.compile('\[\[AddComment.*\Z', re.DOTALL) fulltext = del_addcomment.sub('', fulltext) # limit length of preview: post_size = self._choose_value('post_size', req, kwargs, int) if not post_size and (not isinstance(post_size, int)): post_size = int(self.env.config.get('blog', 'post_size', 1024)) text = self._trim_page(fulltext, blog_entry, post_size) pagetags = [x for x in tags.get_name_tags(blog_entry) if x not in tlist] tagtags = [] for i, t in enumerate(pagetags[:3]): d = { 'link' : t, 'name' : t, 'last' : i == (len(pagetags[:3]) - 1), } tagtags.append(d) continue # extract title from text: match = _title_split_match(fulltext) if match: title = match.group(1) fulltext = match.group(2) else: title = blog_entry html_text = wiki_to_html(fulltext, self.env, req) rss_text = Markup.escape(to_unicode(html_text)) data = { 'name' : blog_entry, 'title' : title, 'href' : self.env.href.wiki(blog_entry), 'wiki_link' : wiki_to_oneliner(read_post % blog_entry, self.env), 'time' : timeStr, 'date' : http_date(post_time), # 'date' : http_date(page.time), 'author' : author, 'wiki_text' : wiki_to_nofloat_html(text, self.env, req, macro_blacklist=macro_bl), 'rss_text' : rss_text, 'comment' : wiki_to_oneliner(comment, self.env), 'tags' : { 'present' : len(pagetags), 'tags' : tagtags, 'more' : len(pagetags) > 3 or 0, }, } if author: # For RSS, author must be an email address if author.find('@') != -1: data['author.email'] = author elif email_map.has_key(author): data['author.email'] = email_map[author] if (modified != post_time) and mark_updated: data['modified'] = 1 mod_str = format_datetime(modified, format=time_format) data['mod_time'] = mod_str entries[post_time] = data continue tlist = entries.keys() tlist.sort() tlist.reverse() if num_posts and (num_posts <= len(tlist)): tlist = tlist[:num_posts] if tlist: entries[tlist[-1]]['last'] = 1 req.hdf['blog.entries'] = [entries[x] for x in tlist] bloglink = self.env.config.get('blog', 'new_blog_link', 'New Blog Post') req.hdf['blog.newblog'] = bloglink hidecal = self._choose_value('hidecal', req, kwargs) if not hidecal: self._generate_calendar(req, tallies) req.hdf['blog.hidecal'] = hidecal # Insert /wiki/BlogHeader into /blog. If the page does not exist, # this'll be a no-op blog_header = WikiPage(self.env, name='BlogHeader').text req.hdf['blog.header'] = Mimeview(self.env).render(req, 'text/x-trac-wiki', blog_header)