##// END OF EJS Templates
pep8ify + small fixes for followers page + added tooltips for followers
marcink -
r1280:215a4801 beta
parent child Browse files
Show More
@@ -1,254 +1,253
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.changeset
3 rhodecode.controllers.changeset
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 changeset controller for pylons showoing changes beetween
6 changeset controller for pylons showoing changes beetween
7 revisions
7 revisions
8
8
9 :created_on: Apr 25, 2010
9 :created_on: Apr 25, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from pylons import tmpl_context as c, url, request, response
29 from pylons import tmpl_context as c, url, request, response
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31 from pylons.controllers.util import redirect
31 from pylons.controllers.util import redirect
32
32
33 import rhodecode.lib.helpers as h
33 import rhodecode.lib.helpers as h
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
34 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.base import BaseRepoController, render
35 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.utils import EmptyChangeset
36 from rhodecode.lib.utils import EmptyChangeset
37
37
38 from vcs.exceptions import RepositoryError, ChangesetError, \
38 from vcs.exceptions import RepositoryError, ChangesetError, \
39 ChangesetDoesNotExistError
39 ChangesetDoesNotExistError
40 from vcs.nodes import FileNode
40 from vcs.nodes import FileNode
41 from vcs.utils import diffs as differ
41 from vcs.utils import diffs as differ
42 from vcs.utils.ordered_dict import OrderedDict
42 from vcs.utils.ordered_dict import OrderedDict
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46
46
47 class ChangesetController(BaseRepoController):
47 class ChangesetController(BaseRepoController):
48
48
49 @LoginRequired()
49 @LoginRequired()
50 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
50 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
51 'repository.admin')
51 'repository.admin')
52 def __before__(self):
52 def __before__(self):
53 super(ChangesetController, self).__before__()
53 super(ChangesetController, self).__before__()
54 c.affected_files_cut_off = 60
54 c.affected_files_cut_off = 60
55
55
56 def index(self, revision):
56 def index(self, revision):
57
57
58 def wrap_to_table(str):
58 def wrap_to_table(str):
59
59
60 return '''<table class="code-difftable">
60 return '''<table class="code-difftable">
61 <tr class="line">
61 <tr class="line">
62 <td class="lineno new"></td>
62 <td class="lineno new"></td>
63 <td class="code"><pre>%s</pre></td>
63 <td class="code"><pre>%s</pre></td>
64 </tr>
64 </tr>
65 </table>''' % str
65 </table>''' % str
66
66
67 #get ranges of revisions if preset
67 #get ranges of revisions if preset
68 rev_range = revision.split('...')[:2]
68 rev_range = revision.split('...')[:2]
69
69
70 try:
70 try:
71 if len(rev_range) == 2:
71 if len(rev_range) == 2:
72 rev_start = rev_range[0]
72 rev_start = rev_range[0]
73 rev_end = rev_range[1]
73 rev_end = rev_range[1]
74 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
74 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
75 end=rev_end)
75 end=rev_end)
76 else:
76 else:
77 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
77 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
78
78
79 c.cs_ranges = list(rev_ranges)
79 c.cs_ranges = list(rev_ranges)
80
80
81 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
81 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
82 log.error(traceback.format_exc())
82 log.error(traceback.format_exc())
83 h.flash(str(e), category='warning')
83 h.flash(str(e), category='warning')
84 return redirect(url('home'))
84 return redirect(url('home'))
85
85
86 c.changes = OrderedDict()
86 c.changes = OrderedDict()
87 c.sum_added = 0
87 c.sum_added = 0
88 c.sum_removed = 0
88 c.sum_removed = 0
89 c.lines_added = 0
89 c.lines_added = 0
90 c.lines_deleted = 0
90 c.lines_deleted = 0
91 c.cut_off = False # defines if cut off limit is reached
91 c.cut_off = False # defines if cut off limit is reached
92
92
93 # Iterate over ranges (default changeset view is always one changeset)
93 # Iterate over ranges (default changeset view is always one changeset)
94 for changeset in c.cs_ranges:
94 for changeset in c.cs_ranges:
95 c.changes[changeset.raw_id] = []
95 c.changes[changeset.raw_id] = []
96 try:
96 try:
97 changeset_parent = changeset.parents[0]
97 changeset_parent = changeset.parents[0]
98 except IndexError:
98 except IndexError:
99 changeset_parent = None
99 changeset_parent = None
100
100
101 #==================================================================
101 #==================================================================
102 # ADDED FILES
102 # ADDED FILES
103 #==================================================================
103 #==================================================================
104 for node in changeset.added:
104 for node in changeset.added:
105
105
106 filenode_old = FileNode(node.path, '', EmptyChangeset())
106 filenode_old = FileNode(node.path, '', EmptyChangeset())
107 if filenode_old.is_binary or node.is_binary:
107 if filenode_old.is_binary or node.is_binary:
108 diff = wrap_to_table(_('binary file'))
108 diff = wrap_to_table(_('binary file'))
109 st = (0, 0)
109 st = (0, 0)
110 else:
110 else:
111 # in this case node.size is good parameter since those are
111 # in this case node.size is good parameter since those are
112 # added nodes and their size defines how many changes were
112 # added nodes and their size defines how many changes were
113 # made
113 # made
114 c.sum_added += node.size
114 c.sum_added += node.size
115 if c.sum_added < self.cut_off_limit:
115 if c.sum_added < self.cut_off_limit:
116 f_gitdiff = differ.get_gitdiff(filenode_old, node)
116 f_gitdiff = differ.get_gitdiff(filenode_old, node)
117 d = differ.DiffProcessor(f_gitdiff, format='gitdiff')
117 d = differ.DiffProcessor(f_gitdiff, format='gitdiff')
118
118
119 st = d.stat()
119 st = d.stat()
120 diff = d.as_html()
120 diff = d.as_html()
121
121
122 else:
122 else:
123 diff = wrap_to_table(_('Changeset is to big and '
123 diff = wrap_to_table(_('Changeset is to big and '
124 'was cut off, see raw '
124 'was cut off, see raw '
125 'changeset instead'))
125 'changeset instead'))
126 c.cut_off = True
126 c.cut_off = True
127 break
127 break
128
128
129 cs1 = None
129 cs1 = None
130 cs2 = node.last_changeset.raw_id
130 cs2 = node.last_changeset.raw_id
131 c.lines_added += st[0]
131 c.lines_added += st[0]
132 c.lines_deleted += st[1]
132 c.lines_deleted += st[1]
133 c.changes[changeset.raw_id].append(('added', node, diff,
133 c.changes[changeset.raw_id].append(('added', node, diff,
134 cs1, cs2, st))
134 cs1, cs2, st))
135
135
136 #==================================================================
136 #==================================================================
137 # CHANGED FILES
137 # CHANGED FILES
138 #==================================================================
138 #==================================================================
139 if not c.cut_off:
139 if not c.cut_off:
140 for node in changeset.changed:
140 for node in changeset.changed:
141 try:
141 try:
142 filenode_old = changeset_parent.get_node(node.path)
142 filenode_old = changeset_parent.get_node(node.path)
143 except ChangesetError:
143 except ChangesetError:
144 log.warning('Unable to fetch parent node for diff')
144 log.warning('Unable to fetch parent node for diff')
145 filenode_old = FileNode(node.path, '',
145 filenode_old = FileNode(node.path, '',
146 EmptyChangeset())
146 EmptyChangeset())
147
147
148 if filenode_old.is_binary or node.is_binary:
148 if filenode_old.is_binary or node.is_binary:
149 diff = wrap_to_table(_('binary file'))
149 diff = wrap_to_table(_('binary file'))
150 st = (0, 0)
150 st = (0, 0)
151 else:
151 else:
152
152
153 if c.sum_removed < self.cut_off_limit:
153 if c.sum_removed < self.cut_off_limit:
154 f_gitdiff = differ.get_gitdiff(filenode_old, node)
154 f_gitdiff = differ.get_gitdiff(filenode_old, node)
155 d = differ.DiffProcessor(f_gitdiff,
155 d = differ.DiffProcessor(f_gitdiff,
156 format='gitdiff')
156 format='gitdiff')
157 st = d.stat()
157 st = d.stat()
158 if (st[0] + st[1]) * 256 > self.cut_off_limit:
158 if (st[0] + st[1]) * 256 > self.cut_off_limit:
159 diff = wrap_to_table(_('Diff is to big '
159 diff = wrap_to_table(_('Diff is to big '
160 'and was cut off, see '
160 'and was cut off, see '
161 'raw diff instead'))
161 'raw diff instead'))
162 else:
162 else:
163 diff = d.as_html()
163 diff = d.as_html()
164
164
165
166 if diff:
165 if diff:
167 c.sum_removed += len(diff)
166 c.sum_removed += len(diff)
168 else:
167 else:
169 diff = wrap_to_table(_('Changeset is to big and '
168 diff = wrap_to_table(_('Changeset is to big and '
170 'was cut off, see raw '
169 'was cut off, see raw '
171 'changeset instead'))
170 'changeset instead'))
172 c.cut_off = True
171 c.cut_off = True
173 break
172 break
174
173
175 cs1 = filenode_old.last_changeset.raw_id
174 cs1 = filenode_old.last_changeset.raw_id
176 cs2 = node.last_changeset.raw_id
175 cs2 = node.last_changeset.raw_id
177 c.lines_added += st[0]
176 c.lines_added += st[0]
178 c.lines_deleted += st[1]
177 c.lines_deleted += st[1]
179 c.changes[changeset.raw_id].append(('changed', node, diff,
178 c.changes[changeset.raw_id].append(('changed', node, diff,
180 cs1, cs2, st))
179 cs1, cs2, st))
181
180
182 #==================================================================
181 #==================================================================
183 # REMOVED FILES
182 # REMOVED FILES
184 #==================================================================
183 #==================================================================
185 if not c.cut_off:
184 if not c.cut_off:
186 for node in changeset.removed:
185 for node in changeset.removed:
187 c.changes[changeset.raw_id].append(('removed', node, None,
186 c.changes[changeset.raw_id].append(('removed', node, None,
188 None, None, (0, 0)))
187 None, None, (0, 0)))
189
188
190 if len(c.cs_ranges) == 1:
189 if len(c.cs_ranges) == 1:
191 c.changeset = c.cs_ranges[0]
190 c.changeset = c.cs_ranges[0]
192 c.changes = c.changes[c.changeset.raw_id]
191 c.changes = c.changes[c.changeset.raw_id]
193
192
194 return render('changeset/changeset.html')
193 return render('changeset/changeset.html')
195 else:
194 else:
196 return render('changeset/changeset_range.html')
195 return render('changeset/changeset_range.html')
197
196
198 def raw_changeset(self, revision):
197 def raw_changeset(self, revision):
199
198
200 method = request.GET.get('diff', 'show')
199 method = request.GET.get('diff', 'show')
201 try:
200 try:
202 c.scm_type = c.rhodecode_repo.alias
201 c.scm_type = c.rhodecode_repo.alias
203 c.changeset = c.rhodecode_repo.get_changeset(revision)
202 c.changeset = c.rhodecode_repo.get_changeset(revision)
204 except RepositoryError:
203 except RepositoryError:
205 log.error(traceback.format_exc())
204 log.error(traceback.format_exc())
206 return redirect(url('home'))
205 return redirect(url('home'))
207 else:
206 else:
208 try:
207 try:
209 c.changeset_parent = c.changeset.parents[0]
208 c.changeset_parent = c.changeset.parents[0]
210 except IndexError:
209 except IndexError:
211 c.changeset_parent = None
210 c.changeset_parent = None
212 c.changes = []
211 c.changes = []
213
212
214 for node in c.changeset.added:
213 for node in c.changeset.added:
215 filenode_old = FileNode(node.path, '')
214 filenode_old = FileNode(node.path, '')
216 if filenode_old.is_binary or node.is_binary:
215 if filenode_old.is_binary or node.is_binary:
217 diff = _('binary file') + '\n'
216 diff = _('binary file') + '\n'
218 else:
217 else:
219 f_gitdiff = differ.get_gitdiff(filenode_old, node)
218 f_gitdiff = differ.get_gitdiff(filenode_old, node)
220 diff = differ.DiffProcessor(f_gitdiff,
219 diff = differ.DiffProcessor(f_gitdiff,
221 format='gitdiff').raw_diff()
220 format='gitdiff').raw_diff()
222
221
223 cs1 = None
222 cs1 = None
224 cs2 = node.last_changeset.raw_id
223 cs2 = node.last_changeset.raw_id
225 c.changes.append(('added', node, diff, cs1, cs2))
224 c.changes.append(('added', node, diff, cs1, cs2))
226
225
227 for node in c.changeset.changed:
226 for node in c.changeset.changed:
228 filenode_old = c.changeset_parent.get_node(node.path)
227 filenode_old = c.changeset_parent.get_node(node.path)
229 if filenode_old.is_binary or node.is_binary:
228 if filenode_old.is_binary or node.is_binary:
230 diff = _('binary file')
229 diff = _('binary file')
231 else:
230 else:
232 f_gitdiff = differ.get_gitdiff(filenode_old, node)
231 f_gitdiff = differ.get_gitdiff(filenode_old, node)
233 diff = differ.DiffProcessor(f_gitdiff,
232 diff = differ.DiffProcessor(f_gitdiff,
234 format='gitdiff').raw_diff()
233 format='gitdiff').raw_diff()
235
234
236 cs1 = filenode_old.last_changeset.raw_id
235 cs1 = filenode_old.last_changeset.raw_id
237 cs2 = node.last_changeset.raw_id
236 cs2 = node.last_changeset.raw_id
238 c.changes.append(('changed', node, diff, cs1, cs2))
237 c.changes.append(('changed', node, diff, cs1, cs2))
239
238
240 response.content_type = 'text/plain'
239 response.content_type = 'text/plain'
241
240
242 if method == 'download':
241 if method == 'download':
243 response.content_disposition = 'attachment; filename=%s.patch' \
242 response.content_disposition = 'attachment; filename=%s.patch' \
244 % revision
243 % revision
245
244
246 parent = True if len(c.changeset.parents) > 0 else False
245 parent = True if len(c.changeset.parents) > 0 else False
247 c.parent_tmpl = 'Parent %s' \
246 c.parent_tmpl = 'Parent %s' \
248 % c.changeset.parents[0].raw_id if parent else ''
247 % c.changeset.parents[0].raw_id if parent else ''
249
248
250 c.diffs = ''
249 c.diffs = ''
251 for x in c.changes:
250 for x in c.changes:
252 c.diffs += x[2]
251 c.diffs += x[2]
253
252
254 return render('changeset/raw_changeset.html')
253 return render('changeset/raw_changeset.html')
@@ -1,33 +1,32
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${c.repo_name} ${_('Followers')} - ${c.rhodecode_name}
5 ${c.repo_name} ${_('Followers')} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8
9 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
10 ${h.link_to(u'Home',h.url('/'))}
9 ${h.link_to(u'Home',h.url('/'))}
11 &raquo;
10 &raquo;
12 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
13 &raquo;
12 &raquo;
14 ${_('followers')}
13 ${_('followers')}
15 </%def>
14 </%def>
16
15
17 <%def name="page_nav()">
16 <%def name="page_nav()">
18 ${self.menu('followers')}
17 ${self.menu('followers')}
19 </%def>
18 </%def>
20 <%def name="main()">
19 <%def name="main()">
21 <div class="box">
20 <div class="box">
22 <!-- box / title -->
21 <!-- box / title -->
23 <div class="title">
22 <div class="title">
24 ${self.breadcrumbs()}
23 ${self.breadcrumbs()}
25 </div>
24 </div>
26 <!-- end box / title -->
25 <!-- end box / title -->
27 <div class="table">
26 <div class="table">
28 <div id="followers">
27 <div id="followers">
29 ${c.followers_data}
28 ${c.followers_data}
30 </div>
29 </div>
31 </div>
30 </div>
32 </div>
31 </div>
33 </%def> No newline at end of file
32 </%def>
@@ -1,37 +1,36
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3
4 % for f in c.followers_pager:
3 % for f in c.followers_pager:
5 <div>
4 <div>
6 <div class="follower_user">
5 <div class="follower_user">
7 <div class="gravatar">
6 <div class="gravatar">
8 <img alt="gravatar" src="${h.gravatar_url(f.user.email,24)}"/>
7 <img alt="gravatar" src="${h.gravatar_url(f.user.email,24)}"/>
9 </div>
8 </div>
10 <span style="font-size: 20px"> <b>${f.user.username}</b> (${f.user.name} ${f.user.lastname})</span>
9 <span style="font-size: 20px"> <b>${f.user.username}</b> (${f.user.name} ${f.user.lastname})</span>
11 </div>
10 </div>
12 <div style="clear:both;padding-top: 10px"></div>
11 <div style="clear:both;padding-top: 10px"></div>
13 <div class="follower_date">${_('Started following on')} - ${f.follows_from}</div>
12 <div class="follower_date">${_('Started following')} -
13 <span class="tooltip" title="${f.follows_from}"> ${h.age(f.follows_from)}</span></div>
14 <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div>
14 <div style="border-bottom: 1px solid #DDD;margin:10px 0px 10px 0px"></div>
15 </div>
15 </div>
16 % endfor
16 % endfor
17
17
18
19 <div class="pagination-wh pagination-left">
18 <div class="pagination-wh pagination-left">
20 <script type="text/javascript">
19 <script type="text/javascript">
21 var data_div = 'followers';
20 var data_div = 'followers';
22 YAHOO.util.Event.onDOMReady(function(){
21 YAHOO.util.Event.onDOMReady(function(){
23 YAHOO.util.Event.addListener(
22 YAHOO.util.Event.addListener(
24 YUD.getElementsByClassName('pager_link'),"click",
23 YUD.getElementsByClassName('pager_link'),"click",
25 function(){
24 function(){
26 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');
25 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');
27 });
26 });
28 });
27 });
29 </script>
28 </script>
30
29
31 ${c.followers_pager.pager('$link_previous ~2~ $link_next',
30 ${c.followers_pager.pager('$link_previous ~2~ $link_next',
32 onclick="""YAHOO.util.Connect.asyncRequest('GET','$partial_url',{
31 onclick="""YAHOO.util.Connect.asyncRequest('GET','$partial_url',{
33 success:function(o){YAHOO.util.Dom.get(data_div).innerHTML=o.responseText;
32 success:function(o){YAHOO.util.Dom.get(data_div).innerHTML=o.responseText;
34 YUE.on(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
33 YUE.on(YAHOO.util.Dom.getElementsByClassName('pager_link'),"click",function(){
35 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');});
34 YAHOO.util.Dom.setStyle(data_div,'opacity','0.3');});
36 YAHOO.util.Dom.setStyle(data_div,'opacity','1');}},null); return false;""")}
35 YAHOO.util.Dom.setStyle(data_div,'opacity','1');}},null); return false;""")}
37 </div> No newline at end of file
36 </div>
General Comments 0
You need to be logged in to leave comments. Login now