##// END OF EJS Templates
Wraps group listing with permissions check so they don't get displayed
marcink -
r2831:0959096b beta
parent child Browse files
Show More
@@ -1,317 +1,317
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.repos_groups
3 rhodecode.controllers.admin.repos_groups
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Repositories groups controller for RhodeCode
6 Repositories groups controller for RhodeCode
7
7
8 :created_on: Mar 23, 2010
8 :created_on: Mar 23, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # 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,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # 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
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29
29
30 from formencode import htmlfill
30 from formencode import htmlfill
31
31
32 from pylons import request, tmpl_context as c, url
32 from pylons import request, tmpl_context as c, url
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35
35
36 from sqlalchemy.exc import IntegrityError
36 from sqlalchemy.exc import IntegrityError
37
37
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAnyDecorator,\
40 HasReposGroupPermissionAnyDecorator
40 HasReposGroupPermissionAnyDecorator
41 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.base import BaseController, render
42 from rhodecode.model.db import RepoGroup
42 from rhodecode.model.db import RepoGroup
43 from rhodecode.model.repos_group import ReposGroupModel
43 from rhodecode.model.repos_group import ReposGroupModel
44 from rhodecode.model.forms import ReposGroupForm
44 from rhodecode.model.forms import ReposGroupForm
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.repo import RepoModel
46 from rhodecode.model.repo import RepoModel
47 from webob.exc import HTTPInternalServerError, HTTPNotFound
47 from webob.exc import HTTPInternalServerError, HTTPNotFound
48 from rhodecode.lib.utils2 import str2bool
48 from rhodecode.lib.utils2 import str2bool
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52
52
53 class ReposGroupsController(BaseController):
53 class ReposGroupsController(BaseController):
54 """REST Controller styled on the Atom Publishing Protocol"""
54 """REST Controller styled on the Atom Publishing Protocol"""
55 # To properly map this controller, ensure your config/routing.py
55 # To properly map this controller, ensure your config/routing.py
56 # file has a resource setup:
56 # file has a resource setup:
57 # map.resource('repos_group', 'repos_groups')
57 # map.resource('repos_group', 'repos_groups')
58
58
59 @LoginRequired()
59 @LoginRequired()
60 def __before__(self):
60 def __before__(self):
61 super(ReposGroupsController, self).__before__()
61 super(ReposGroupsController, self).__before__()
62
62
63 def __load_defaults(self):
63 def __load_defaults(self):
64 c.repo_groups = RepoGroup.groups_choices()
64 c.repo_groups = RepoGroup.groups_choices()
65 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
65 c.repo_groups_choices = map(lambda k: unicode(k[0]), c.repo_groups)
66
66
67 repo_model = RepoModel()
67 repo_model = RepoModel()
68 c.users_array = repo_model.get_users_js()
68 c.users_array = repo_model.get_users_js()
69 c.users_groups_array = repo_model.get_users_groups_js()
69 c.users_groups_array = repo_model.get_users_groups_js()
70
70
71 def __load_data(self, group_id):
71 def __load_data(self, group_id):
72 """
72 """
73 Load defaults settings for edit, and update
73 Load defaults settings for edit, and update
74
74
75 :param group_id:
75 :param group_id:
76 """
76 """
77 self.__load_defaults()
77 self.__load_defaults()
78 repo_group = RepoGroup.get_or_404(group_id)
78 repo_group = RepoGroup.get_or_404(group_id)
79 data = repo_group.get_dict()
79 data = repo_group.get_dict()
80 data['group_name'] = repo_group.name
80 data['group_name'] = repo_group.name
81
81
82 # fill repository users
82 # fill repository users
83 for p in repo_group.repo_group_to_perm:
83 for p in repo_group.repo_group_to_perm:
84 data.update({'u_perm_%s' % p.user.username:
84 data.update({'u_perm_%s' % p.user.username:
85 p.permission.permission_name})
85 p.permission.permission_name})
86
86
87 # fill repository groups
87 # fill repository groups
88 for p in repo_group.users_group_to_perm:
88 for p in repo_group.users_group_to_perm:
89 data.update({'g_perm_%s' % p.users_group.users_group_name:
89 data.update({'g_perm_%s' % p.users_group.users_group_name:
90 p.permission.permission_name})
90 p.permission.permission_name})
91
91
92 return data
92 return data
93
93
94 @HasPermissionAnyDecorator('hg.admin')
94 @HasPermissionAnyDecorator('hg.admin')
95 def index(self, format='html'):
95 def index(self, format='html'):
96 """GET /repos_groups: All items in the collection"""
96 """GET /repos_groups: All items in the collection"""
97 # url('repos_groups')
97 # url('repos_groups')
98 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
98 sk = lambda g: g.parents[0].group_name if g.parents else g.group_name
99 c.groups = sorted(RepoGroup.query().all(), key=sk)
99 c.groups = sorted(RepoGroup.query().all(), key=sk)
100 return render('admin/repos_groups/repos_groups_show.html')
100 return render('admin/repos_groups/repos_groups_show.html')
101
101
102 @HasPermissionAnyDecorator('hg.admin')
102 @HasPermissionAnyDecorator('hg.admin')
103 def create(self):
103 def create(self):
104 """POST /repos_groups: Create a new item"""
104 """POST /repos_groups: Create a new item"""
105 # url('repos_groups')
105 # url('repos_groups')
106 self.__load_defaults()
106 self.__load_defaults()
107 repos_group_form = ReposGroupForm(available_groups =
107 repos_group_form = ReposGroupForm(available_groups =
108 c.repo_groups_choices)()
108 c.repo_groups_choices)()
109 try:
109 try:
110 form_result = repos_group_form.to_python(dict(request.POST))
110 form_result = repos_group_form.to_python(dict(request.POST))
111 ReposGroupModel().create(
111 ReposGroupModel().create(
112 group_name=form_result['group_name'],
112 group_name=form_result['group_name'],
113 group_description=form_result['group_description'],
113 group_description=form_result['group_description'],
114 parent=form_result['group_parent_id']
114 parent=form_result['group_parent_id']
115 )
115 )
116 Session().commit()
116 Session().commit()
117 h.flash(_('created repos group %s') \
117 h.flash(_('created repos group %s') \
118 % form_result['group_name'], category='success')
118 % form_result['group_name'], category='success')
119 #TODO: in futureaction_logger(, '', '', '', self.sa)
119 #TODO: in futureaction_logger(, '', '', '', self.sa)
120 except formencode.Invalid, errors:
120 except formencode.Invalid, errors:
121
121
122 return htmlfill.render(
122 return htmlfill.render(
123 render('admin/repos_groups/repos_groups_add.html'),
123 render('admin/repos_groups/repos_groups_add.html'),
124 defaults=errors.value,
124 defaults=errors.value,
125 errors=errors.error_dict or {},
125 errors=errors.error_dict or {},
126 prefix_error=False,
126 prefix_error=False,
127 encoding="UTF-8")
127 encoding="UTF-8")
128 except Exception:
128 except Exception:
129 log.error(traceback.format_exc())
129 log.error(traceback.format_exc())
130 h.flash(_('error occurred during creation of repos group %s') \
130 h.flash(_('error occurred during creation of repos group %s') \
131 % request.POST.get('group_name'), category='error')
131 % request.POST.get('group_name'), category='error')
132
132
133 return redirect(url('repos_groups'))
133 return redirect(url('repos_groups'))
134
134
135 @HasPermissionAnyDecorator('hg.admin')
135 @HasPermissionAnyDecorator('hg.admin')
136 def new(self, format='html'):
136 def new(self, format='html'):
137 """GET /repos_groups/new: Form to create a new item"""
137 """GET /repos_groups/new: Form to create a new item"""
138 # url('new_repos_group')
138 # url('new_repos_group')
139 self.__load_defaults()
139 self.__load_defaults()
140 return render('admin/repos_groups/repos_groups_add.html')
140 return render('admin/repos_groups/repos_groups_add.html')
141
141
142 @HasPermissionAnyDecorator('hg.admin')
142 @HasPermissionAnyDecorator('hg.admin')
143 def update(self, id):
143 def update(self, id):
144 """PUT /repos_groups/id: Update an existing item"""
144 """PUT /repos_groups/id: Update an existing item"""
145 # Forms posted to this method should contain a hidden field:
145 # Forms posted to this method should contain a hidden field:
146 # <input type="hidden" name="_method" value="PUT" />
146 # <input type="hidden" name="_method" value="PUT" />
147 # Or using helpers:
147 # Or using helpers:
148 # h.form(url('repos_group', id=ID),
148 # h.form(url('repos_group', id=ID),
149 # method='put')
149 # method='put')
150 # url('repos_group', id=ID)
150 # url('repos_group', id=ID)
151
151
152 self.__load_defaults()
152 self.__load_defaults()
153 c.repos_group = RepoGroup.get(id)
153 c.repos_group = RepoGroup.get(id)
154
154
155 repos_group_form = ReposGroupForm(
155 repos_group_form = ReposGroupForm(
156 edit=True,
156 edit=True,
157 old_data=c.repos_group.get_dict(),
157 old_data=c.repos_group.get_dict(),
158 available_groups=c.repo_groups_choices
158 available_groups=c.repo_groups_choices
159 )()
159 )()
160 try:
160 try:
161 form_result = repos_group_form.to_python(dict(request.POST))
161 form_result = repos_group_form.to_python(dict(request.POST))
162 ReposGroupModel().update(id, form_result)
162 ReposGroupModel().update(id, form_result)
163 Session().commit()
163 Session().commit()
164 h.flash(_('updated repos group %s') \
164 h.flash(_('updated repos group %s') \
165 % form_result['group_name'], category='success')
165 % form_result['group_name'], category='success')
166 #TODO: in future action_logger(, '', '', '', self.sa)
166 #TODO: in future action_logger(, '', '', '', self.sa)
167 except formencode.Invalid, errors:
167 except formencode.Invalid, errors:
168
168
169 return htmlfill.render(
169 return htmlfill.render(
170 render('admin/repos_groups/repos_groups_edit.html'),
170 render('admin/repos_groups/repos_groups_edit.html'),
171 defaults=errors.value,
171 defaults=errors.value,
172 errors=errors.error_dict or {},
172 errors=errors.error_dict or {},
173 prefix_error=False,
173 prefix_error=False,
174 encoding="UTF-8")
174 encoding="UTF-8")
175 except Exception:
175 except Exception:
176 log.error(traceback.format_exc())
176 log.error(traceback.format_exc())
177 h.flash(_('error occurred during update of repos group %s') \
177 h.flash(_('error occurred during update of repos group %s') \
178 % request.POST.get('group_name'), category='error')
178 % request.POST.get('group_name'), category='error')
179
179
180 return redirect(url('edit_repos_group', id=id))
180 return redirect(url('edit_repos_group', id=id))
181
181
182 @HasPermissionAnyDecorator('hg.admin')
182 @HasPermissionAnyDecorator('hg.admin')
183 def delete(self, id):
183 def delete(self, id):
184 """DELETE /repos_groups/id: Delete an existing item"""
184 """DELETE /repos_groups/id: Delete an existing item"""
185 # Forms posted to this method should contain a hidden field:
185 # Forms posted to this method should contain a hidden field:
186 # <input type="hidden" name="_method" value="DELETE" />
186 # <input type="hidden" name="_method" value="DELETE" />
187 # Or using helpers:
187 # Or using helpers:
188 # h.form(url('repos_group', id=ID),
188 # h.form(url('repos_group', id=ID),
189 # method='delete')
189 # method='delete')
190 # url('repos_group', id=ID)
190 # url('repos_group', id=ID)
191
191
192 gr = RepoGroup.get(id)
192 gr = RepoGroup.get(id)
193 repos = gr.repositories.all()
193 repos = gr.repositories.all()
194 if repos:
194 if repos:
195 h.flash(_('This group contains %s repositores and cannot be '
195 h.flash(_('This group contains %s repositores and cannot be '
196 'deleted') % len(repos),
196 'deleted') % len(repos),
197 category='error')
197 category='error')
198 return redirect(url('repos_groups'))
198 return redirect(url('repos_groups'))
199
199
200 try:
200 try:
201 ReposGroupModel().delete(id)
201 ReposGroupModel().delete(id)
202 Session().commit()
202 Session().commit()
203 h.flash(_('removed repos group %s') % gr.group_name,
203 h.flash(_('removed repos group %s') % gr.group_name,
204 category='success')
204 category='success')
205 #TODO: in future action_logger(, '', '', '', self.sa)
205 #TODO: in future action_logger(, '', '', '', self.sa)
206 except IntegrityError, e:
206 except IntegrityError, e:
207 if str(e.message).find('groups_group_parent_id_fkey') != -1:
207 if str(e.message).find('groups_group_parent_id_fkey') != -1:
208 log.error(traceback.format_exc())
208 log.error(traceback.format_exc())
209 h.flash(_('Cannot delete this group it still contains '
209 h.flash(_('Cannot delete this group it still contains '
210 'subgroups'),
210 'subgroups'),
211 category='warning')
211 category='warning')
212 else:
212 else:
213 log.error(traceback.format_exc())
213 log.error(traceback.format_exc())
214 h.flash(_('error occurred during deletion of repos '
214 h.flash(_('error occurred during deletion of repos '
215 'group %s') % gr.group_name, category='error')
215 'group %s') % gr.group_name, category='error')
216
216
217 except Exception:
217 except Exception:
218 log.error(traceback.format_exc())
218 log.error(traceback.format_exc())
219 h.flash(_('error occurred during deletion of repos '
219 h.flash(_('error occurred during deletion of repos '
220 'group %s') % gr.group_name, category='error')
220 'group %s') % gr.group_name, category='error')
221
221
222 return redirect(url('repos_groups'))
222 return redirect(url('repos_groups'))
223
223
224 @HasReposGroupPermissionAnyDecorator('group.admin')
224 @HasReposGroupPermissionAnyDecorator('group.admin')
225 def delete_repos_group_user_perm(self, group_name):
225 def delete_repos_group_user_perm(self, group_name):
226 """
226 """
227 DELETE an existing repositories group permission user
227 DELETE an existing repositories group permission user
228
228
229 :param group_name:
229 :param group_name:
230 """
230 """
231 try:
231 try:
232 recursive = str2bool(request.POST.get('recursive', False))
232 recursive = str2bool(request.POST.get('recursive', False))
233 ReposGroupModel().delete_permission(
233 ReposGroupModel().delete_permission(
234 repos_group=group_name, obj=request.POST['user_id'],
234 repos_group=group_name, obj=request.POST['user_id'],
235 obj_type='user', recursive=recursive
235 obj_type='user', recursive=recursive
236 )
236 )
237 Session().commit()
237 Session().commit()
238 except Exception:
238 except Exception:
239 log.error(traceback.format_exc())
239 log.error(traceback.format_exc())
240 h.flash(_('An error occurred during deletion of group user'),
240 h.flash(_('An error occurred during deletion of group user'),
241 category='error')
241 category='error')
242 raise HTTPInternalServerError()
242 raise HTTPInternalServerError()
243
243
244 @HasReposGroupPermissionAnyDecorator('group.admin')
244 @HasReposGroupPermissionAnyDecorator('group.admin')
245 def delete_repos_group_users_group_perm(self, group_name):
245 def delete_repos_group_users_group_perm(self, group_name):
246 """
246 """
247 DELETE an existing repositories group permission users group
247 DELETE an existing repositories group permission users group
248
248
249 :param group_name:
249 :param group_name:
250 """
250 """
251
251
252 try:
252 try:
253 recursive = str2bool(request.POST.get('recursive', False))
253 recursive = str2bool(request.POST.get('recursive', False))
254 ReposGroupModel().delete_permission(
254 ReposGroupModel().delete_permission(
255 repos_group=group_name, obj=request.POST['users_group_id'],
255 repos_group=group_name, obj=request.POST['users_group_id'],
256 obj_type='users_group', recursive=recursive
256 obj_type='users_group', recursive=recursive
257 )
257 )
258 Session().commit()
258 Session().commit()
259 except Exception:
259 except Exception:
260 log.error(traceback.format_exc())
260 log.error(traceback.format_exc())
261 h.flash(_('An error occurred during deletion of group'
261 h.flash(_('An error occurred during deletion of group'
262 ' users groups'),
262 ' users groups'),
263 category='error')
263 category='error')
264 raise HTTPInternalServerError()
264 raise HTTPInternalServerError()
265
265
266 def show_by_name(self, group_name):
266 def show_by_name(self, group_name):
267 """
267 """
268 This is a proxy that does a lookup group_name -> id, and shows
268 This is a proxy that does a lookup group_name -> id, and shows
269 the group by id view instead
269 the group by id view instead
270 """
270 """
271 group_name = group_name.rstrip('/')
271 group_name = group_name.rstrip('/')
272 id_ = RepoGroup.get_by_group_name(group_name)
272 id_ = RepoGroup.get_by_group_name(group_name)
273 if id_:
273 if id_:
274 return self.show(id_.group_id)
274 return self.show(id_.group_id)
275 raise HTTPNotFound
275 raise HTTPNotFound
276
276
277 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
277 @HasReposGroupPermissionAnyDecorator('group.read', 'group.write',
278 'group.admin')
278 'group.admin')
279 def show(self, id, format='html'):
279 def show(self, id, format='html'):
280 """GET /repos_groups/id: Show a specific item"""
280 """GET /repos_groups/id: Show a specific item"""
281 # url('repos_group', id=ID)
281 # url('repos_group', id=ID)
282
282
283 c.group = RepoGroup.get_or_404(id)
283 c.group = RepoGroup.get_or_404(id)
284
284
285 c.group_repos = c.group.repositories.all()
285 c.group_repos = c.group.repositories.all()
286
286
287 #overwrite our cached list with current filter
287 #overwrite our cached list with current filter
288 gr_filter = c.group_repos
288 gr_filter = c.group_repos
289 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
289 c.cached_repo_list = self.scm_model.get_repos(all_repos=gr_filter)
290
290
291 c.repos_list = c.cached_repo_list
291 c.repos_list = c.cached_repo_list
292
292
293 c.repo_cnt = 0
293 c.repo_cnt = 0
294
294
295 c.groups = RepoGroup.query().order_by(RepoGroup.group_name)\
295 groups = RepoGroup.query().order_by(RepoGroup.group_name)\
296 .filter(RepoGroup.group_parent_id == id).all()
296 .filter(RepoGroup.group_parent_id == id).all()
297
297 c.groups = self.scm_model.get_repos_groups(groups)
298 return render('admin/repos_groups/repos_groups.html')
298 return render('admin/repos_groups/repos_groups.html')
299
299
300 @HasPermissionAnyDecorator('hg.admin')
300 @HasPermissionAnyDecorator('hg.admin')
301 def edit(self, id, format='html'):
301 def edit(self, id, format='html'):
302 """GET /repos_groups/id/edit: Form to edit an existing item"""
302 """GET /repos_groups/id/edit: Form to edit an existing item"""
303 # url('edit_repos_group', id=ID)
303 # url('edit_repos_group', id=ID)
304
304
305 c.repos_group = ReposGroupModel()._get_repos_group(id)
305 c.repos_group = ReposGroupModel()._get_repos_group(id)
306 defaults = self.__load_data(c.repos_group.group_id)
306 defaults = self.__load_data(c.repos_group.group_id)
307
307
308 # we need to exclude this group from the group list for editing
308 # we need to exclude this group from the group list for editing
309 c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id,
309 c.repo_groups = filter(lambda x: x[0] != c.repos_group.group_id,
310 c.repo_groups)
310 c.repo_groups)
311
311
312 return htmlfill.render(
312 return htmlfill.render(
313 render('admin/repos_groups/repos_groups_edit.html'),
313 render('admin/repos_groups/repos_groups_edit.html'),
314 defaults=defaults,
314 defaults=defaults,
315 encoding="UTF-8",
315 encoding="UTF-8",
316 force_defaults=False
316 force_defaults=False
317 )
317 )
General Comments 0
You need to be logged in to leave comments. Login now