##// END OF EJS Templates
some extra fixes added docs string
marcink -
r824:ceb9f419 beta
parent child Browse files
Show More
@@ -1,305 +1,312 b''
1 #!/usr/bin/env python
1 # -*- coding: utf-8 -*-
2 # encoding: utf-8
2 """
3 # repos controller for pylons
3 rhodecode.controllers.admin.repos
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 #
5
6 Admin controller for RhodeCode
7
8 :created_on: Apr 7, 2010
9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
6 # This program is free software; you can redistribute it and/or
13 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
10 #
17 #
11 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
21 # GNU General Public License for more details.
15 #
22 #
16 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
24 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
20 """
27
21 Created on April 7, 2010
28 import logging
22 admin controller for pylons
29 import traceback
23 @author: marcink
30 import formencode
24 """
31 from operator import itemgetter
25 from formencode import htmlfill
32 from formencode import htmlfill
26 from operator import itemgetter
33
27 from paste.httpexceptions import HTTPInternalServerError
34 from paste.httpexceptions import HTTPInternalServerError
28 from pylons import request, response, session, tmpl_context as c, url
35 from pylons import request, response, session, tmpl_context as c, url
29 from pylons.controllers.util import abort, redirect
36 from pylons.controllers.util import abort, redirect
30 from pylons.i18n.translation import _
37 from pylons.i18n.translation import _
38
31 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
33 HasPermissionAnyDecorator
41 HasPermissionAnyDecorator
34 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.base import BaseController, render
35 from rhodecode.lib.utils import invalidate_cache, action_logger
43 from rhodecode.lib.utils import invalidate_cache, action_logger
36 from rhodecode.model.db import User
44 from rhodecode.model.db import User
37 from rhodecode.model.forms import RepoForm
45 from rhodecode.model.forms import RepoForm
38 from rhodecode.model.scm import ScmModel
46 from rhodecode.model.scm import ScmModel
39 from rhodecode.model.repo import RepoModel
47 from rhodecode.model.repo import RepoModel
40 import formencode
48
41 import logging
42 import traceback
43
49
44 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
45
51
46 class ReposController(BaseController):
52 class ReposController(BaseController):
47 """REST Controller styled on the Atom Publishing Protocol"""
53 """REST Controller styled on the Atom Publishing Protocol"""
48 # To properly map this controller, ensure your config/routing.py
54 # To properly map this controller, ensure your config/routing.py
49 # file has a resource setup:
55 # file has a resource setup:
50 # map.resource('repo', 'repos')
56 # map.resource('repo', 'repos')
51
57
52 @LoginRequired()
58 @LoginRequired()
53 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
59 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
54 def __before__(self):
60 def __before__(self):
55 c.admin_user = session.get('admin_user')
61 c.admin_user = session.get('admin_user')
56 c.admin_username = session.get('admin_username')
62 c.admin_username = session.get('admin_username')
57 super(ReposController, self).__before__()
63 super(ReposController, self).__before__()
58
64
59 @HasPermissionAllDecorator('hg.admin')
65 @HasPermissionAllDecorator('hg.admin')
60 def index(self, format='html'):
66 def index(self, format='html'):
61 """GET /repos: All items in the collection"""
67 """GET /repos: All items in the collection"""
62 # url('repos')
68 # url('repos')
63 cached_repo_list = ScmModel().get_repos()
69 cached_repo_list = ScmModel().get_repos()
64 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
70 c.repos_list = sorted(cached_repo_list, key=itemgetter('name_sort'))
65 return render('admin/repos/repos.html')
71 return render('admin/repos/repos.html')
66
72
67 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
73 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
68 def create(self):
74 def create(self):
69 """POST /repos: Create a new item"""
75 """POST /repos: Create a new item"""
70 # url('repos')
76 # url('repos')
71 repo_model = RepoModel()
77 repo_model = RepoModel()
72 _form = RepoForm()()
78 _form = RepoForm()()
73 form_result = {}
79 form_result = {}
74 try:
80 try:
75 form_result = _form.to_python(dict(request.POST))
81 form_result = _form.to_python(dict(request.POST))
76 repo_model.create(form_result, c.rhodecode_user)
82 repo_model.create(form_result, c.rhodecode_user)
77 h.flash(_('created repository %s') % form_result['repo_name'],
83 h.flash(_('created repository %s') % form_result['repo_name'],
78 category='success')
84 category='success')
79
85
80 if request.POST.get('user_created'):
86 if request.POST.get('user_created'):
81 action_logger(self.rhodecode_user, 'user_created_repo',
87 action_logger(self.rhodecode_user, 'user_created_repo',
82 form_result['repo_name'], '', self.sa)
88 form_result['repo_name'], '', self.sa)
83 else:
89 else:
84 action_logger(self.rhodecode_user, 'admin_created_repo',
90 action_logger(self.rhodecode_user, 'admin_created_repo',
85 form_result['repo_name'], '', self.sa)
91 form_result['repo_name'], '', self.sa)
86
92
87 except formencode.Invalid, errors:
93 except formencode.Invalid, errors:
88 c.new_repo = errors.value['repo_name']
94 c.new_repo = errors.value['repo_name']
89
95
90 if request.POST.get('user_created'):
96 if request.POST.get('user_created'):
91 r = render('admin/repos/repo_add_create_repository.html')
97 r = render('admin/repos/repo_add_create_repository.html')
92 else:
98 else:
93 r = render('admin/repos/repo_add.html')
99 r = render('admin/repos/repo_add.html')
94
100
95 return htmlfill.render(
101 return htmlfill.render(
96 r,
102 r,
97 defaults=errors.value,
103 defaults=errors.value,
98 errors=errors.error_dict or {},
104 errors=errors.error_dict or {},
99 prefix_error=False,
105 prefix_error=False,
100 encoding="UTF-8")
106 encoding="UTF-8")
101
107
102 except Exception:
108 except Exception:
103 log.error(traceback.format_exc())
109 log.error(traceback.format_exc())
104 msg = _('error occured during creation of repository %s') \
110 msg = _('error occured during creation of repository %s') \
105 % form_result.get('repo_name')
111 % form_result.get('repo_name')
106 h.flash(msg, category='error')
112 h.flash(msg, category='error')
107 if request.POST.get('user_created'):
113 if request.POST.get('user_created'):
108 return redirect(url('home'))
114 return redirect(url('home'))
109 return redirect(url('repos'))
115 return redirect(url('repos'))
110
116
111 @HasPermissionAllDecorator('hg.admin')
117 @HasPermissionAllDecorator('hg.admin')
112 def new(self, format='html'):
118 def new(self, format='html'):
113 """GET /repos/new: Form to create a new item"""
119 """GET /repos/new: Form to create a new item"""
114 new_repo = request.GET.get('repo', '')
120 new_repo = request.GET.get('repo', '')
115 c.new_repo = h.repo_name_slug(new_repo)
121 c.new_repo = h.repo_name_slug(new_repo)
116
122
117 return render('admin/repos/repo_add.html')
123 return render('admin/repos/repo_add.html')
118
124
119 @HasPermissionAllDecorator('hg.admin')
125 @HasPermissionAllDecorator('hg.admin')
120 def update(self, repo_name):
126 def update(self, repo_name):
121 """PUT /repos/repo_name: Update an existing item"""
127 """PUT /repos/repo_name: Update an existing item"""
122 # Forms posted to this method should contain a hidden field:
128 # Forms posted to this method should contain a hidden field:
123 # <input type="hidden" name="_method" value="PUT" />
129 # <input type="hidden" name="_method" value="PUT" />
124 # Or using helpers:
130 # Or using helpers:
125 # h.form(url('repo', repo_name=ID),
131 # h.form(url('repo', repo_name=ID),
126 # method='put')
132 # method='put')
127 # url('repo', repo_name=ID)
133 # url('repo', repo_name=ID)
128 repo_model = RepoModel()
134 repo_model = RepoModel()
129 changed_name = repo_name
135 changed_name = repo_name
130 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
136 _form = RepoForm(edit=True, old_data={'repo_name':repo_name})()
131
137
132 try:
138 try:
133 form_result = _form.to_python(dict(request.POST))
139 form_result = _form.to_python(dict(request.POST))
134 repo_model.update(repo_name, form_result)
140 repo_model.update(repo_name, form_result)
135 invalidate_cache('get_repo_cached_%s' % repo_name)
141 invalidate_cache('get_repo_cached_%s' % repo_name)
136 h.flash(_('Repository %s updated successfully' % repo_name),
142 h.flash(_('Repository %s updated successfully' % repo_name),
137 category='success')
143 category='success')
138 changed_name = form_result['repo_name']
144 changed_name = form_result['repo_name']
139 action_logger(self.rhodecode_user, 'admin_updated_repo',
145 action_logger(self.rhodecode_user, 'admin_updated_repo',
140 changed_name, '', self.sa)
146 changed_name, '', self.sa)
141
147
142 except formencode.Invalid, errors:
148 except formencode.Invalid, errors:
143 c.repo_info = repo_model.get_by_repo_name(repo_name)
149 c.repo_info = repo_model.get_by_repo_name(repo_name)
144 if c.repo_info.stats:
150 if c.repo_info.stats:
145 last_rev = c.repo_info.stats.stat_on_revision
151 last_rev = c.repo_info.stats.stat_on_revision
146 else:
152 else:
147 last_rev = 0
153 last_rev = 0
148 c.stats_revision = last_rev
154 c.stats_revision = last_rev
149 r = ScmModel().get(repo_name)
155 r = ScmModel().get(repo_name)
150 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
156 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
151
157
152 if last_rev == 0:
158 if last_rev == 0:
153 c.stats_percentage = 0
159 c.stats_percentage = 0
154 else:
160 else:
155 c.stats_percentage = '%.2f' % ((float((last_rev)) /
161 c.stats_percentage = '%.2f' % ((float((last_rev)) /
156 c.repo_last_rev) * 100)
162 c.repo_last_rev) * 100)
157
163
158 c.users_array = repo_model.get_users_js()
164 c.users_array = repo_model.get_users_js()
159 errors.value.update({'user':c.repo_info.user.username})
165 errors.value.update({'user':c.repo_info.user.username})
160 return htmlfill.render(
166 return htmlfill.render(
161 render('admin/repos/repo_edit.html'),
167 render('admin/repos/repo_edit.html'),
162 defaults=errors.value,
168 defaults=errors.value,
163 errors=errors.error_dict or {},
169 errors=errors.error_dict or {},
164 prefix_error=False,
170 prefix_error=False,
165 encoding="UTF-8")
171 encoding="UTF-8")
166
172
167 except Exception:
173 except Exception:
168 log.error(traceback.format_exc())
174 log.error(traceback.format_exc())
169 h.flash(_('error occurred during update of repository %s') \
175 h.flash(_('error occurred during update of repository %s') \
170 % repo_name, category='error')
176 % repo_name, category='error')
171
177
172 return redirect(url('edit_repo', repo_name=changed_name))
178 return redirect(url('edit_repo', repo_name=changed_name))
173
179
174 @HasPermissionAllDecorator('hg.admin')
180 @HasPermissionAllDecorator('hg.admin')
175 def delete(self, repo_name):
181 def delete(self, repo_name):
176 """DELETE /repos/repo_name: Delete an existing item"""
182 """DELETE /repos/repo_name: Delete an existing item"""
177 # Forms posted to this method should contain a hidden field:
183 # Forms posted to this method should contain a hidden field:
178 # <input type="hidden" name="_method" value="DELETE" />
184 # <input type="hidden" name="_method" value="DELETE" />
179 # Or using helpers:
185 # Or using helpers:
180 # h.form(url('repo', repo_name=ID),
186 # h.form(url('repo', repo_name=ID),
181 # method='delete')
187 # method='delete')
182 # url('repo', repo_name=ID)
188 # url('repo', repo_name=ID)
183
189
184 repo_model = RepoModel()
190 repo_model = RepoModel()
185 repo = repo_model.get_by_repo_name(repo_name)
191 repo = repo_model.get_by_repo_name(repo_name)
186 if not repo:
192 if not repo:
187 h.flash(_('%s repository is not mapped to db perhaps'
193 h.flash(_('%s repository is not mapped to db perhaps'
188 ' it was moved or renamed from the filesystem'
194 ' it was moved or renamed from the filesystem'
189 ' please run the application again'
195 ' please run the application again'
190 ' in order to rescan repositories') % repo_name,
196 ' in order to rescan repositories') % repo_name,
191 category='error')
197 category='error')
192
198
193 return redirect(url('repos'))
199 return redirect(url('repos'))
194 try:
200 try:
195 action_logger(self.rhodecode_user, 'admin_deleted_repo',
201 action_logger(self.rhodecode_user, 'admin_deleted_repo',
196 repo_name, '', self.sa)
202 repo_name, '', self.sa)
197 repo_model.delete(repo)
203 repo_model.delete(repo)
198 invalidate_cache('get_repo_cached_%s' % repo_name)
204 invalidate_cache('get_repo_cached_%s' % repo_name)
199 h.flash(_('deleted repository %s') % repo_name, category='success')
205 h.flash(_('deleted repository %s') % repo_name, category='success')
200
206
201 except Exception, e:
207 except Exception, e:
202 log.error(traceback.format_exc())
208 log.error(traceback.format_exc())
203 h.flash(_('An error occured during deletion of %s') % repo_name,
209 h.flash(_('An error occured during deletion of %s') % repo_name,
204 category='error')
210 category='error')
205
211
206 return redirect(url('repos'))
212 return redirect(url('repos'))
207
213
208 @HasPermissionAllDecorator('hg.admin')
214 @HasPermissionAllDecorator('hg.admin')
209 def delete_perm_user(self, repo_name):
215 def delete_perm_user(self, repo_name):
210 """
216 """
211 DELETE an existing repository permission user
217 DELETE an existing repository permission user
212 :param repo_name:
218 :param repo_name:
213 """
219 """
214
220
215 try:
221 try:
216 repo_model = RepoModel()
222 repo_model = RepoModel()
217 repo_model.delete_perm_user(request.POST, repo_name)
223 repo_model.delete_perm_user(request.POST, repo_name)
218 except Exception, e:
224 except Exception, e:
219 h.flash(_('An error occured during deletion of repository user'),
225 h.flash(_('An error occured during deletion of repository user'),
220 category='error')
226 category='error')
221 raise HTTPInternalServerError()
227 raise HTTPInternalServerError()
222
228
223 @HasPermissionAllDecorator('hg.admin')
229 @HasPermissionAllDecorator('hg.admin')
224 def repo_stats(self, repo_name):
230 def repo_stats(self, repo_name):
225 """
231 """
226 DELETE an existing repository statistics
232 DELETE an existing repository statistics
227 :param repo_name:
233 :param repo_name:
228 """
234 """
229
235
230 try:
236 try:
231 repo_model = RepoModel()
237 repo_model = RepoModel()
232 repo_model.delete_stats(repo_name)
238 repo_model.delete_stats(repo_name)
233 except Exception, e:
239 except Exception, e:
234 h.flash(_('An error occured during deletion of repository stats'),
240 h.flash(_('An error occured during deletion of repository stats'),
235 category='error')
241 category='error')
236 return redirect(url('edit_repo', repo_name=repo_name))
242 return redirect(url('edit_repo', repo_name=repo_name))
237
243
238 @HasPermissionAllDecorator('hg.admin')
244 @HasPermissionAllDecorator('hg.admin')
239 def repo_cache(self, repo_name):
245 def repo_cache(self, repo_name):
240 """
246 """
241 INVALIDATE exisitings repository cache
247 INVALIDATE exisitings repository cache
242 :param repo_name:
248 :param repo_name:
243 """
249 """
244
250
245 try:
251 try:
246 ScmModel().mark_for_invalidation(repo_name)
252 ScmModel().mark_for_invalidation(repo_name)
247 except Exception, e:
253 except Exception, e:
248 h.flash(_('An error occurred during cache invalidation'),
254 h.flash(_('An error occurred during cache invalidation'),
249 category='error')
255 category='error')
250 return redirect(url('edit_repo', repo_name=repo_name))
256 return redirect(url('edit_repo', repo_name=repo_name))
251
257
252 @HasPermissionAllDecorator('hg.admin')
258 @HasPermissionAllDecorator('hg.admin')
253 def show(self, repo_name, format='html'):
259 def show(self, repo_name, format='html'):
254 """GET /repos/repo_name: Show a specific item"""
260 """GET /repos/repo_name: Show a specific item"""
255 # url('repo', repo_name=ID)
261 # url('repo', repo_name=ID)
256
262
257 @HasPermissionAllDecorator('hg.admin')
263 @HasPermissionAllDecorator('hg.admin')
258 def edit(self, repo_name, format='html'):
264 def edit(self, repo_name, format='html'):
259 """GET /repos/repo_name/edit: Form to edit an existing item"""
265 """GET /repos/repo_name/edit: Form to edit an existing item"""
260 # url('edit_repo', repo_name=ID)
266 # url('edit_repo', repo_name=ID)
261 repo_model = RepoModel()
267 repo_model = RepoModel()
262 c.repo_info = repo_model.get_by_repo_name(repo_name)
268 c.repo_info = repo_model.get_by_repo_name(repo_name)
263 if c.repo_info.stats:
269 if c.repo_info.stats:
264 last_rev = c.repo_info.stats.stat_on_revision
270 last_rev = c.repo_info.stats.stat_on_revision
265 else:
271 else:
266 last_rev = 0
272 last_rev = 0
267 c.stats_revision = last_rev
273 c.stats_revision = last_rev
268 r = ScmModel().get(repo_name)
274 r = ScmModel().get(repo_name)
269 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
275 c.repo_last_rev = r.revisions[-1] if r.revisions else 0
270
276
271 if last_rev == 0:
277 if last_rev == 0:
272 c.stats_percentage = 0
278 c.stats_percentage = 0
273 else:
279 else:
274 c.stats_percentage = '%.2f' % ((float((last_rev)) /
280 c.stats_percentage = '%.2f' % ((float((last_rev)) /
275 c.repo_last_rev) * 100)
281 c.repo_last_rev) * 100)
276
282
277
283
278 if not c.repo_info:
284 if not c.repo_info:
279 h.flash(_('%s repository is not mapped to db perhaps'
285 h.flash(_('%s repository is not mapped to db perhaps'
280 ' it was created or renamed from the filesystem'
286 ' it was created or renamed from the filesystem'
281 ' please run the application again'
287 ' please run the application again'
282 ' in order to rescan repositories') % repo_name,
288 ' in order to rescan repositories') % repo_name,
283 category='error')
289 category='error')
284
290
285 return redirect(url('repos'))
291 return redirect(url('repos'))
292
286 defaults = c.repo_info.__dict__
293 defaults = c.repo_info.__dict__
287 if c.repo_info.user:
294 if c.repo_info.user:
288 defaults.update({'user':c.repo_info.user.username})
295 defaults.update({'user':c.repo_info.user.username})
289 else:
296 else:
290 replacement_user = self.sa.query(User)\
297 replacement_user = self.sa.query(User)\
291 .filter(User.admin == True).first().username
298 .filter(User.admin == True).first().username
292 defaults.update({'user':replacement_user})
299 defaults.update({'user':replacement_user})
293
300
294 c.users_array = repo_model.get_users_js()
301 c.users_array = repo_model.get_users_js()
295
302
296 for p in c.repo_info.repo_to_perm:
303 for p in c.repo_info.repo_to_perm:
297 defaults.update({'perm_%s' % p.user.username:
304 defaults.update({'perm_%s' % p.user.username:
298 p.permission.permission_name})
305 p.permission.permission_name})
299
306
300 return htmlfill.render(
307 return htmlfill.render(
301 render('admin/repos/repo_edit.html'),
308 render('admin/repos/repo_edit.html'),
302 defaults=defaults,
309 defaults=defaults,
303 encoding="UTF-8",
310 encoding="UTF-8",
304 force_defaults=False
311 force_defaults=False
305 )
312 )
General Comments 0
You need to be logged in to leave comments. Login now