##// END OF EJS Templates
fix redirection on repo create failures
marcink -
r2707:aa897677 beta
parent child Browse files
Show More
@@ -1,486 +1,487 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.admin.repos
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Repositories controller for RhodeCode
7 7
8 8 :created_on: Apr 7, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 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 webob.exc import HTTPInternalServerError
32 32 from pylons import request, session, tmpl_context as c, url
33 33 from pylons.controllers.util import redirect
34 34 from pylons.i18n.translation import _
35 35 from sqlalchemy.exc import IntegrityError
36 36
37 37 import rhodecode
38 38 from rhodecode.lib import helpers as h
39 39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 40 HasPermissionAnyDecorator, HasRepoPermissionAllDecorator
41 41 from rhodecode.lib.base import BaseController, render
42 42 from rhodecode.lib.utils import invalidate_cache, action_logger, repo_name_slug
43 43 from rhodecode.lib.helpers import get_token
44 44 from rhodecode.model.meta import Session
45 45 from rhodecode.model.db import User, Repository, UserFollowing, RepoGroup
46 46 from rhodecode.model.forms import RepoForm
47 47 from rhodecode.model.scm import ScmModel
48 48 from rhodecode.model.repo import RepoModel
49 49 from rhodecode.lib.compat import json
50 50
51 51 log = logging.getLogger(__name__)
52 52
53 53
54 54 class ReposController(BaseController):
55 55 """
56 56 REST Controller styled on the Atom Publishing Protocol"""
57 57 # To properly map this controller, ensure your config/routing.py
58 58 # file has a resource setup:
59 59 # map.resource('repo', 'repos')
60 60
61 61 @LoginRequired()
62 62 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
63 63 def __before__(self):
64 64 c.admin_user = session.get('admin_user')
65 65 c.admin_username = session.get('admin_username')
66 66 super(ReposController, self).__before__()
67 67
68 68 def __load_defaults(self):
69 69 c.repo_groups = RepoGroup.groups_choices()
70 70 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
71 71
72 72 repo_model = RepoModel()
73 73 c.users_array = repo_model.get_users_js()
74 74 c.users_groups_array = repo_model.get_users_groups_js()
75 75 choices, c.landing_revs = ScmModel().get_repo_landing_revs()
76 76 c.landing_revs_choices = choices
77 77
78 78 def __load_data(self, repo_name=None):
79 79 """
80 80 Load defaults settings for edit, and update
81 81
82 82 :param repo_name:
83 83 """
84 84 self.__load_defaults()
85 85
86 86 c.repo_info = db_repo = Repository.get_by_repo_name(repo_name)
87 87 repo = db_repo.scm_instance
88 88
89 89 if c.repo_info is None:
90 90 h.flash(_('%s repository is not mapped to db perhaps'
91 91 ' it was created or renamed from the filesystem'
92 92 ' please run the application again'
93 93 ' in order to rescan repositories') % repo_name,
94 94 category='error')
95 95
96 96 return redirect(url('repos'))
97 97
98 98 choices, c.landing_revs = ScmModel().get_repo_landing_revs(c.repo_info)
99 99 c.landing_revs_choices = choices
100 100
101 101 c.default_user_id = User.get_by_username('default').user_id
102 102 c.in_public_journal = UserFollowing.query()\
103 103 .filter(UserFollowing.user_id == c.default_user_id)\
104 104 .filter(UserFollowing.follows_repository == c.repo_info).scalar()
105 105
106 106 if c.repo_info.stats:
107 107 # this is on what revision we ended up so we add +1 for count
108 108 last_rev = c.repo_info.stats.stat_on_revision + 1
109 109 else:
110 110 last_rev = 0
111 111 c.stats_revision = last_rev
112 112
113 113 c.repo_last_rev = repo.count() if repo.revisions else 0
114 114
115 115 if last_rev == 0 or c.repo_last_rev == 0:
116 116 c.stats_percentage = 0
117 117 else:
118 118 c.stats_percentage = '%.2f' % ((float((last_rev)) /
119 119 c.repo_last_rev) * 100)
120 120
121 121 defaults = RepoModel()._get_defaults(repo_name)
122 122
123 123 c.repos_list = [('', _('--REMOVE FORK--'))]
124 124 c.repos_list += [(x.repo_id, x.repo_name) for x in
125 125 Repository.query().order_by(Repository.repo_name).all()
126 126 if x.repo_id != c.repo_info.repo_id]
127 127
128 128 defaults['id_fork_of'] = db_repo.fork.repo_id if db_repo.fork else ''
129 129 return defaults
130 130
131 131 @HasPermissionAllDecorator('hg.admin')
132 132 def index(self, format='html'):
133 133 """GET /repos: All items in the collection"""
134 134 # url('repos')
135 135
136 136 c.repos_list = Repository.query()\
137 137 .order_by(Repository.repo_name)\
138 138 .all()
139 139
140 140 repos_data = []
141 141 total_records = len(c.repos_list)
142 142
143 143 _tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
144 144 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
145 145
146 146 quick_menu = lambda repo_name: (template.get_def("quick_menu")
147 147 .render(repo_name, _=_, h=h, c=c))
148 148 repo_lnk = lambda name, rtype, private, fork_of: (
149 149 template.get_def("repo_name")
150 150 .render(name, rtype, private, fork_of, short_name=False,
151 151 admin=True, _=_, h=h, c=c))
152 152
153 153 repo_actions = lambda repo_name: (template.get_def("repo_actions")
154 154 .render(repo_name, _=_, h=h, c=c))
155 155
156 156 for repo in c.repos_list:
157 157 repos_data.append({
158 158 "menu": quick_menu(repo.repo_name),
159 159 "raw_name": repo.repo_name,
160 160 "name": repo_lnk(repo.repo_name, repo.repo_type,
161 161 repo.private, repo.fork),
162 162 "desc": repo.description,
163 163 "owner": repo.user.username,
164 164 "action": repo_actions(repo.repo_name),
165 165 })
166 166
167 167 c.data = json.dumps({
168 168 "totalRecords": total_records,
169 169 "startIndex": 0,
170 170 "sort": "name",
171 171 "dir": "asc",
172 172 "records": repos_data
173 173 })
174 174
175 175 return render('admin/repos/repos.html')
176 176
177 177 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
178 178 def create(self):
179 179 """
180 180 POST /repos: Create a new item"""
181 181 # url('repos')
182 182
183 183 self.__load_defaults()
184 184 form_result = {}
185 185 try:
186 186 form_result = RepoForm(repo_groups=c.repo_groups_choices,
187 187 landing_revs=c.landing_revs_choices)()\
188 188 .to_python(dict(request.POST))
189 189 new_repo = RepoModel().create(form_result,
190 190 self.rhodecode_user.user_id)
191 191 if form_result['clone_uri']:
192 192 h.flash(_('created repository %s from %s') \
193 193 % (form_result['repo_name'], form_result['clone_uri']),
194 194 category='success')
195 195 else:
196 196 h.flash(_('created repository %s') % form_result['repo_name'],
197 197 category='success')
198 198
199 199 if request.POST.get('user_created'):
200 200 # created by regular non admin user
201 201 action_logger(self.rhodecode_user, 'user_created_repo',
202 202 form_result['repo_name_full'], self.ip_addr,
203 203 self.sa)
204 204 else:
205 205 action_logger(self.rhodecode_user, 'admin_created_repo',
206 206 form_result['repo_name_full'], self.ip_addr,
207 207 self.sa)
208 208 Session().commit()
209 209 except formencode.Invalid, errors:
210 210
211 211 c.new_repo = errors.value['repo_name']
212 212
213 213 if request.POST.get('user_created'):
214 214 r = render('admin/repos/repo_add_create_repository.html')
215 215 else:
216 216 r = render('admin/repos/repo_add.html')
217 217
218 218 return htmlfill.render(
219 219 r,
220 220 defaults=errors.value,
221 221 errors=errors.error_dict or {},
222 222 prefix_error=False,
223 223 encoding="UTF-8")
224 224
225 225 except Exception:
226 226 log.error(traceback.format_exc())
227 227 msg = _('error occurred during creation of repository %s') \
228 228 % form_result.get('repo_name')
229 229 h.flash(msg, category='error')
230 return redirect(url('repos'))
230 231 #redirect to our new repo !
231 232 return redirect(url('summary_home', repo_name=new_repo.repo_name))
232 233
233 234 @HasPermissionAllDecorator('hg.admin')
234 235 def new(self, format='html'):
235 236 """GET /repos/new: Form to create a new item"""
236 237 new_repo = request.GET.get('repo', '')
237 238 c.new_repo = repo_name_slug(new_repo)
238 239 self.__load_defaults()
239 240 return render('admin/repos/repo_add.html')
240 241
241 242 @HasPermissionAllDecorator('hg.admin')
242 243 def update(self, repo_name):
243 244 """
244 245 PUT /repos/repo_name: Update an existing item"""
245 246 # Forms posted to this method should contain a hidden field:
246 247 # <input type="hidden" name="_method" value="PUT" />
247 248 # Or using helpers:
248 249 # h.form(url('repo', repo_name=ID),
249 250 # method='put')
250 251 # url('repo', repo_name=ID)
251 252 self.__load_defaults()
252 253 repo_model = RepoModel()
253 254 changed_name = repo_name
254 255 #override the choices with extracted revisions !
255 256 choices, c.landing_revs = ScmModel().get_repo_landing_revs(repo_name)
256 257 c.landing_revs_choices = choices
257 258
258 259 _form = RepoForm(edit=True, old_data={'repo_name': repo_name},
259 260 repo_groups=c.repo_groups_choices,
260 261 landing_revs=c.landing_revs_choices)()
261 262 try:
262 263 form_result = _form.to_python(dict(request.POST))
263 264 repo = repo_model.update(repo_name, form_result)
264 265 invalidate_cache('get_repo_cached_%s' % repo_name)
265 266 h.flash(_('Repository %s updated successfully') % repo_name,
266 267 category='success')
267 268 changed_name = repo.repo_name
268 269 action_logger(self.rhodecode_user, 'admin_updated_repo',
269 270 changed_name, self.ip_addr, self.sa)
270 271 Session().commit()
271 272 except formencode.Invalid, errors:
272 273 defaults = self.__load_data(repo_name)
273 274 defaults.update(errors.value)
274 275 return htmlfill.render(
275 276 render('admin/repos/repo_edit.html'),
276 277 defaults=defaults,
277 278 errors=errors.error_dict or {},
278 279 prefix_error=False,
279 280 encoding="UTF-8")
280 281
281 282 except Exception:
282 283 log.error(traceback.format_exc())
283 284 h.flash(_('error occurred during update of repository %s') \
284 285 % repo_name, category='error')
285 286 return redirect(url('edit_repo', repo_name=changed_name))
286 287
287 288 @HasPermissionAllDecorator('hg.admin')
288 289 def delete(self, repo_name):
289 290 """
290 291 DELETE /repos/repo_name: Delete an existing item"""
291 292 # Forms posted to this method should contain a hidden field:
292 293 # <input type="hidden" name="_method" value="DELETE" />
293 294 # Or using helpers:
294 295 # h.form(url('repo', repo_name=ID),
295 296 # method='delete')
296 297 # url('repo', repo_name=ID)
297 298
298 299 repo_model = RepoModel()
299 300 repo = repo_model.get_by_repo_name(repo_name)
300 301 if not repo:
301 302 h.flash(_('%s repository is not mapped to db perhaps'
302 303 ' it was moved or renamed from the filesystem'
303 304 ' please run the application again'
304 305 ' in order to rescan repositories') % repo_name,
305 306 category='error')
306 307
307 308 return redirect(url('repos'))
308 309 try:
309 310 action_logger(self.rhodecode_user, 'admin_deleted_repo',
310 311 repo_name, self.ip_addr, self.sa)
311 312 repo_model.delete(repo)
312 313 invalidate_cache('get_repo_cached_%s' % repo_name)
313 314 h.flash(_('deleted repository %s') % repo_name, category='success')
314 315 Session().commit()
315 316 except IntegrityError, e:
316 317 if e.message.find('repositories_fork_id_fkey') != -1:
317 318 log.error(traceback.format_exc())
318 319 h.flash(_('Cannot delete %s it still contains attached '
319 320 'forks') % repo_name,
320 321 category='warning')
321 322 else:
322 323 log.error(traceback.format_exc())
323 324 h.flash(_('An error occurred during '
324 325 'deletion of %s') % repo_name,
325 326 category='error')
326 327
327 328 except Exception, e:
328 329 log.error(traceback.format_exc())
329 330 h.flash(_('An error occurred during deletion of %s') % repo_name,
330 331 category='error')
331 332
332 333 return redirect(url('repos'))
333 334
334 335 @HasRepoPermissionAllDecorator('repository.admin')
335 336 def delete_perm_user(self, repo_name):
336 337 """
337 338 DELETE an existing repository permission user
338 339
339 340 :param repo_name:
340 341 """
341 342 try:
342 343 RepoModel().revoke_user_permission(repo=repo_name,
343 344 user=request.POST['user_id'])
344 345 Session().commit()
345 346 except Exception:
346 347 log.error(traceback.format_exc())
347 348 h.flash(_('An error occurred during deletion of repository user'),
348 349 category='error')
349 350 raise HTTPInternalServerError()
350 351
351 352 @HasRepoPermissionAllDecorator('repository.admin')
352 353 def delete_perm_users_group(self, repo_name):
353 354 """
354 355 DELETE an existing repository permission users group
355 356
356 357 :param repo_name:
357 358 """
358 359
359 360 try:
360 361 RepoModel().revoke_users_group_permission(
361 362 repo=repo_name, group_name=request.POST['users_group_id']
362 363 )
363 364 Session().commit()
364 365 except Exception:
365 366 log.error(traceback.format_exc())
366 367 h.flash(_('An error occurred during deletion of repository'
367 368 ' users groups'),
368 369 category='error')
369 370 raise HTTPInternalServerError()
370 371
371 372 @HasPermissionAllDecorator('hg.admin')
372 373 def repo_stats(self, repo_name):
373 374 """
374 375 DELETE an existing repository statistics
375 376
376 377 :param repo_name:
377 378 """
378 379
379 380 try:
380 381 RepoModel().delete_stats(repo_name)
381 382 Session().commit()
382 383 except Exception, e:
383 384 h.flash(_('An error occurred during deletion of repository stats'),
384 385 category='error')
385 386 return redirect(url('edit_repo', repo_name=repo_name))
386 387
387 388 @HasPermissionAllDecorator('hg.admin')
388 389 def repo_cache(self, repo_name):
389 390 """
390 391 INVALIDATE existing repository cache
391 392
392 393 :param repo_name:
393 394 """
394 395
395 396 try:
396 397 ScmModel().mark_for_invalidation(repo_name)
397 398 Session().commit()
398 399 except Exception, e:
399 400 h.flash(_('An error occurred during cache invalidation'),
400 401 category='error')
401 402 return redirect(url('edit_repo', repo_name=repo_name))
402 403
403 404 @HasPermissionAllDecorator('hg.admin')
404 405 def repo_public_journal(self, repo_name):
405 406 """
406 407 Set's this repository to be visible in public journal,
407 408 in other words assing default user to follow this repo
408 409
409 410 :param repo_name:
410 411 """
411 412
412 413 cur_token = request.POST.get('auth_token')
413 414 token = get_token()
414 415 if cur_token == token:
415 416 try:
416 417 repo_id = Repository.get_by_repo_name(repo_name).repo_id
417 418 user_id = User.get_by_username('default').user_id
418 419 self.scm_model.toggle_following_repo(repo_id, user_id)
419 420 h.flash(_('Updated repository visibility in public journal'),
420 421 category='success')
421 422 Session().commit()
422 423 except:
423 424 h.flash(_('An error occurred during setting this'
424 425 ' repository in public journal'),
425 426 category='error')
426 427
427 428 else:
428 429 h.flash(_('Token mismatch'), category='error')
429 430 return redirect(url('edit_repo', repo_name=repo_name))
430 431
431 432 @HasPermissionAllDecorator('hg.admin')
432 433 def repo_pull(self, repo_name):
433 434 """
434 435 Runs task to update given repository with remote changes,
435 436 ie. make pull on remote location
436 437
437 438 :param repo_name:
438 439 """
439 440 try:
440 441 ScmModel().pull_changes(repo_name, self.rhodecode_user.username)
441 442 h.flash(_('Pulled from remote location'), category='success')
442 443 except Exception, e:
443 444 h.flash(_('An error occurred during pull from remote location'),
444 445 category='error')
445 446
446 447 return redirect(url('edit_repo', repo_name=repo_name))
447 448
448 449 @HasPermissionAllDecorator('hg.admin')
449 450 def repo_as_fork(self, repo_name):
450 451 """
451 452 Mark given repository as a fork of another
452 453
453 454 :param repo_name:
454 455 """
455 456 try:
456 457 fork_id = request.POST.get('id_fork_of')
457 458 repo = ScmModel().mark_as_fork(repo_name, fork_id,
458 459 self.rhodecode_user.username)
459 460 fork = repo.fork.repo_name if repo.fork else _('Nothing')
460 461 Session().commit()
461 462 h.flash(_('Marked repo %s as fork of %s') % (repo_name, fork),
462 463 category='success')
463 464 except Exception, e:
464 465 log.error(traceback.format_exc())
465 466 h.flash(_('An error occurred during this operation'),
466 467 category='error')
467 468
468 469 return redirect(url('edit_repo', repo_name=repo_name))
469 470
470 471 @HasPermissionAllDecorator('hg.admin')
471 472 def show(self, repo_name, format='html'):
472 473 """GET /repos/repo_name: Show a specific item"""
473 474 # url('repo', repo_name=ID)
474 475
475 476 @HasPermissionAllDecorator('hg.admin')
476 477 def edit(self, repo_name, format='html'):
477 478 """GET /repos/repo_name/edit: Form to edit an existing item"""
478 479 # url('edit_repo', repo_name=ID)
479 480 defaults = self.__load_data(repo_name)
480 481
481 482 return htmlfill.render(
482 483 render('admin/repos/repo_edit.html'),
483 484 defaults=defaults,
484 485 encoding="UTF-8",
485 486 force_defaults=False
486 487 )
General Comments 0
You need to be logged in to leave comments. Login now