##// END OF EJS Templates
Fix for #378
Erwin Kroon -
r2070:c238df8c default
parent child Browse files
Show More
@@ -1,367 +1,367 b''
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) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 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 from collections import defaultdict
28 from collections import defaultdict
29 from webob.exc import HTTPForbidden
29 from webob.exc import HTTPForbidden
30
30
31 from pylons import tmpl_context as c, url, request, response
31 from pylons import tmpl_context as c, url, request, response
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.decorators import jsonify
34 from pylons.decorators import jsonify
35
35
36 from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetError, \
36 from rhodecode.lib.vcs.exceptions import RepositoryError, ChangesetError, \
37 ChangesetDoesNotExistError
37 ChangesetDoesNotExistError
38 from rhodecode.lib.vcs.nodes import FileNode
38 from rhodecode.lib.vcs.nodes import FileNode
39
39
40 import rhodecode.lib.helpers as h
40 import rhodecode.lib.helpers as h
41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.utils import EmptyChangeset
43 from rhodecode.lib.utils import EmptyChangeset
44 from rhodecode.lib.compat import OrderedDict
44 from rhodecode.lib.compat import OrderedDict
45 from rhodecode.lib import diffs
45 from rhodecode.lib import diffs
46 from rhodecode.model.db import ChangesetComment
46 from rhodecode.model.db import ChangesetComment
47 from rhodecode.model.comment import ChangesetCommentsModel
47 from rhodecode.model.comment import ChangesetCommentsModel
48 from rhodecode.model.meta import Session
48 from rhodecode.model.meta import Session
49 from rhodecode.lib.diffs import wrapped_diff
49 from rhodecode.lib.diffs import wrapped_diff
50
50
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53
53
54 def anchor_url(revision, path):
54 def anchor_url(revision, path):
55 fid = h.FID(revision, path)
55 fid = h.FID(revision, path)
56 return h.url.current(anchor=fid, **request.GET)
56 return h.url.current(anchor=fid, **request.GET)
57
57
58
58
59 def get_ignore_ws(fid, GET):
59 def get_ignore_ws(fid, GET):
60 ig_ws_global = request.GET.get('ignorews')
60 ig_ws_global = request.GET.get('ignorews')
61 ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
61 ig_ws = filter(lambda k: k.startswith('WS'), GET.getall(fid))
62 if ig_ws:
62 if ig_ws:
63 try:
63 try:
64 return int(ig_ws[0].split(':')[-1])
64 return int(ig_ws[0].split(':')[-1])
65 except:
65 except:
66 pass
66 pass
67 return ig_ws_global
67 return ig_ws_global
68
68
69
69
70 def _ignorews_url(fileid=None):
70 def _ignorews_url(fileid=None):
71
71
72 params = defaultdict(list)
72 params = defaultdict(list)
73 lbl = _('show white space')
73 lbl = _('show white space')
74 ig_ws = get_ignore_ws(fileid, request.GET)
74 ig_ws = get_ignore_ws(fileid, request.GET)
75 ln_ctx = get_line_ctx(fileid, request.GET)
75 ln_ctx = get_line_ctx(fileid, request.GET)
76 # global option
76 # global option
77 if fileid is None:
77 if fileid is None:
78 if ig_ws is None:
78 if ig_ws is None:
79 params['ignorews'] += [1]
79 params['ignorews'] += [1]
80 lbl = _('ignore white space')
80 lbl = _('ignore white space')
81 ctx_key = 'context'
81 ctx_key = 'context'
82 ctx_val = ln_ctx
82 ctx_val = ln_ctx
83 # per file options
83 # per file options
84 else:
84 else:
85 if ig_ws is None:
85 if ig_ws is None:
86 params[fileid] += ['WS:1']
86 params[fileid] += ['WS:1']
87 lbl = _('ignore white space')
87 lbl = _('ignore white space')
88
88
89 ctx_key = fileid
89 ctx_key = fileid
90 ctx_val = 'C:%s' % ln_ctx
90 ctx_val = 'C:%s' % ln_ctx
91 # if we have passed in ln_ctx pass it along to our params
91 # if we have passed in ln_ctx pass it along to our params
92 if ln_ctx:
92 if ln_ctx:
93 params[ctx_key] += [ctx_val]
93 params[ctx_key] += [ctx_val]
94
94
95 params['anchor'] = fileid
95 params['anchor'] = fileid
96 img = h.image('/images/icons/text_strikethrough.png', lbl, class_='icon')
96 img = h.image(h.url('/images/icons/text_strikethrough.png'), lbl, class_='icon')
97 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
97 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
98
98
99
99
100 def get_line_ctx(fid, GET):
100 def get_line_ctx(fid, GET):
101 ln_ctx_global = request.GET.get('context')
101 ln_ctx_global = request.GET.get('context')
102 ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
102 ln_ctx = filter(lambda k: k.startswith('C'), GET.getall(fid))
103
103
104 if ln_ctx:
104 if ln_ctx:
105 retval = ln_ctx[0].split(':')[-1]
105 retval = ln_ctx[0].split(':')[-1]
106 else:
106 else:
107 retval = ln_ctx_global
107 retval = ln_ctx_global
108
108
109 try:
109 try:
110 return int(retval)
110 return int(retval)
111 except:
111 except:
112 return
112 return
113
113
114
114
115 def _context_url(fileid=None):
115 def _context_url(fileid=None):
116 """
116 """
117 Generates url for context lines
117 Generates url for context lines
118
118
119 :param fileid:
119 :param fileid:
120 """
120 """
121 ig_ws = get_ignore_ws(fileid, request.GET)
121 ig_ws = get_ignore_ws(fileid, request.GET)
122 ln_ctx = (get_line_ctx(fileid, request.GET) or 3) * 2
122 ln_ctx = (get_line_ctx(fileid, request.GET) or 3) * 2
123
123
124 params = defaultdict(list)
124 params = defaultdict(list)
125
125
126 # global option
126 # global option
127 if fileid is None:
127 if fileid is None:
128 if ln_ctx > 0:
128 if ln_ctx > 0:
129 params['context'] += [ln_ctx]
129 params['context'] += [ln_ctx]
130
130
131 if ig_ws:
131 if ig_ws:
132 ig_ws_key = 'ignorews'
132 ig_ws_key = 'ignorews'
133 ig_ws_val = 1
133 ig_ws_val = 1
134
134
135 # per file option
135 # per file option
136 else:
136 else:
137 params[fileid] += ['C:%s' % ln_ctx]
137 params[fileid] += ['C:%s' % ln_ctx]
138 ig_ws_key = fileid
138 ig_ws_key = fileid
139 ig_ws_val = 'WS:%s' % 1
139 ig_ws_val = 'WS:%s' % 1
140
140
141 if ig_ws:
141 if ig_ws:
142 params[ig_ws_key] += [ig_ws_val]
142 params[ig_ws_key] += [ig_ws_val]
143
143
144 lbl = _('%s line context') % ln_ctx
144 lbl = _('%s line context') % ln_ctx
145
145
146 params['anchor'] = fileid
146 params['anchor'] = fileid
147 img = h.image('/images/icons/table_add.png', lbl, class_='icon')
147 img = h.image(h.url('/images/icons/table_add.png'), lbl, class_='icon')
148 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
148 return h.link_to(img, h.url.current(**params), title=lbl, class_='tooltip')
149
149
150
150
151 class ChangesetController(BaseRepoController):
151 class ChangesetController(BaseRepoController):
152
152
153 @LoginRequired()
153 @LoginRequired()
154 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
154 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
155 'repository.admin')
155 'repository.admin')
156 def __before__(self):
156 def __before__(self):
157 super(ChangesetController, self).__before__()
157 super(ChangesetController, self).__before__()
158 c.affected_files_cut_off = 60
158 c.affected_files_cut_off = 60
159
159
160 def index(self, revision):
160 def index(self, revision):
161
161
162 c.anchor_url = anchor_url
162 c.anchor_url = anchor_url
163 c.ignorews_url = _ignorews_url
163 c.ignorews_url = _ignorews_url
164 c.context_url = _context_url
164 c.context_url = _context_url
165
165
166 #get ranges of revisions if preset
166 #get ranges of revisions if preset
167 rev_range = revision.split('...')[:2]
167 rev_range = revision.split('...')[:2]
168 enable_comments = True
168 enable_comments = True
169 try:
169 try:
170 if len(rev_range) == 2:
170 if len(rev_range) == 2:
171 enable_comments = False
171 enable_comments = False
172 rev_start = rev_range[0]
172 rev_start = rev_range[0]
173 rev_end = rev_range[1]
173 rev_end = rev_range[1]
174 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
174 rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start,
175 end=rev_end)
175 end=rev_end)
176 else:
176 else:
177 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
177 rev_ranges = [c.rhodecode_repo.get_changeset(revision)]
178
178
179 c.cs_ranges = list(rev_ranges)
179 c.cs_ranges = list(rev_ranges)
180 if not c.cs_ranges:
180 if not c.cs_ranges:
181 raise RepositoryError('Changeset range returned empty result')
181 raise RepositoryError('Changeset range returned empty result')
182
182
183 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
183 except (RepositoryError, ChangesetDoesNotExistError, Exception), e:
184 log.error(traceback.format_exc())
184 log.error(traceback.format_exc())
185 h.flash(str(e), category='warning')
185 h.flash(str(e), category='warning')
186 return redirect(url('home'))
186 return redirect(url('home'))
187
187
188 c.changes = OrderedDict()
188 c.changes = OrderedDict()
189
189
190 c.lines_added = 0 # count of lines added
190 c.lines_added = 0 # count of lines added
191 c.lines_deleted = 0 # count of lines removes
191 c.lines_deleted = 0 # count of lines removes
192
192
193 cumulative_diff = 0
193 cumulative_diff = 0
194 c.cut_off = False # defines if cut off limit is reached
194 c.cut_off = False # defines if cut off limit is reached
195
195
196 c.comments = []
196 c.comments = []
197 c.inline_comments = []
197 c.inline_comments = []
198 c.inline_cnt = 0
198 c.inline_cnt = 0
199 # Iterate over ranges (default changeset view is always one changeset)
199 # Iterate over ranges (default changeset view is always one changeset)
200 for changeset in c.cs_ranges:
200 for changeset in c.cs_ranges:
201 c.comments.extend(ChangesetCommentsModel()\
201 c.comments.extend(ChangesetCommentsModel()\
202 .get_comments(c.rhodecode_db_repo.repo_id,
202 .get_comments(c.rhodecode_db_repo.repo_id,
203 changeset.raw_id))
203 changeset.raw_id))
204 inlines = ChangesetCommentsModel()\
204 inlines = ChangesetCommentsModel()\
205 .get_inline_comments(c.rhodecode_db_repo.repo_id,
205 .get_inline_comments(c.rhodecode_db_repo.repo_id,
206 changeset.raw_id)
206 changeset.raw_id)
207 c.inline_comments.extend(inlines)
207 c.inline_comments.extend(inlines)
208 c.changes[changeset.raw_id] = []
208 c.changes[changeset.raw_id] = []
209 try:
209 try:
210 changeset_parent = changeset.parents[0]
210 changeset_parent = changeset.parents[0]
211 except IndexError:
211 except IndexError:
212 changeset_parent = None
212 changeset_parent = None
213
213
214 #==================================================================
214 #==================================================================
215 # ADDED FILES
215 # ADDED FILES
216 #==================================================================
216 #==================================================================
217 for node in changeset.added:
217 for node in changeset.added:
218 fid = h.FID(revision, node.path)
218 fid = h.FID(revision, node.path)
219 line_context_lcl = get_line_ctx(fid, request.GET)
219 line_context_lcl = get_line_ctx(fid, request.GET)
220 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
220 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
221 lim = self.cut_off_limit
221 lim = self.cut_off_limit
222 if cumulative_diff > self.cut_off_limit:
222 if cumulative_diff > self.cut_off_limit:
223 lim = -1
223 lim = -1
224 size, cs1, cs2, diff, st = wrapped_diff(filenode_old=None,
224 size, cs1, cs2, diff, st = wrapped_diff(filenode_old=None,
225 filenode_new=node,
225 filenode_new=node,
226 cut_off_limit=lim,
226 cut_off_limit=lim,
227 ignore_whitespace=ign_whitespace_lcl,
227 ignore_whitespace=ign_whitespace_lcl,
228 line_context=line_context_lcl,
228 line_context=line_context_lcl,
229 enable_comments=enable_comments)
229 enable_comments=enable_comments)
230 cumulative_diff += size
230 cumulative_diff += size
231 c.lines_added += st[0]
231 c.lines_added += st[0]
232 c.lines_deleted += st[1]
232 c.lines_deleted += st[1]
233 c.changes[changeset.raw_id].append(('added', node, diff,
233 c.changes[changeset.raw_id].append(('added', node, diff,
234 cs1, cs2, st))
234 cs1, cs2, st))
235
235
236 #==================================================================
236 #==================================================================
237 # CHANGED FILES
237 # CHANGED FILES
238 #==================================================================
238 #==================================================================
239 for node in changeset.changed:
239 for node in changeset.changed:
240 try:
240 try:
241 filenode_old = changeset_parent.get_node(node.path)
241 filenode_old = changeset_parent.get_node(node.path)
242 except ChangesetError:
242 except ChangesetError:
243 log.warning('Unable to fetch parent node for diff')
243 log.warning('Unable to fetch parent node for diff')
244 filenode_old = FileNode(node.path, '', EmptyChangeset())
244 filenode_old = FileNode(node.path, '', EmptyChangeset())
245
245
246 fid = h.FID(revision, node.path)
246 fid = h.FID(revision, node.path)
247 line_context_lcl = get_line_ctx(fid, request.GET)
247 line_context_lcl = get_line_ctx(fid, request.GET)
248 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
248 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
249 lim = self.cut_off_limit
249 lim = self.cut_off_limit
250 if cumulative_diff > self.cut_off_limit:
250 if cumulative_diff > self.cut_off_limit:
251 lim = -1
251 lim = -1
252 size, cs1, cs2, diff, st = wrapped_diff(filenode_old=filenode_old,
252 size, cs1, cs2, diff, st = wrapped_diff(filenode_old=filenode_old,
253 filenode_new=node,
253 filenode_new=node,
254 cut_off_limit=lim,
254 cut_off_limit=lim,
255 ignore_whitespace=ign_whitespace_lcl,
255 ignore_whitespace=ign_whitespace_lcl,
256 line_context=line_context_lcl,
256 line_context=line_context_lcl,
257 enable_comments=enable_comments)
257 enable_comments=enable_comments)
258 cumulative_diff += size
258 cumulative_diff += size
259 c.lines_added += st[0]
259 c.lines_added += st[0]
260 c.lines_deleted += st[1]
260 c.lines_deleted += st[1]
261 c.changes[changeset.raw_id].append(('changed', node, diff,
261 c.changes[changeset.raw_id].append(('changed', node, diff,
262 cs1, cs2, st))
262 cs1, cs2, st))
263
263
264 #==================================================================
264 #==================================================================
265 # REMOVED FILES
265 # REMOVED FILES
266 #==================================================================
266 #==================================================================
267 for node in changeset.removed:
267 for node in changeset.removed:
268 c.changes[changeset.raw_id].append(('removed', node, None,
268 c.changes[changeset.raw_id].append(('removed', node, None,
269 None, None, (0, 0)))
269 None, None, (0, 0)))
270
270
271 # count inline comments
271 # count inline comments
272 for path, lines in c.inline_comments:
272 for path, lines in c.inline_comments:
273 for comments in lines.values():
273 for comments in lines.values():
274 c.inline_cnt += len(comments)
274 c.inline_cnt += len(comments)
275
275
276 if len(c.cs_ranges) == 1:
276 if len(c.cs_ranges) == 1:
277 c.changeset = c.cs_ranges[0]
277 c.changeset = c.cs_ranges[0]
278 c.changes = c.changes[c.changeset.raw_id]
278 c.changes = c.changes[c.changeset.raw_id]
279
279
280 return render('changeset/changeset.html')
280 return render('changeset/changeset.html')
281 else:
281 else:
282 return render('changeset/changeset_range.html')
282 return render('changeset/changeset_range.html')
283
283
284 def raw_changeset(self, revision):
284 def raw_changeset(self, revision):
285
285
286 method = request.GET.get('diff', 'show')
286 method = request.GET.get('diff', 'show')
287 ignore_whitespace = request.GET.get('ignorews') == '1'
287 ignore_whitespace = request.GET.get('ignorews') == '1'
288 line_context = request.GET.get('context', 3)
288 line_context = request.GET.get('context', 3)
289 try:
289 try:
290 c.scm_type = c.rhodecode_repo.alias
290 c.scm_type = c.rhodecode_repo.alias
291 c.changeset = c.rhodecode_repo.get_changeset(revision)
291 c.changeset = c.rhodecode_repo.get_changeset(revision)
292 except RepositoryError:
292 except RepositoryError:
293 log.error(traceback.format_exc())
293 log.error(traceback.format_exc())
294 return redirect(url('home'))
294 return redirect(url('home'))
295 else:
295 else:
296 try:
296 try:
297 c.changeset_parent = c.changeset.parents[0]
297 c.changeset_parent = c.changeset.parents[0]
298 except IndexError:
298 except IndexError:
299 c.changeset_parent = None
299 c.changeset_parent = None
300 c.changes = []
300 c.changes = []
301
301
302 for node in c.changeset.added:
302 for node in c.changeset.added:
303 filenode_old = FileNode(node.path, '')
303 filenode_old = FileNode(node.path, '')
304 if filenode_old.is_binary or node.is_binary:
304 if filenode_old.is_binary or node.is_binary:
305 diff = _('binary file') + '\n'
305 diff = _('binary file') + '\n'
306 else:
306 else:
307 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
307 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
308 ignore_whitespace=ignore_whitespace,
308 ignore_whitespace=ignore_whitespace,
309 context=line_context)
309 context=line_context)
310 diff = diffs.DiffProcessor(f_gitdiff,
310 diff = diffs.DiffProcessor(f_gitdiff,
311 format='gitdiff').raw_diff()
311 format='gitdiff').raw_diff()
312
312
313 cs1 = None
313 cs1 = None
314 cs2 = node.last_changeset.raw_id
314 cs2 = node.last_changeset.raw_id
315 c.changes.append(('added', node, diff, cs1, cs2))
315 c.changes.append(('added', node, diff, cs1, cs2))
316
316
317 for node in c.changeset.changed:
317 for node in c.changeset.changed:
318 filenode_old = c.changeset_parent.get_node(node.path)
318 filenode_old = c.changeset_parent.get_node(node.path)
319 if filenode_old.is_binary or node.is_binary:
319 if filenode_old.is_binary or node.is_binary:
320 diff = _('binary file')
320 diff = _('binary file')
321 else:
321 else:
322 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
322 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
323 ignore_whitespace=ignore_whitespace,
323 ignore_whitespace=ignore_whitespace,
324 context=line_context)
324 context=line_context)
325 diff = diffs.DiffProcessor(f_gitdiff,
325 diff = diffs.DiffProcessor(f_gitdiff,
326 format='gitdiff').raw_diff()
326 format='gitdiff').raw_diff()
327
327
328 cs1 = filenode_old.last_changeset.raw_id
328 cs1 = filenode_old.last_changeset.raw_id
329 cs2 = node.last_changeset.raw_id
329 cs2 = node.last_changeset.raw_id
330 c.changes.append(('changed', node, diff, cs1, cs2))
330 c.changes.append(('changed', node, diff, cs1, cs2))
331
331
332 response.content_type = 'text/plain'
332 response.content_type = 'text/plain'
333
333
334 if method == 'download':
334 if method == 'download':
335 response.content_disposition = 'attachment; filename=%s.patch' \
335 response.content_disposition = 'attachment; filename=%s.patch' \
336 % revision
336 % revision
337
337
338 c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id for x in
338 c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id for x in
339 c.changeset.parents])
339 c.changeset.parents])
340
340
341 c.diffs = ''
341 c.diffs = ''
342 for x in c.changes:
342 for x in c.changes:
343 c.diffs += x[2]
343 c.diffs += x[2]
344
344
345 return render('changeset/raw_changeset.html')
345 return render('changeset/raw_changeset.html')
346
346
347 def comment(self, repo_name, revision):
347 def comment(self, repo_name, revision):
348 ChangesetCommentsModel().create(text=request.POST.get('text'),
348 ChangesetCommentsModel().create(text=request.POST.get('text'),
349 repo_id=c.rhodecode_db_repo.repo_id,
349 repo_id=c.rhodecode_db_repo.repo_id,
350 user_id=c.rhodecode_user.user_id,
350 user_id=c.rhodecode_user.user_id,
351 revision=revision,
351 revision=revision,
352 f_path=request.POST.get('f_path'),
352 f_path=request.POST.get('f_path'),
353 line_no=request.POST.get('line'))
353 line_no=request.POST.get('line'))
354 Session.commit()
354 Session.commit()
355 return redirect(h.url('changeset_home', repo_name=repo_name,
355 return redirect(h.url('changeset_home', repo_name=repo_name,
356 revision=revision))
356 revision=revision))
357
357
358 @jsonify
358 @jsonify
359 def delete_comment(self, repo_name, comment_id):
359 def delete_comment(self, repo_name, comment_id):
360 co = ChangesetComment.get(comment_id)
360 co = ChangesetComment.get(comment_id)
361 owner = lambda: co.author.user_id == c.rhodecode_user.user_id
361 owner = lambda: co.author.user_id == c.rhodecode_user.user_id
362 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
362 if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner:
363 ChangesetCommentsModel().delete(comment=co)
363 ChangesetCommentsModel().delete(comment=co)
364 Session.commit()
364 Session.commit()
365 return True
365 return True
366 else:
366 else:
367 raise HTTPForbidden()
367 raise HTTPForbidden()
General Comments 0
You need to be logged in to leave comments. Login now