##// END OF EJS Templates
repo groups: make it possible to remove own explicit permissions, now when group owners always have admin permissions...
Mads Kiilerich -
r8772:2e1059de stable
parent child Browse files
Show More
@@ -1,403 +1,386 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.controllers.admin.repo_groups
15 kallithea.controllers.admin.repo_groups
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 Repository groups controller for Kallithea
18 Repository groups controller for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Mar 23, 2010
22 :created_on: Mar 23, 2010
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28 import logging
28 import logging
29 import traceback
29 import traceback
30
30
31 import formencode
31 import formencode
32 from formencode import htmlfill
32 from formencode import htmlfill
33 from tg import app_globals, request
33 from tg import app_globals, request
34 from tg import tmpl_context as c
34 from tg import tmpl_context as c
35 from tg.i18n import ugettext as _
35 from tg.i18n import ugettext as _
36 from tg.i18n import ungettext
36 from tg.i18n import ungettext
37 from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound
37 from webob.exc import HTTPForbidden, HTTPFound, HTTPInternalServerError, HTTPNotFound
38
38
39 from kallithea.controllers import base
39 from kallithea.controllers import base
40 from kallithea.lib import webutils
40 from kallithea.lib import webutils
41 from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel, HasRepoGroupPermissionLevelDecorator, LoginRequired
41 from kallithea.lib.auth import HasPermissionAny, HasRepoGroupPermissionLevel, HasRepoGroupPermissionLevelDecorator, LoginRequired
42 from kallithea.lib.utils2 import safe_int
42 from kallithea.lib.utils2 import safe_int
43 from kallithea.lib.webutils import url
43 from kallithea.lib.webutils import url
44 from kallithea.model import db, meta
44 from kallithea.model import db, meta
45 from kallithea.model.forms import RepoGroupForm, RepoGroupPermsForm
45 from kallithea.model.forms import RepoGroupForm, RepoGroupPermsForm
46 from kallithea.model.repo import RepoModel
46 from kallithea.model.repo import RepoModel
47 from kallithea.model.repo_group import RepoGroupModel
47 from kallithea.model.repo_group import RepoGroupModel
48 from kallithea.model.scm import AvailableRepoGroupChoices, RepoGroupList
48 from kallithea.model.scm import AvailableRepoGroupChoices, RepoGroupList
49
49
50
50
51 log = logging.getLogger(__name__)
51 log = logging.getLogger(__name__)
52
52
53
53
54 class RepoGroupsController(base.BaseController):
54 class RepoGroupsController(base.BaseController):
55
55
56 @LoginRequired(allow_default_user=True)
56 @LoginRequired(allow_default_user=True)
57 def _before(self, *args, **kwargs):
57 def _before(self, *args, **kwargs):
58 super(RepoGroupsController, self)._before(*args, **kwargs)
58 super(RepoGroupsController, self)._before(*args, **kwargs)
59
59
60 def __load_defaults(self, extras=(), exclude=()):
60 def __load_defaults(self, extras=(), exclude=()):
61 """extras is used for keeping current parent ignoring permissions
61 """extras is used for keeping current parent ignoring permissions
62 exclude is used for not moving group to itself TODO: also exclude descendants
62 exclude is used for not moving group to itself TODO: also exclude descendants
63 Note: only admin can create top level groups
63 Note: only admin can create top level groups
64 """
64 """
65 repo_groups = AvailableRepoGroupChoices('admin', extras)
65 repo_groups = AvailableRepoGroupChoices('admin', extras)
66 exclude_group_ids = set(rg.group_id for rg in exclude)
66 exclude_group_ids = set(rg.group_id for rg in exclude)
67 c.repo_groups = [rg for rg in repo_groups
67 c.repo_groups = [rg for rg in repo_groups
68 if rg[0] not in exclude_group_ids]
68 if rg[0] not in exclude_group_ids]
69
69
70 def __load_data(self, group_id):
70 def __load_data(self, group_id):
71 """
71 """
72 Load defaults settings for edit, and update
72 Load defaults settings for edit, and update
73
73
74 :param group_id:
74 :param group_id:
75 """
75 """
76 repo_group = db.RepoGroup.get_or_404(group_id)
76 repo_group = db.RepoGroup.get_or_404(group_id)
77 data = repo_group.get_dict()
77 data = repo_group.get_dict()
78 data['group_name'] = repo_group.name
78 data['group_name'] = repo_group.name
79 data['owner'] = repo_group.owner.username
79 data['owner'] = repo_group.owner.username
80
80
81 # fill repository group users
81 # fill repository group users
82 for p in repo_group.repo_group_to_perm:
82 for p in repo_group.repo_group_to_perm:
83 data.update({'u_perm_%s' % p.user.username:
83 data.update({'u_perm_%s' % p.user.username:
84 p.permission.permission_name})
84 p.permission.permission_name})
85
85
86 # fill repository group groups
86 # fill repository group groups
87 for p in repo_group.users_group_to_perm:
87 for p in repo_group.users_group_to_perm:
88 data.update({'g_perm_%s' % p.users_group.users_group_name:
88 data.update({'g_perm_%s' % p.users_group.users_group_name:
89 p.permission.permission_name})
89 p.permission.permission_name})
90
90
91 return data
91 return data
92
92
93 def _revoke_perms_on_yourself(self, form_result):
94 _up = [u for u in form_result['perms_updates'] if request.authuser.username == u[0]]
95 _new = [u for u in form_result['perms_new'] if request.authuser.username == u[0]]
96 if _new and _new[0][1] != 'group.admin' or _up and _up[0][1] != 'group.admin':
97 return True
98 return False
99
100 def index(self, format='html'):
93 def index(self, format='html'):
101 _list = db.RepoGroup.query(sorted=True).all()
94 _list = db.RepoGroup.query(sorted=True).all()
102 group_iter = RepoGroupList(_list, perm_level='admin')
95 group_iter = RepoGroupList(_list, perm_level='admin')
103 repo_groups_data = []
96 repo_groups_data = []
104 _tmpl_lookup = app_globals.mako_lookup
97 _tmpl_lookup = app_globals.mako_lookup
105 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
98 template = _tmpl_lookup.get_template('data_table/_dt_elements.html')
106
99
107 def repo_group_name(repo_group_name, children_groups):
100 def repo_group_name(repo_group_name, children_groups):
108 return template.get_def("repo_group_name") \
101 return template.get_def("repo_group_name") \
109 .render_unicode(repo_group_name, children_groups, _=_, webutils=webutils, c=c)
102 .render_unicode(repo_group_name, children_groups, _=_, webutils=webutils, c=c)
110
103
111 def repo_group_actions(repo_group_id, repo_group_name, gr_count):
104 def repo_group_actions(repo_group_id, repo_group_name, gr_count):
112 return template.get_def("repo_group_actions") \
105 return template.get_def("repo_group_actions") \
113 .render_unicode(repo_group_id, repo_group_name, gr_count, _=_, webutils=webutils, c=c,
106 .render_unicode(repo_group_id, repo_group_name, gr_count, _=_, webutils=webutils, c=c,
114 ungettext=ungettext)
107 ungettext=ungettext)
115
108
116 for repo_gr in group_iter:
109 for repo_gr in group_iter:
117 children_groups = [g.name for g in repo_gr.parents] + [repo_gr.name]
110 children_groups = [g.name for g in repo_gr.parents] + [repo_gr.name]
118 repo_count = repo_gr.repositories.count()
111 repo_count = repo_gr.repositories.count()
119 repo_groups_data.append({
112 repo_groups_data.append({
120 "raw_name": webutils.escape(repo_gr.group_name),
113 "raw_name": webutils.escape(repo_gr.group_name),
121 "group_name": repo_group_name(repo_gr.group_name, children_groups),
114 "group_name": repo_group_name(repo_gr.group_name, children_groups),
122 "desc": webutils.escape(repo_gr.group_description),
115 "desc": webutils.escape(repo_gr.group_description),
123 "repos": repo_count,
116 "repos": repo_count,
124 "owner": repo_gr.owner.username,
117 "owner": repo_gr.owner.username,
125 "action": repo_group_actions(repo_gr.group_id, repo_gr.group_name,
118 "action": repo_group_actions(repo_gr.group_id, repo_gr.group_name,
126 repo_count)
119 repo_count)
127 })
120 })
128
121
129 c.data = {
122 c.data = {
130 "sort": None,
123 "sort": None,
131 "dir": "asc",
124 "dir": "asc",
132 "records": repo_groups_data
125 "records": repo_groups_data
133 }
126 }
134
127
135 return base.render('admin/repo_groups/repo_groups.html')
128 return base.render('admin/repo_groups/repo_groups.html')
136
129
137 def create(self):
130 def create(self):
138 self.__load_defaults()
131 self.__load_defaults()
139
132
140 # permissions for can create group based on parent_id are checked
133 # permissions for can create group based on parent_id are checked
141 # here in the Form
134 # here in the Form
142 repo_group_form = RepoGroupForm(repo_groups=c.repo_groups)
135 repo_group_form = RepoGroupForm(repo_groups=c.repo_groups)
143 form_result = None
136 form_result = None
144 try:
137 try:
145 form_result = repo_group_form.to_python(dict(request.POST))
138 form_result = repo_group_form.to_python(dict(request.POST))
146 gr = RepoGroupModel().create(
139 gr = RepoGroupModel().create(
147 group_name=form_result['group_name'],
140 group_name=form_result['group_name'],
148 group_description=form_result['group_description'],
141 group_description=form_result['group_description'],
149 parent=form_result['parent_group_id'],
142 parent=form_result['parent_group_id'],
150 owner=request.authuser.user_id,
143 owner=request.authuser.user_id,
151 copy_permissions=form_result['group_copy_permissions']
144 copy_permissions=form_result['group_copy_permissions']
152 )
145 )
153 meta.Session().commit()
146 meta.Session().commit()
154 # TODO: in future action_logger(, '', '', '')
147 # TODO: in future action_logger(, '', '', '')
155 except formencode.Invalid as errors:
148 except formencode.Invalid as errors:
156 return htmlfill.render(
149 return htmlfill.render(
157 base.render('admin/repo_groups/repo_group_add.html'),
150 base.render('admin/repo_groups/repo_group_add.html'),
158 defaults=errors.value,
151 defaults=errors.value,
159 errors=errors.error_dict or {},
152 errors=errors.error_dict or {},
160 prefix_error=False,
153 prefix_error=False,
161 encoding="UTF-8",
154 encoding="UTF-8",
162 force_defaults=False)
155 force_defaults=False)
163 except Exception:
156 except Exception:
164 log.error(traceback.format_exc())
157 log.error(traceback.format_exc())
165 webutils.flash(_('Error occurred during creation of repository group %s')
158 webutils.flash(_('Error occurred during creation of repository group %s')
166 % request.POST.get('group_name'), category='error')
159 % request.POST.get('group_name'), category='error')
167 if form_result is None:
160 if form_result is None:
168 raise
161 raise
169 parent_group_id = form_result['parent_group_id']
162 parent_group_id = form_result['parent_group_id']
170 # TODO: maybe we should get back to the main view, not the admin one
163 # TODO: maybe we should get back to the main view, not the admin one
171 raise HTTPFound(location=url('repos_groups', parent_group=parent_group_id))
164 raise HTTPFound(location=url('repos_groups', parent_group=parent_group_id))
172 webutils.flash(_('Created repository group %s') % gr.group_name,
165 webutils.flash(_('Created repository group %s') % gr.group_name,
173 category='success')
166 category='success')
174 raise HTTPFound(location=url('repos_group_home', group_name=gr.group_name))
167 raise HTTPFound(location=url('repos_group_home', group_name=gr.group_name))
175
168
176 def new(self):
169 def new(self):
177 parent_group_id = safe_int(request.GET.get('parent_group') or '-1')
170 parent_group_id = safe_int(request.GET.get('parent_group') or '-1')
178 if HasPermissionAny('hg.admin')('group create'):
171 if HasPermissionAny('hg.admin')('group create'):
179 # we're global admin, we're ok and we can create TOP level groups
172 # we're global admin, we're ok and we can create TOP level groups
180 pass
173 pass
181 else:
174 else:
182 # we pass in parent group into creation form, thus we know
175 # we pass in parent group into creation form, thus we know
183 # what would be the group, we can check perms here !
176 # what would be the group, we can check perms here !
184 group = db.RepoGroup.get(parent_group_id) if parent_group_id else None
177 group = db.RepoGroup.get(parent_group_id) if parent_group_id else None
185 group_name = group.group_name if group else None
178 group_name = group.group_name if group else None
186 if HasRepoGroupPermissionLevel('admin')(group_name, 'group create'):
179 if HasRepoGroupPermissionLevel('admin')(group_name, 'group create'):
187 pass
180 pass
188 else:
181 else:
189 raise HTTPForbidden()
182 raise HTTPForbidden()
190
183
191 self.__load_defaults()
184 self.__load_defaults()
192 return htmlfill.render(
185 return htmlfill.render(
193 base.render('admin/repo_groups/repo_group_add.html'),
186 base.render('admin/repo_groups/repo_group_add.html'),
194 defaults={'parent_group_id': parent_group_id},
187 defaults={'parent_group_id': parent_group_id},
195 errors={},
188 errors={},
196 prefix_error=False,
189 prefix_error=False,
197 encoding="UTF-8",
190 encoding="UTF-8",
198 force_defaults=False)
191 force_defaults=False)
199
192
200 @HasRepoGroupPermissionLevelDecorator('admin')
193 @HasRepoGroupPermissionLevelDecorator('admin')
201 def update(self, group_name):
194 def update(self, group_name):
202 c.repo_group = db.RepoGroup.guess_instance(group_name)
195 c.repo_group = db.RepoGroup.guess_instance(group_name)
203 self.__load_defaults(extras=[c.repo_group.parent_group],
196 self.__load_defaults(extras=[c.repo_group.parent_group],
204 exclude=[c.repo_group])
197 exclude=[c.repo_group])
205
198
206 # TODO: kill allow_empty_group - it is only used for redundant form validation!
199 # TODO: kill allow_empty_group - it is only used for redundant form validation!
207 if HasPermissionAny('hg.admin')('group edit'):
200 if HasPermissionAny('hg.admin')('group edit'):
208 # we're global admin, we're ok and we can create TOP level groups
201 # we're global admin, we're ok and we can create TOP level groups
209 allow_empty_group = True
202 allow_empty_group = True
210 elif not c.repo_group.parent_group:
203 elif not c.repo_group.parent_group:
211 allow_empty_group = True
204 allow_empty_group = True
212 else:
205 else:
213 allow_empty_group = False
206 allow_empty_group = False
214 repo_group_form = RepoGroupForm(
207 repo_group_form = RepoGroupForm(
215 edit=True,
208 edit=True,
216 old_data=c.repo_group.get_dict(),
209 old_data=c.repo_group.get_dict(),
217 repo_groups=c.repo_groups,
210 repo_groups=c.repo_groups,
218 can_create_in_root=allow_empty_group,
211 can_create_in_root=allow_empty_group,
219 )()
212 )()
220 try:
213 try:
221 form_result = repo_group_form.to_python(dict(request.POST))
214 form_result = repo_group_form.to_python(dict(request.POST))
222
215
223 new_gr = RepoGroupModel().update(group_name, form_result)
216 new_gr = RepoGroupModel().update(group_name, form_result)
224 meta.Session().commit()
217 meta.Session().commit()
225 webutils.flash(_('Updated repository group %s')
218 webutils.flash(_('Updated repository group %s')
226 % form_result['group_name'], category='success')
219 % form_result['group_name'], category='success')
227 # we now have new name !
220 # we now have new name !
228 group_name = new_gr.group_name
221 group_name = new_gr.group_name
229 # TODO: in future action_logger(, '', '', '')
222 # TODO: in future action_logger(, '', '', '')
230 except formencode.Invalid as errors:
223 except formencode.Invalid as errors:
231 c.active = 'settings'
224 c.active = 'settings'
232 return htmlfill.render(
225 return htmlfill.render(
233 base.render('admin/repo_groups/repo_group_edit.html'),
226 base.render('admin/repo_groups/repo_group_edit.html'),
234 defaults=errors.value,
227 defaults=errors.value,
235 errors=errors.error_dict or {},
228 errors=errors.error_dict or {},
236 prefix_error=False,
229 prefix_error=False,
237 encoding="UTF-8",
230 encoding="UTF-8",
238 force_defaults=False)
231 force_defaults=False)
239 except Exception:
232 except Exception:
240 log.error(traceback.format_exc())
233 log.error(traceback.format_exc())
241 webutils.flash(_('Error occurred during update of repository group %s')
234 webutils.flash(_('Error occurred during update of repository group %s')
242 % request.POST.get('group_name'), category='error')
235 % request.POST.get('group_name'), category='error')
243
236
244 raise HTTPFound(location=url('edit_repo_group', group_name=group_name))
237 raise HTTPFound(location=url('edit_repo_group', group_name=group_name))
245
238
246 @HasRepoGroupPermissionLevelDecorator('admin')
239 @HasRepoGroupPermissionLevelDecorator('admin')
247 def delete(self, group_name):
240 def delete(self, group_name):
248 gr = c.repo_group = db.RepoGroup.guess_instance(group_name)
241 gr = c.repo_group = db.RepoGroup.guess_instance(group_name)
249 parent_group = gr.parent_group
242 parent_group = gr.parent_group
250 repos = gr.repositories.all()
243 repos = gr.repositories.all()
251 if repos:
244 if repos:
252 webutils.flash(_('This group contains %s repositories and cannot be '
245 webutils.flash(_('This group contains %s repositories and cannot be '
253 'deleted') % len(repos), category='warning')
246 'deleted') % len(repos), category='warning')
254 raise HTTPFound(location=url('repos_groups'))
247 raise HTTPFound(location=url('repos_groups'))
255
248
256 children = gr.children.all()
249 children = gr.children.all()
257 if children:
250 if children:
258 webutils.flash(_('This group contains %s subgroups and cannot be deleted'
251 webutils.flash(_('This group contains %s subgroups and cannot be deleted'
259 % (len(children))), category='warning')
252 % (len(children))), category='warning')
260 raise HTTPFound(location=url('repos_groups'))
253 raise HTTPFound(location=url('repos_groups'))
261
254
262 try:
255 try:
263 RepoGroupModel().delete(group_name)
256 RepoGroupModel().delete(group_name)
264 meta.Session().commit()
257 meta.Session().commit()
265 webutils.flash(_('Removed repository group %s') % group_name,
258 webutils.flash(_('Removed repository group %s') % group_name,
266 category='success')
259 category='success')
267 # TODO: in future action_logger(, '', '', '')
260 # TODO: in future action_logger(, '', '', '')
268 except Exception:
261 except Exception:
269 log.error(traceback.format_exc())
262 log.error(traceback.format_exc())
270 webutils.flash(_('Error occurred during deletion of repository group %s')
263 webutils.flash(_('Error occurred during deletion of repository group %s')
271 % group_name, category='error')
264 % group_name, category='error')
272
265
273 if parent_group:
266 if parent_group:
274 raise HTTPFound(location=url('repos_group_home', group_name=parent_group.group_name))
267 raise HTTPFound(location=url('repos_group_home', group_name=parent_group.group_name))
275 raise HTTPFound(location=url('repos_groups'))
268 raise HTTPFound(location=url('repos_groups'))
276
269
277 def show_by_name(self, group_name):
270 def show_by_name(self, group_name):
278 """
271 """
279 This is a proxy that does a lookup group_name -> id, and shows
272 This is a proxy that does a lookup group_name -> id, and shows
280 the group by id view instead
273 the group by id view instead
281 """
274 """
282 group_name = group_name.rstrip('/')
275 group_name = group_name.rstrip('/')
283 id_ = db.RepoGroup.get_by_group_name(group_name)
276 id_ = db.RepoGroup.get_by_group_name(group_name)
284 if id_:
277 if id_:
285 return self.show(group_name)
278 return self.show(group_name)
286 raise HTTPNotFound
279 raise HTTPNotFound
287
280
288 @HasRepoGroupPermissionLevelDecorator('read')
281 @HasRepoGroupPermissionLevelDecorator('read')
289 def show(self, group_name):
282 def show(self, group_name):
290 c.active = 'settings'
283 c.active = 'settings'
291
284
292 c.group = c.repo_group = db.RepoGroup.guess_instance(group_name)
285 c.group = c.repo_group = db.RepoGroup.guess_instance(group_name)
293
286
294 groups = db.RepoGroup.query(sorted=True).filter_by(parent_group=c.group).all()
287 groups = db.RepoGroup.query(sorted=True).filter_by(parent_group=c.group).all()
295 repo_groups_list = self.scm_model.get_repo_groups(groups)
288 repo_groups_list = self.scm_model.get_repo_groups(groups)
296
289
297 repos_list = db.Repository.query(sorted=True).filter_by(group=c.group).all()
290 repos_list = db.Repository.query(sorted=True).filter_by(group=c.group).all()
298 c.data = RepoModel().get_repos_as_dict(repos_list,
291 c.data = RepoModel().get_repos_as_dict(repos_list,
299 repo_groups_list=repo_groups_list,
292 repo_groups_list=repo_groups_list,
300 short_name=True)
293 short_name=True)
301
294
302 return base.render('admin/repo_groups/repo_group_show.html')
295 return base.render('admin/repo_groups/repo_group_show.html')
303
296
304 @HasRepoGroupPermissionLevelDecorator('admin')
297 @HasRepoGroupPermissionLevelDecorator('admin')
305 def edit(self, group_name):
298 def edit(self, group_name):
306 c.active = 'settings'
299 c.active = 'settings'
307
300
308 c.repo_group = db.RepoGroup.guess_instance(group_name)
301 c.repo_group = db.RepoGroup.guess_instance(group_name)
309 self.__load_defaults(extras=[c.repo_group.parent_group],
302 self.__load_defaults(extras=[c.repo_group.parent_group],
310 exclude=[c.repo_group])
303 exclude=[c.repo_group])
311 defaults = self.__load_data(c.repo_group.group_id)
304 defaults = self.__load_data(c.repo_group.group_id)
312
305
313 return htmlfill.render(
306 return htmlfill.render(
314 base.render('admin/repo_groups/repo_group_edit.html'),
307 base.render('admin/repo_groups/repo_group_edit.html'),
315 defaults=defaults,
308 defaults=defaults,
316 encoding="UTF-8",
309 encoding="UTF-8",
317 force_defaults=False
310 force_defaults=False
318 )
311 )
319
312
320 @HasRepoGroupPermissionLevelDecorator('admin')
313 @HasRepoGroupPermissionLevelDecorator('admin')
321 def edit_repo_group_advanced(self, group_name):
314 def edit_repo_group_advanced(self, group_name):
322 c.active = 'advanced'
315 c.active = 'advanced'
323 c.repo_group = db.RepoGroup.guess_instance(group_name)
316 c.repo_group = db.RepoGroup.guess_instance(group_name)
324
317
325 return base.render('admin/repo_groups/repo_group_edit.html')
318 return base.render('admin/repo_groups/repo_group_edit.html')
326
319
327 @HasRepoGroupPermissionLevelDecorator('admin')
320 @HasRepoGroupPermissionLevelDecorator('admin')
328 def edit_repo_group_perms(self, group_name):
321 def edit_repo_group_perms(self, group_name):
329 c.active = 'perms'
322 c.active = 'perms'
330 c.repo_group = db.RepoGroup.guess_instance(group_name)
323 c.repo_group = db.RepoGroup.guess_instance(group_name)
331 self.__load_defaults()
324 self.__load_defaults()
332 defaults = self.__load_data(c.repo_group.group_id)
325 defaults = self.__load_data(c.repo_group.group_id)
333
326
334 return htmlfill.render(
327 return htmlfill.render(
335 base.render('admin/repo_groups/repo_group_edit.html'),
328 base.render('admin/repo_groups/repo_group_edit.html'),
336 defaults=defaults,
329 defaults=defaults,
337 encoding="UTF-8",
330 encoding="UTF-8",
338 force_defaults=False
331 force_defaults=False
339 )
332 )
340
333
341 @HasRepoGroupPermissionLevelDecorator('admin')
334 @HasRepoGroupPermissionLevelDecorator('admin')
342 def update_perms(self, group_name):
335 def update_perms(self, group_name):
343 """
336 """
344 Update permissions for given repository group
337 Update permissions for given repository group
345
338
346 :param group_name:
339 :param group_name:
347 """
340 """
348
341
349 c.repo_group = db.RepoGroup.guess_instance(group_name)
342 c.repo_group = db.RepoGroup.guess_instance(group_name)
350 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
343 valid_recursive_choices = ['none', 'repos', 'groups', 'all']
351 form_result = RepoGroupPermsForm(valid_recursive_choices)().to_python(request.POST)
344 form_result = RepoGroupPermsForm(valid_recursive_choices)().to_python(request.POST)
352 if not request.authuser.is_admin:
353 if self._revoke_perms_on_yourself(form_result):
354 msg = _('Cannot revoke permission for yourself as admin')
355 webutils.flash(msg, category='warning')
356 raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name))
357 recursive = form_result['recursive']
345 recursive = form_result['recursive']
358 # iterate over all members(if in recursive mode) of this groups and
346 # iterate over all members(if in recursive mode) of this groups and
359 # set the permissions !
347 # set the permissions !
360 # this can be potentially heavy operation
348 # this can be potentially heavy operation
361 RepoGroupModel()._update_permissions(c.repo_group,
349 RepoGroupModel()._update_permissions(c.repo_group,
362 form_result['perms_new'],
350 form_result['perms_new'],
363 form_result['perms_updates'],
351 form_result['perms_updates'],
364 recursive)
352 recursive)
365 # TODO: implement this
353 # TODO: implement this
366 #action_logger(request.authuser, 'admin_changed_repo_permissions',
354 #action_logger(request.authuser, 'admin_changed_repo_permissions',
367 # repo_name, request.ip_addr)
355 # repo_name, request.ip_addr)
368 meta.Session().commit()
356 meta.Session().commit()
369 webutils.flash(_('Repository group permissions updated'), category='success')
357 webutils.flash(_('Repository group permissions updated'), category='success')
370 raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name))
358 raise HTTPFound(location=url('edit_repo_group_perms', group_name=group_name))
371
359
372 @HasRepoGroupPermissionLevelDecorator('admin')
360 @HasRepoGroupPermissionLevelDecorator('admin')
373 def delete_perms(self, group_name):
361 def delete_perms(self, group_name):
374 try:
362 try:
375 obj_type = request.POST.get('obj_type')
363 obj_type = request.POST.get('obj_type')
376 obj_id = None
364 obj_id = None
377 if obj_type == 'user':
365 if obj_type == 'user':
378 obj_id = safe_int(request.POST.get('user_id'))
366 obj_id = safe_int(request.POST.get('user_id'))
379 elif obj_type == 'user_group':
367 elif obj_type == 'user_group':
380 obj_id = safe_int(request.POST.get('user_group_id'))
368 obj_id = safe_int(request.POST.get('user_group_id'))
381
369
382 if not request.authuser.is_admin:
383 if obj_type == 'user' and request.authuser.user_id == obj_id:
384 msg = _('Cannot revoke permission for yourself as admin')
385 webutils.flash(msg, category='warning')
386 raise Exception('revoke admin permission on self')
387 recursive = request.POST.get('recursive', 'none')
370 recursive = request.POST.get('recursive', 'none')
388 if obj_type == 'user':
371 if obj_type == 'user':
389 RepoGroupModel().delete_permission(repo_group=group_name,
372 RepoGroupModel().delete_permission(repo_group=group_name,
390 obj=obj_id, obj_type='user',
373 obj=obj_id, obj_type='user',
391 recursive=recursive)
374 recursive=recursive)
392 elif obj_type == 'user_group':
375 elif obj_type == 'user_group':
393 RepoGroupModel().delete_permission(repo_group=group_name,
376 RepoGroupModel().delete_permission(repo_group=group_name,
394 obj=obj_id,
377 obj=obj_id,
395 obj_type='user_group',
378 obj_type='user_group',
396 recursive=recursive)
379 recursive=recursive)
397
380
398 meta.Session().commit()
381 meta.Session().commit()
399 except Exception:
382 except Exception:
400 log.error(traceback.format_exc())
383 log.error(traceback.format_exc())
401 webutils.flash(_('An error occurred during revoking of permission'),
384 webutils.flash(_('An error occurred during revoking of permission'),
402 category='error')
385 category='error')
403 raise HTTPInternalServerError()
386 raise HTTPInternalServerError()
@@ -1,122 +1,109 b''
1 ${h.form(url('edit_repo_group_perms', group_name=c.repo_group.group_name))}
1 ${h.form(url('edit_repo_group_perms', group_name=c.repo_group.group_name))}
2 <div class="form">
2 <div class="form">
3 <div>
3 <div>
4 <table id="permissions_manage" class="table">
4 <table id="permissions_manage" class="table">
5 <tr>
5 <tr>
6 <td>${_('None')}<br />(${_('Not visible')})</td>
6 <td>${_('None')}<br />(${_('Not visible')})</td>
7 <td>${_('Read')}<br />(${_('Visible')})</td>
7 <td>${_('Read')}<br />(${_('Visible')})</td>
8 <td>${_('Write')}<br />(${_('Add repos')})</td>
8 <td>${_('Write')}<br />(${_('Add repos')})</td>
9 <td>${_('Admin')}<br />(${_('Add/Edit groups')})</td>
9 <td>${_('Admin')}<br />(${_('Add/Edit groups')})</td>
10 <td>${_('User/User Group')}</td>
10 <td>${_('User/User Group')}</td>
11 <td></td>
11 <td></td>
12 </tr>
12 </tr>
13 ## USERS
13 ## USERS
14 %for r2p in c.repo_group.repo_group_to_perm:
14 %for r2p in c.repo_group.repo_group_to_perm:
15 ##forbid revoking permission from yourself, except if you're an super admin
16 <tr id="id${id(r2p.user.username)}">
15 <tr id="id${id(r2p.user.username)}">
17 %if request.authuser.user_id != r2p.user.user_id or request.authuser.is_admin:
18 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.none')}</td>
16 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.none')}</td>
19 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.read')}</td>
17 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.read')}</td>
20 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.write')}</td>
18 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.write')}</td>
21 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.admin')}</td>
19 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.admin')}</td>
22 <td>
20 <td>
23 ${h.gravatar(r2p.user.email, cls="perm-gravatar", size=14)}
21 ${h.gravatar(r2p.user.email, cls="perm-gravatar", size=14)}
24 %if h.HasPermissionAny('hg.admin')() and r2p.user.username != 'default':
22 %if h.HasPermissionAny('hg.admin')() and r2p.user.username != 'default':
25 <a href="${h.url('edit_user',id=r2p.user.user_id)}">${r2p.user.username}</a>
23 <a href="${h.url('edit_user',id=r2p.user.user_id)}">${r2p.user.username}</a>
26 %else:
24 %else:
27 ${r2p.user.username if r2p.user.username != 'default' else _('Default')}
25 ${r2p.user.username if r2p.user.username != 'default' else _('Default')}
28 %endif
26 %endif
29 </td>
27 </td>
30 <td>
28 <td>
31 %if r2p.user.username !='default':
29 %if r2p.user.username !='default':
32 <button type="button" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}', '${r2p.user.username}')">
30 <button type="button" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${r2p.user.user_id}, 'user', '${'id%s'%id(r2p.user.username)}', '${r2p.user.username}')">
33 <i class="icon-minus-circled"></i>${_('Revoke')}
31 <i class="icon-minus-circled"></i>${_('Revoke')}
34 </button>
32 </button>
35 %endif
33 %endif
36 </td>
34 </td>
37 %else:
38 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.none', disabled="disabled")}</td>
39 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.read', disabled="disabled")}</td>
40 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.write', disabled="disabled")}</td>
41 <td>${h.radio('u_perm_%s' % r2p.user.username,'group.admin', disabled="disabled")}</td>
42 <td>
43 ${h.gravatar(r2p.user.email, cls="perm-gravatar", size=14)}
44 ${r2p.user.username if r2p.user.username != 'default' else _('Default')}
45 </td>
46 <td><i class="icon-user"></i>${_('Admin')}</td>
47 %endif
48 </tr>
35 </tr>
49 %endfor
36 %endfor
50
37
51 ## USER GROUPS
38 ## USER GROUPS
52 %for g2p in c.repo_group.users_group_to_perm:
39 %for g2p in c.repo_group.users_group_to_perm:
53 <tr id="id${id(g2p.users_group.users_group_name)}">
40 <tr id="id${id(g2p.users_group.users_group_name)}">
54 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.none')}</td>
41 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.none')}</td>
55 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.read')}</td>
42 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.read')}</td>
56 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.write')}</td>
43 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.write')}</td>
57 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.admin')}</td>
44 <td>${h.radio('g_perm_%s' % g2p.users_group.users_group_name,'group.admin')}</td>
58 <td>
45 <td>
59 <i class="icon-users"></i>
46 <i class="icon-users"></i>
60 %if h.HasPermissionAny('hg.admin')():
47 %if h.HasPermissionAny('hg.admin')():
61 <a href="${h.url('edit_users_group',id=g2p.users_group.users_group_id)}">
48 <a href="${h.url('edit_users_group',id=g2p.users_group.users_group_id)}">
62 ${g2p.users_group.users_group_name}
49 ${g2p.users_group.users_group_name}
63 </a>
50 </a>
64 %else:
51 %else:
65 ${g2p.users_group.users_group_name}
52 ${g2p.users_group.users_group_name}
66 %endif
53 %endif
67 </td>
54 </td>
68 <td>
55 <td>
69 <button type="button" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${g2p.users_group.users_group_id}, 'user_group', '${'id%s'%id(g2p.users_group.users_group_name)}', '${g2p.users_group.users_group_name}')">
56 <button type="button" class="btn btn-default btn-xs" onclick="ajaxActionRevoke(${g2p.users_group.users_group_id}, 'user_group', '${'id%s'%id(g2p.users_group.users_group_name)}', '${g2p.users_group.users_group_name}')">
70 <i class="icon-minus-circled"></i>${_('Revoke')}
57 <i class="icon-minus-circled"></i>${_('Revoke')}
71 </button>
58 </button>
72 </td>
59 </td>
73 </tr>
60 </tr>
74 %endfor
61 %endfor
75 ## New entries added by addPermAction here.
62 ## New entries added by addPermAction here.
76 <tr class="new_members last_new_member" id="add_perm_input"><td colspan="6"></td></tr>
63 <tr class="new_members last_new_member" id="add_perm_input"><td colspan="6"></td></tr>
77 <tr>
64 <tr>
78 <td colspan="6">
65 <td colspan="6">
79 <button type="button" id="add_perm" class="btn btn-link btn-xs">
66 <button type="button" id="add_perm" class="btn btn-link btn-xs">
80 <i class="icon-plus"></i>${_('Add new')}
67 <i class="icon-plus"></i>${_('Add new')}
81 </button>
68 </button>
82 </td>
69 </td>
83 </tr>
70 </tr>
84 <tr>
71 <tr>
85 <td colspan="6">
72 <td colspan="6">
86 ${_('Apply to children')}:
73 ${_('Apply to children')}:
87 ${h.radio('recursive', 'none', label=_('None'), checked="checked")}
74 ${h.radio('recursive', 'none', label=_('None'), checked="checked")}
88 ${h.radio('recursive', 'groups', label=_('Repository Groups'))}
75 ${h.radio('recursive', 'groups', label=_('Repository Groups'))}
89 ${h.radio('recursive', 'repos', label=_('Repositories'))}
76 ${h.radio('recursive', 'repos', label=_('Repositories'))}
90 ${h.radio('recursive', 'all', label=_('Both'))}
77 ${h.radio('recursive', 'all', label=_('Both'))}
91 <span class="help-block">${_('Set or revoke permission to all children of that group, including non-private repositories and other groups if selected.')}</span>
78 <span class="help-block">${_('Set or revoke permission to all children of that group, including non-private repositories and other groups if selected.')}</span>
92 </td>
79 </td>
93 </tr>
80 </tr>
94 </table>
81 </table>
95 </div>
82 </div>
96 <div class="buttons">
83 <div class="buttons">
97 ${h.submit('save',_('Save'),class_="btn btn-default")}
84 ${h.submit('save',_('Save'),class_="btn btn-default")}
98 ${h.reset('reset',_('Reset'),class_="btn btn-default")}
85 ${h.reset('reset',_('Reset'),class_="btn btn-default")}
99 </div>
86 </div>
100 </div>
87 </div>
101 ${h.end_form()}
88 ${h.end_form()}
102
89
103 <script>
90 <script>
104 'use strict';
91 'use strict';
105 function ajaxActionRevoke(obj_id, obj_type, field_id, obj_name) {
92 function ajaxActionRevoke(obj_id, obj_type, field_id, obj_name) {
106 let url = ${h.jshtml(h.url('edit_repo_group_perms_delete', group_name=c.repo_group.group_name))};
93 let url = ${h.jshtml(h.url('edit_repo_group_perms_delete', group_name=c.repo_group.group_name))};
107 var revoke_msg = _TM['Confirm to revoke permission for {0}: {1}?'].format(obj_type.replace('_', ' '), obj_name);
94 var revoke_msg = _TM['Confirm to revoke permission for {0}: {1}?'].format(obj_type.replace('_', ' '), obj_name);
108 if (confirm(revoke_msg)){
95 if (confirm(revoke_msg)){
109 var recursive = $('input[name=recursive]:checked').val();
96 var recursive = $('input[name=recursive]:checked').val();
110 ajaxActionRevokePermission(url, obj_id, obj_type, field_id, {recursive:recursive});
97 ajaxActionRevokePermission(url, obj_id, obj_type, field_id, {recursive:recursive});
111 }
98 }
112 }
99 }
113
100
114 $(document).ready(function () {
101 $(document).ready(function () {
115 if (!$('#perm_new_member_name').hasClass('error')) {
102 if (!$('#perm_new_member_name').hasClass('error')) {
116 $('#add_perm_input').hide();
103 $('#add_perm_input').hide();
117 }
104 }
118 $('#add_perm').click(function () {
105 $('#add_perm').click(function () {
119 addPermAction('group');
106 addPermAction('group');
120 });
107 });
121 });
108 });
122 </script>
109 </script>
General Comments 0
You need to be logged in to leave comments. Login now