##// END OF EJS Templates
fixes issue when owner of a repo couldn't revoke permissions for users and groups
marcink -
r1829:6f8f1ab2 default
parent child Browse files
Show More
@@ -1,397 +1,398
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.repos
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Admin controller for RhodeCode
7 7
8 8 :created_on: Apr 7, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import traceback
28 28 import formencode
29 29 from formencode import htmlfill
30 30
31 31 from paste.httpexceptions import HTTPInternalServerError
32 32 from pylons import request, response, session, tmpl_context as c, url
33 33 from pylons.controllers.util import abort, redirect
34 34 from pylons.i18n.translation import _
35 35
36 36 from rhodecode.lib import helpers as h
37 37 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
38 HasPermissionAnyDecorator
38 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator
39 39 from rhodecode.lib.base import BaseController, render
40 40 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
41 41 from rhodecode.lib.helpers import get_token
42 42 from rhodecode.model.db import User, Repository, UserFollowing, Group
43 43 from rhodecode.model.forms import RepoForm
44 44 from rhodecode.model.scm import ScmModel
45 45 from rhodecode.model.repo import RepoModel
46 46 from sqlalchemy.exc import IntegrityError
47 47
48 48 log = logging.getLogger(__name__)
49 49
50 50
51 51 class ReposController(BaseController):
52 52 """
53 53 REST Controller styled on the Atom Publishing Protocol"""
54 54 # To properly map this controller, ensure your config/routing.py
55 55 # file has a resource setup:
56 56 # map.resource('repo', 'repos')
57 57
58 58 @LoginRequired()
59 59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
60 60 def __before__(self):
61 61 c.admin_user = session.get('admin_user')
62 62 c.admin_username = session.get('admin_username')
63 63 super(ReposController, self).__before__()
64 64
65 65 def __load_defaults(self):
66 66 c.repo_groups = Group.groups_choices()
67 67 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
68 68
69 69 repo_model = RepoModel()
70 70 c.users_array = repo_model.get_users_js()
71 71 c.users_groups_array = repo_model.get_users_groups_js()
72 72
73 73 def __load_data(self, repo_name=None):
74 74 """
75 75 Load defaults settings for edit, and update
76 76
77 77 :param repo_name:
78 78 """
79 79 self.__load_defaults()
80 80
81 81 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
82 82 repo = db_repo.scm_instance
83 83
84 84 if c.repo_info is None:
85 85 h.flash(_('%s repository is not mapped to db perhaps'
86 86 ' it was created or renamed from the filesystem'
87 87 ' please run the application again'
88 88 ' in order to rescan repositories') % repo_name,
89 89 category='error')
90 90
91 91 return redirect(url('repos'))
92 92
93 93 c.default_user_id = User.get_by_username('default').user_id
94 94 c.in_public_journal = UserFollowing.query()\
95 95 .filter(UserFollowing.user_id == c.default_user_id)\
96 96 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
97 97
98 98 if c.repo_info.stats:
99 99 last_rev = c.repo_info.stats.stat_on_revision
100 100 else:
101 101 last_rev = 0
102 102 c.stats_revision = last_rev
103 103
104 104 c.repo_last_rev = repo.count() - 1 if repo.revisions else 0
105 105
106 106 if last_rev == 0 or c.repo_last_rev == 0:
107 107 c.stats_percentage = 0
108 108 else:
109 109 c.stats_percentage = '%.2f' % ((float((last_rev)) /
110 110 c.repo_last_rev) * 100)
111 111
112 112 defaults = RepoModel()._get_defaults(repo_name)
113 113 return defaults
114 114
115 115 @HasPermissionAllDecorator('hg.admin')
116 116 def index(self, format='html'):
117 117 """GET /repos: All items in the collection"""
118 118 # url('repos')
119 119
120 120 c.repos_list = ScmModel().get_repos(Repository.query()
121 121 .order_by(Repository.repo_name)
122 122 .all(), sort_key='name_sort')
123 123 return render('admin/repos/repos.html')
124 124
125 125 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
126 126 def create(self):
127 127 """
128 128 POST /repos: Create a new item"""
129 129 # url('repos')
130 130 repo_model = RepoModel()
131 131 self.__load_defaults()
132 132 form_result = {}
133 133 try:
134 134 form_result = RepoForm(repo_groups=c.repo_groups_choices)()\
135 135 .to_python(dict(request.POST))
136 136 repo_model.create(form_result, self.rhodecode_user)
137 137 if form_result['clone_uri']:
138 138 h.flash(_('created repository %s from %s') \
139 139 % (form_result['repo_name'], form_result['clone_uri']),
140 140 category='success')
141 141 else:
142 142 h.flash(_('created repository %s') % form_result['repo_name'],
143 143 category='success')
144 144
145 145 if request.POST.get('user_created'):
146 146 #created by regular non admin user
147 147 action_logger(self.rhodecode_user, 'user_created_repo',
148 148 form_result['repo_name_full'], '', self.sa)
149 149 else:
150 150 action_logger(self.rhodecode_user, 'admin_created_repo',
151 151 form_result['repo_name_full'], '', self.sa)
152 152
153 153 except formencode.Invalid, errors:
154 154
155 155 c.new_repo = errors.value['repo_name']
156 156
157 157 if request.POST.get('user_created'):
158 158 r = render('admin/repos/repo_add_create_repository.html')
159 159 else:
160 160 r = render('admin/repos/repo_add.html')
161 161
162 162 return htmlfill.render(
163 163 r,
164 164 defaults=errors.value,
165 165 errors=errors.error_dict or {},
166 166 prefix_error=False,
167 167 encoding="UTF-8")
168 168
169 169 except Exception:
170 170 log.error(traceback.format_exc())
171 171 msg = _('error occurred during creation of repository %s') \
172 172 % form_result.get('repo_name')
173 173 h.flash(msg, category='error')
174 174 if request.POST.get('user_created'):
175 175 return redirect(url('home'))
176 176 return redirect(url('repos'))
177 177
178 178 @HasPermissionAllDecorator('hg.admin')
179 179 def new(self, format='html'):
180 180 """GET /repos/new: Form to create a new item"""
181 181 new_repo = request.GET.get('repo', '')
182 182 c.new_repo = repo_name_slug(new_repo)
183 183 self.__load_defaults()
184 184 return render('admin/repos/repo_add.html')
185 185
186 186 @HasPermissionAllDecorator('hg.admin')
187 187 def update(self, repo_name):
188 188 """
189 189 PUT /repos/repo_name: Update an existing item"""
190 190 # Forms posted to this method should contain a hidden field:
191 191 # <input type="hidden" name="_method" value="PUT" />
192 192 # Or using helpers:
193 193 # h.form(url('repo', repo_name=ID),
194 194 # method='put')
195 195 # url('repo', repo_name=ID)
196 196 self.__load_defaults()
197 197 repo_model = RepoModel()
198 198 changed_name = repo_name
199 199 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
200 200 repo_groups=c.repo_groups_choices)()
201 201 try:
202 202 form_result = _form.to_python(dict(request.POST))
203 203 repo = repo_model.update(repo_name, form_result)
204 204 invalidate_cache('get_repo_cached_%s' % repo_name)
205 205 h.flash(_('Repository %s updated successfully' % repo_name),
206 206 category='success')
207 207 changed_name = repo.repo_name
208 208 action_logger(self.rhodecode_user, 'admin_updated_repo',
209 209 changed_name, '', self.sa)
210 210
211 211 except formencode.Invalid, errors:
212 212 defaults = self.__load_data(repo_name)
213 213 defaults.update(errors.value)
214 214 return htmlfill.render(
215 215 render('admin/repos/repo_edit.html'),
216 216 defaults=defaults,
217 217 errors=errors.error_dict or {},
218 218 prefix_error=False,
219 219 encoding="UTF-8")
220 220
221 221 except Exception:
222 222 log.error(traceback.format_exc())
223 223 h.flash(_('error occurred during update of repository %s') \
224 224 % repo_name, category='error')
225 225 return redirect(url('edit_repo', repo_name=changed_name))
226 226
227 227 @HasPermissionAllDecorator('hg.admin')
228 228 def delete(self, repo_name):
229 229 """
230 230 DELETE /repos/repo_name: Delete an existing item"""
231 231 # Forms posted to this method should contain a hidden field:
232 232 # <input type="hidden" name="_method" value="DELETE" />
233 233 # Or using helpers:
234 234 # h.form(url('repo', repo_name=ID),
235 235 # method='delete')
236 236 # url('repo', repo_name=ID)
237 237
238 238 repo_model = RepoModel()
239 239 repo = repo_model.get_by_repo_name(repo_name)
240 240 if not repo:
241 241 h.flash(_('%s repository is not mapped to db perhaps'
242 242 ' it was moved or renamed from the filesystem'
243 243 ' please run the application again'
244 244 ' in order to rescan repositories') % repo_name,
245 245 category='error')
246 246
247 247 return redirect(url('repos'))
248 248 try:
249 249 action_logger(self.rhodecode_user, 'admin_deleted_repo',
250 250 repo_name, '', self.sa)
251 251 repo_model.delete(repo)
252 252 invalidate_cache('get_repo_cached_%s' % repo_name)
253 253 h.flash(_('deleted repository %s') % repo_name, category='success')
254 254
255 255 except IntegrityError, e:
256 256 if e.message.find('repositories_fork_id_fkey'):
257 257 log.error(traceback.format_exc())
258 258 h.flash(_('Cannot delete %s it still contains attached '
259 259 'forks') % repo_name,
260 260 category='warning')
261 261 else:
262 262 log.error(traceback.format_exc())
263 263 h.flash(_('An error occurred during '
264 264 'deletion of %s') % repo_name,
265 265 category='error')
266 266
267 267 except Exception, e:
268 268 log.error(traceback.format_exc())
269 269 h.flash(_('An error occurred during deletion of %s') % repo_name,
270 270 category='error')
271 271
272 272 return redirect(url('repos'))
273 273
274 @HasPermissionAllDecorator('hg.admin')
274
275 @HasRepoPermissionAllDecorator('repository.admin')
275 276 def delete_perm_user(self, repo_name):
276 277 """
277 278 DELETE an existing repository permission user
278 279
279 280 :param repo_name:
280 281 """
281 282
282 283 try:
283 284 repo_model = RepoModel()
284 285 repo_model.delete_perm_user(request.POST, repo_name)
285 286 except Exception, e:
286 287 h.flash(_('An error occurred during deletion of repository user'),
287 288 category='error')
288 289 raise HTTPInternalServerError()
289 290
290 @HasPermissionAllDecorator('hg.admin')
291 @HasRepoPermissionAllDecorator('repository.admin')
291 292 def delete_perm_users_group(self, repo_name):
292 293 """
293 294 DELETE an existing repository permission users group
294 295
295 296 :param repo_name:
296 297 """
297 298 try:
298 299 repo_model = RepoModel()
299 300 repo_model.delete_perm_users_group(request.POST, repo_name)
300 301 except Exception, e:
301 302 h.flash(_('An error occurred during deletion of repository'
302 303 ' users groups'),
303 304 category='error')
304 305 raise HTTPInternalServerError()
305 306
306 307 @HasPermissionAllDecorator('hg.admin')
307 308 def repo_stats(self, repo_name):
308 309 """
309 310 DELETE an existing repository statistics
310 311
311 312 :param repo_name:
312 313 """
313 314
314 315 try:
315 316 repo_model = RepoModel()
316 317 repo_model.delete_stats(repo_name)
317 318 except Exception, e:
318 319 h.flash(_('An error occurred during deletion of repository stats'),
319 320 category='error')
320 321 return redirect(url('edit_repo', repo_name=repo_name))
321 322
322 323 @HasPermissionAllDecorator('hg.admin')
323 324 def repo_cache(self, repo_name):
324 325 """
325 326 INVALIDATE existing repository cache
326 327
327 328 :param repo_name:
328 329 """
329 330
330 331 try:
331 332 ScmModel().mark_for_invalidation(repo_name)
332 333 except Exception, e:
333 334 h.flash(_('An error occurred during cache invalidation'),
334 335 category='error')
335 336 return redirect(url('edit_repo', repo_name=repo_name))
336 337
337 338 @HasPermissionAllDecorator('hg.admin')
338 339 def repo_public_journal(self, repo_name):
339 340 """
340 341 Set's this repository to be visible in public journal,
341 342 in other words assing default user to follow this repo
342 343
343 344 :param repo_name:
344 345 """
345 346
346 347 cur_token = request.POST.get('auth_token')
347 348 token = get_token()
348 349 if cur_token == token:
349 350 try:
350 351 repo_id = Repository.get_by_repo_name(repo_name).repo_id
351 352 user_id = User.get_by_username('default').user_id
352 353 self.scm_model.toggle_following_repo(repo_id, user_id)
353 354 h.flash(_('Updated repository visibility in public journal'),
354 355 category='success')
355 356 except:
356 357 h.flash(_('An error occurred during setting this'
357 358 ' repository in public journal'),
358 359 category='error')
359 360
360 361 else:
361 362 h.flash(_('Token mismatch'), category='error')
362 363 return redirect(url('edit_repo', repo_name=repo_name))
363 364
364 365 @HasPermissionAllDecorator('hg.admin')
365 366 def repo_pull(self, repo_name):
366 367 """
367 368 Runs task to update given repository with remote changes,
368 369 ie. make pull on remote location
369 370
370 371 :param repo_name:
371 372 """
372 373 try:
373 374 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
374 375 h.flash(_('Pulled from remote location'), category='success')
375 376 except Exception, e:
376 377 h.flash(_('An error occurred during pull from remote location'),
377 378 category='error')
378 379
379 380 return redirect(url('edit_repo', repo_name=repo_name))
380 381
381 382 @HasPermissionAllDecorator('hg.admin')
382 383 def show(self, repo_name, format='html'):
383 384 """GET /repos/repo_name: Show a specific item"""
384 385 # url('repo', repo_name=ID)
385 386
386 387 @HasPermissionAllDecorator('hg.admin')
387 388 def edit(self, repo_name, format='html'):
388 389 """GET /repos/repo_name/edit: Form to edit an existing item"""
389 390 # url('edit_repo', repo_name=ID)
390 391 defaults = self.__load_data(repo_name)
391 392
392 393 return htmlfill.render(
393 394 render('admin/repos/repo_edit.html'),
394 395 defaults=defaults,
395 396 encoding="UTF-8",
396 397 force_defaults=False
397 398 )
General Comments 0
You need to be logged in to leave comments. Login now