diff -ru trac-0.8.orig/templates/timeline.cs trac-0.8/templates/timeline.cs
|
old
|
new
|
|
| 1 | 1 | <?cs set:html.stylesheet = 'css/timeline.css' ?> |
| 2 | 2 | <?cs include "header.cs"?> |
| | 3 | <?cs include "macros.cs"?> |
| 3 | 4 | |
| 4 | 5 | <div id="ctxtnav" class="nav"></div> |
| 5 | 6 | |
| … |
… |
|
| 35 | 36 | if:timeline.milestone ?>checked="checked"<?cs /if ?> /> |
| 36 | 37 | <label for="milestone">Milestones</label> |
| 37 | 38 | </div><?cs /if ?> |
| | 39 | <div class="field"> |
| | 40 | <input type="checkbox" id="component" name="component" <?cs |
| | 41 | if:timeline.component ?>checked="checked"<?cs /if ?> /> |
| | 42 | <label for="component">Component: </label><?cs |
| | 43 | call:hdf_select(timeline.components, "cfilter", timeline.cfilter) ?> |
| | 44 | </div> |
| 38 | 45 | </fieldset> |
| 39 | 46 | <div class="buttons"> |
| 40 | 47 | <input type="submit" value="Update" /> |
| … |
… |
|
| 60 | 67 | |
| 61 | 68 | <?cs each:item = timeline.items ?> |
| 62 | 69 | <?cs call:day_separator(item.date) ?> |
| | 70 | <?cs if:item.component ?> |
| | 71 | <?cs set:component = ' (' + $item.component + ')' ?> |
| | 72 | <?cs else ?> |
| | 73 | <?cs set:component = '' ?> |
| | 74 | <?cs /if ?> |
| 63 | 75 | <?cs if:item.type == #1 ?><!-- Changeset --> |
| 64 | 76 | <?cs call:tlitem(item.href, 'changeset', |
| 65 | | 'Changeset <em>['+$item.idata+']</em> by '+$item.author,$item.node_list+item.message) ?> |
| | 77 | 'Changeset <em>['+$item.idata+']</em>'+$component+' by '+$item.author,$item.node_list+item.message) ?> |
| 66 | 78 | <?cs elif:item.type == #2 ?><!-- New ticket --> |
| 67 | 79 | <?cs call:tlitem(item.href, 'newticket', |
| 68 | | 'Ticket <em>#'+$item.idata+'</em> created by '+$item.author, item.message) ?> |
| | 80 | 'Ticket <em>#'+$item.idata+'</em>'+$component+' created by '+$item.author, item.message) ?> |
| 69 | 81 | <?cs elif:item.type == #3 ?><!-- Closed ticket --> |
| 70 | 82 | <?cs if:item.message ?> |
| 71 | 83 | <?cs set:imessage = ' - ' + $item.message ?> |
| … |
… |
|
| 73 | 85 | <?cs set:imessage = '' ?> |
| 74 | 86 | <?cs /if ?> |
| 75 | 87 | <?cs call:tlitem(item.href, 'closedticket', |
| 76 | | 'Ticket <em>#'+$item.idata+'</em> resolved by '+$item.author, |
| | 88 | 'Ticket <em>#'+$item.idata+'</em>'+$component+' resolved by '+$item.author, |
| 77 | 89 | $item.tdata+$imessage) ?> |
| 78 | 90 | <?cs elif:item.type == #4 ?><!-- Reopened ticket --> |
| 79 | 91 | <?cs call:tlitem(item.href, 'newticket', |
| 80 | | 'Ticket <em>#'+$item.idata+'</em> reopened by '+$item.author, '') ?> |
| | 92 | 'Ticket <em>#'+$item.idata+'</em>'+$component+' reopened by '+$item.author, '') ?> |
| 81 | 93 | <?cs elif:item.type == #5 ?><!-- Wiki change --> |
| 82 | 94 | <?cs call:tlitem(item.href, 'wiki', |
| 83 | 95 | '<em>'+$item.tdata+'</em> edited by '+$item.author, item.message) ?> |
diff -ru trac-0.8.orig/templates/timeline_rss.cs trac-0.8/templates/timeline_rss.cs
|
old
|
new
|
|
| 33 | 33 | <link><?cs var:$base_url ?><?cs var:$trac.href.timeline ?></link> |
| 34 | 34 | </image> |
| 35 | 35 | <?cs each:item = $timeline.items ?><?cs |
| | 36 | if:item.component ?> |
| | 37 | <?cs set:component = ' (' + $item.component + ')' ?><?cs |
| | 38 | else ?> |
| | 39 | <?cs set:component = '' ?><?cs |
| | 40 | /if ?><?cs |
| 36 | 41 | if:item.type == #1 |
| 37 | 42 | ?><!-- Changeset --><?cs call:rss_item('Changeset', |
| 38 | | 'Changeset ['+$item.idata+'] by '+$item.author, |
| | 43 | 'Changeset ['+$item.idata+']'+$component+' by '+$item.author, |
| 39 | 44 | $item.href, $item.msg_escwiki) |
| 40 | 45 | ?><?cs elif:item.type == #2 |
| 41 | 46 | ?><!-- New ticket --> <?cs call:rss_item('Ticket', |
| 42 | | 'Ticket #'+$item.idata+' created by '+$item.author, |
| | 47 | 'Ticket #'+$item.idata+$component+' created by '+$item.author, |
| 43 | 48 | $item.href, $item.msg_escwiki) |
| 44 | 49 | ?><?cs elif:item.type == #3 |
| 45 | 50 | ?><!-- Closed ticket --> <?cs call:rss_item('Ticket', |
| 46 | | 'Ticket #'+$item.idata+' resolved: '+$item.shortmsg, |
| | 51 | 'Ticket #'+$item.idata+$component+' resolved: '+$item.shortmsg, |
| 47 | 52 | $item.href, $item.msg_escwiki) |
| 48 | 53 | ?><?cs elif:item.type == #4 |
| 49 | 54 | ?><!-- Reopened ticket --><?cs call:rss_item('Ticket', |
| 50 | | '#'+$item.idata+' reopened: '+$item.shortmsg, |
| | 55 | '#'+$item.idata+$component+' reopened: '+$item.shortmsg, |
| 51 | 56 | $item.href, $item.msg_escwiki) |
| 52 | 57 | ?><?cs elif:item.type == #5 |
| 53 | 58 | ?><!-- Wiki change --><?cs call:rss_item('Wiki', |
| … |
… |
|
| 62 | 67 | <?cs /if ?> |
| 63 | 68 | <?cs /each ?> |
| 64 | 69 | </channel> |
| 65 | | </rss> |
| 66 | | No newline at end of file |
| | 70 | </rss> |
diff -ru trac-0.8.orig/trac/Browser.py trac-0.8/trac/Browser.py
|
old
|
new
|
|
| 22 | 22 | import time |
| 23 | 23 | import string |
| 24 | 24 | import posixpath |
| | 25 | import re |
| 25 | 26 | |
| 26 | 27 | import svn |
| 27 | 28 | |
| … |
… |
|
| 42 | 43 | # class provided by modpython might give us some strange string-like object |
| 43 | 44 | # that svn doesn't like. |
| 44 | 45 | path = str(path) |
| | 46 | rfilter = self.env.get_config('trac', 'repository_filter', '') |
| | 47 | |
| 45 | 48 | try: |
| 46 | 49 | root = svn.fs.revision_root(self.fs_ptr, revision, self.pool) |
| 47 | 50 | except svn.core.SubversionException: |
| … |
… |
|
| 65 | 68 | for item in entries.keys(): |
| 66 | 69 | fullpath = posixpath.join(path, item) |
| 67 | 70 | |
| | 71 | if rfilter and not re.search(rfilter, fullpath): |
| | 72 | continue |
| | 73 | |
| 68 | 74 | is_dir = svn.fs.is_dir(root, fullpath, self.pool) |
| 69 | 75 | if is_dir: |
| 70 | 76 | name = item + '/' |
diff -ru trac-0.8.orig/trac/Timeline.py trac-0.8/trac/Timeline.py
|
old
|
new
|
|
| 22 | 22 | import time |
| 23 | 23 | import string |
| 24 | 24 | import urllib |
| | 25 | import re |
| 25 | 26 | |
| 26 | 27 | import perm |
| 27 | 28 | import util |
| … |
… |
|
| 35 | 36 | template_rss_name = 'timeline_rss.cs' |
| 36 | 37 | |
| 37 | 38 | def get_info (self, start, stop, maxrows, tickets, |
| 38 | | changeset, wiki, milestone): |
| | 39 | changeset, wiki, milestone, component, cfilter): |
| 39 | 40 | cursor = self.db.cursor () |
| 40 | 41 | |
| 41 | 42 | tickets = tickets and self.perm.has_permission(perm.TICKET_VIEW) |
| … |
… |
|
| 53 | 54 | WIKI = 5 |
| 54 | 55 | MILESTONE = 6 |
| 55 | 56 | |
| 56 | | q = [] |
| | 57 | try: |
| | 58 | display_components = int(self.env.get_config('timeline', 'display_components', 0)) |
| | 59 | except ValueError, e: |
| | 60 | self.env.log.warning("Invalid 'display_components' value, " |
| | 61 | "please edit trac.ini : %s" % e) |
| | 62 | display_components = 0 |
| | 63 | |
| | 64 | try: |
| | 65 | guess_component = int(self.env.get_config('timeline', 'changeset_guess_component', 0)) |
| | 66 | except ValueError, e: |
| | 67 | self.env.log.warning("Invalid 'changeset_guess_component' value, " |
| | 68 | "please edit trac.ini : %s" % e) |
| | 69 | guess_component = 0 |
| | 70 | |
| | 71 | rfilter = self.env.get_config('trac', 'repository_filter', '') |
| | 72 | rcomponent = self.env.get_config('trac', 'repository_component') |
| | 73 | |
| | 74 | q = [] |
| 57 | 75 | if changeset: |
| 58 | 76 | q.append("SELECT time, rev AS idata, '' AS tdata, 1 AS type, " |
| 59 | | " message, author " |
| | 77 | " message, author, '' AS component " |
| 60 | 78 | "FROM revision WHERE time>=%s AND time<=%s" % |
| 61 | 79 | (start, stop)) |
| 62 | 80 | if tickets: |
| 63 | 81 | q.append("SELECT time, id AS idata, '' AS tdata, 2 AS type, " |
| 64 | | "summary AS message, reporter AS author " |
| | 82 | "summary AS message, reporter AS author, component " |
| 65 | 83 | "FROM ticket WHERE time>=%s AND time<=%s" % |
| 66 | 84 | (start, stop)) |
| 67 | | q.append("SELECT time, ticket AS idata, '' AS tdata, 4 AS type, " |
| 68 | | "'' AS message, author " |
| 69 | | "FROM ticket_change WHERE field='status' " |
| 70 | | "AND newvalue='reopened' AND time>=%s AND time<=%s" % |
| | 85 | q.append("SELECT t1.time, t1.ticket AS idata, '' AS tdata, 4 AS type, " |
| | 86 | " '' AS message, t1.author, t2.component AS component " |
| | 87 | "FROM ticket_change t1, ticket t2 " |
| | 88 | "WHERE t1.field='status' " |
| | 89 | " AND t1.newvalue='reopened' AND t1.ticket = t2.id " |
| | 90 | " AND t1.time>=%s AND t1.time<=%s" % |
| 71 | 91 | (start, stop)) |
| 72 | 92 | q.append("SELECT t1.time AS time, t1.ticket AS idata," |
| 73 | 93 | " t2.newvalue AS tdata, 3 AS type," |
| 74 | | " t3.newvalue AS message, t1.author AS author" |
| | 94 | " t3.newvalue AS message, t1.author AS author," |
| | 95 | " t4.component AS component" |
| 75 | 96 | " FROM ticket_change t1" |
| 76 | 97 | " INNER JOIN ticket_change t2 ON t1.ticket = t2.ticket" |
| 77 | 98 | " AND t1.time = t2.time" |
| 78 | | " LEFT OUTER JOIN ticket_change t3 ON t1.time = t3.time" |
| | 99 | " INNER JOIN ticket t4 ON t1.ticket = t4.id" |
| | 100 | " LEFT OUTER JOIN ticket_change t3 ON t1.time = t3.time" |
| 79 | 101 | " AND t1.ticket = t3.ticket AND t3.field = 'comment'" |
| 80 | 102 | " WHERE t1.field = 'status' AND t1.newvalue = 'closed'" |
| 81 | 103 | " AND t2.field = 'resolution'" |
| 82 | 104 | " AND t1.time >= %s AND t1.time <= %s" % (start,stop)) |
| 83 | 105 | if wiki: |
| 84 | 106 | q.append("SELECT time, -1 AS idata, name AS tdata, 5 AS type, " |
| 85 | | "comment AS message, author " |
| | 107 | "comment AS message, author, '' AS component " |
| 86 | 108 | "FROM wiki WHERE time>=%s AND time<=%s" % |
| 87 | 109 | (start, stop)) |
| 88 | 110 | if milestone: |
| 89 | 111 | q.append("SELECT time, -1 AS idata, '' AS tdata, 6 AS type, " |
| 90 | | "name AS message, '' AS author " |
| | 112 | "name AS message, '' AS author, '' AS component " |
| 91 | 113 | "FROM milestone WHERE time>=%s AND time<=%s" % |
| 92 | 114 | (start, stop)) |
| 93 | 115 | |
| … |
… |
|
| 113 | 135 | 'tdata': row['tdata'], |
| 114 | 136 | 'type': int(row['type']), |
| 115 | 137 | 'message': row['message'] or '', |
| 116 | | 'author': util.escape(row['author'] or 'anonymous') |
| | 138 | 'author': util.escape(row['author'] or 'anonymous'), |
| | 139 | 'component': row['component'] or '' |
| 117 | 140 | } |
| 118 | 141 | |
| 119 | 142 | if item['type'] == CHANGESET: |
| 120 | | item['href'] = self.env.href.changeset(item['idata']) |
| | 143 | changeset_component = '' |
| | 144 | changeset_filtered = 1 |
| | 145 | item['href'] = self.env.href.changeset(item['idata']) |
| 121 | 146 | msg = item['message'] |
| 122 | 147 | item['shortmsg'] = util.escape(util.shorten_line(msg)) |
| 123 | 148 | item['msg_nowiki'] = util.escape(msg) |
| … |
… |
|
| 134 | 159 | self.env.log.warning("Invalid 'changeset_show_files' value, " |
| 135 | 160 | "please edit trac.ini : %s" % e) |
| 136 | 161 | max_node = 0 |
| 137 | | |
| 138 | | if max_node != 0: |
| 139 | | cursor_node = self.db.cursor () |
| | 162 | |
| | 163 | if guess_component or rfilter or max_node != 0: |
| | 164 | cursor_node = self.db.cursor () |
| | 165 | if guess_component: |
| | 166 | cursor_node.execute("SELECT name FROM component " |
| | 167 | "ORDER BY name") |
| | 168 | components = map(lambda x: x[0], cursor_node.fetchall()) |
| | 169 | |
| 140 | 170 | cursor_node.execute("SELECT name, change " |
| 141 | 171 | "FROM node_change WHERE rev=%d" % item['idata']) |
| | 172 | row_node = cursor_node.fetchone() |
| | 173 | |
| | 174 | if rfilter: |
| | 175 | if re.search(rfilter, row_node['name']): |
| | 176 | changeset_filtered = 0 |
| | 177 | else: |
| | 178 | changeset_filtered = 0 |
| | 179 | |
| | 180 | if guess_component: |
| | 181 | if rcomponent: |
| | 182 | try: |
| | 183 | m = re.search(rcomponent, row_node['name']) |
| | 184 | if m: changeset_component = m.groups()[-1] |
| | 185 | except StandardError, e: |
| | 186 | self.env.log.warning("'repository_component' should have at least 1 group on match : %s" % e) |
| | 187 | else: |
| | 188 | changeset_component = row_node['name'].split('/')[0] |
| | 189 | if changeset_component not in components: |
| | 190 | changeset_component = '' |
| | 191 | |
| | 192 | if max_node != 0: |
| 142 | 193 | node_list = '' |
| 143 | 194 | node_data = '' |
| 144 | 195 | node_count = 0; |
| 145 | 196 | while 1: |
| 146 | | row_node = cursor_node.fetchone() |
| 147 | | if not row_node: |
| 148 | | break |
| 149 | 197 | if node_count != 0: |
| 150 | 198 | node_list += ', ' |
| 151 | 199 | if (max_node != -1) and (node_count >= max_node): |
| … |
… |
|
| 159 | 207 | node_data = '<span class="diff-rem">' + row_node['name'] + "</span>" |
| 160 | 208 | node_list += node_data |
| 161 | 209 | node_count += 1 |
| | 210 | if re.search(rfilter, row_node['name']): |
| | 211 | changeset_filtered = 0 |
| | 212 | row_node = cursor_node.fetchone() |
| | 213 | if not row_node: |
| | 214 | break |
| 162 | 215 | item['node_list'] = node_list + ': ' |
| 163 | | |
| | 216 | |
| | 217 | if changeset_filtered: |
| | 218 | continue |
| | 219 | |
| | 220 | item['component'] = changeset_component; |
| | 221 | |
| 164 | 222 | elif item['type'] == WIKI: |
| 165 | 223 | item['href'] = self.env.href.wiki(row['tdata']) |
| 166 | 224 | item['message'] = wiki_to_oneliner(util.shorten_line(item['message']), |
| … |
… |
|
| 186 | 244 | item['author.rss'] = '' |
| 187 | 245 | item['message.rss'] = util.escape(item['message'] or '') |
| 188 | 246 | |
| 189 | | info.append(item) |
| 190 | | return info |
| | 247 | if not component or item['component'] == '' or item['component'] == cfilter: |
| | 248 | info.append(item) |
| | 249 | |
| | 250 | # now, after appending, remove the component if asked for |
| | 251 | if not display_components: |
| | 252 | item['component'] = '' |
| | 253 | |
| | 254 | return info |
| 191 | 255 | |
| 192 | 256 | def render (self): |
| 193 | 257 | self.perm.assert_permission(perm.TIMELINE_VIEW) |
| … |
… |
|
| 223 | 287 | ticket = self.args.has_key('ticket') |
| 224 | 288 | changeset = self.args.has_key('changeset') |
| 225 | 289 | milestone = self.args.has_key('milestone') |
| | 290 | component = self.args.has_key('component') |
| | 291 | |
| 226 | 292 | if not (wiki or ticket or changeset or milestone): |
| 227 | 293 | wiki = ticket = changeset = milestone = 1 |
| 228 | 294 | |
| … |
… |
|
| 234 | 300 | self.req.hdf.setValue('timeline.changeset', 'checked') |
| 235 | 301 | if milestone: |
| 236 | 302 | self.req.hdf.setValue('timeline.milestone', 'checked') |
| 237 | | |
| | 303 | if component: |
| | 304 | self.req.hdf.setValue('timeline.component', 'checked') |
| | 305 | |
| | 306 | if self.args.has_key('cfilter'): |
| | 307 | cfilter = self.args['cfilter'] |
| | 308 | else: |
| | 309 | cfilter = '' |
| | 310 | self.req.hdf.setValue('timeline.cfilter', cfilter) |
| | 311 | |
| 238 | 312 | info = self.get_info (start, stop, maxrows, ticket, |
| 239 | | changeset, wiki, milestone) |
| | 313 | changeset, wiki, milestone, component, cfilter) |
| 240 | 314 | util.add_dictlist_to_hdf(info, self.req.hdf, 'timeline.items') |
| 241 | 315 | self.req.hdf.setValue('title', 'Timeline') |
| 242 | | |
| | 316 | util.sql_to_hdf(self.db, 'SELECT name FROM component ORDER BY name', |
| | 317 | self.req.hdf, 'timeline.components') |
| | 318 | |
| 243 | 319 | def display_rss(self): |
| 244 | 320 | self.req.display(self.template_rss_name, 'text/xml') |