##// END OF EJS Templates
admin: in usergroups admin allow prefiltering the list of users...
dan -
r93:07ae5171 default
parent child Browse files
Show More
@@ -1,471 +1,480 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 User Groups crud controller for pylons
22 User Groups crud controller for pylons
23 """
23 """
24
24
25 import logging
25 import logging
26 import formencode
26 import formencode
27
27
28 from formencode import htmlfill
28 from formencode import htmlfill
29 from pylons import request, tmpl_context as c, url, config
29 from pylons import request, tmpl_context as c, url, config
30 from pylons.controllers.util import redirect
30 from pylons.controllers.util import redirect
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32
32
33 from sqlalchemy.orm import joinedload
33 from sqlalchemy.orm import joinedload
34
34
35 from rhodecode.lib import auth
35 from rhodecode.lib import auth
36 from rhodecode.lib import helpers as h
36 from rhodecode.lib import helpers as h
37 from rhodecode.lib.exceptions import UserGroupAssignedException,\
37 from rhodecode.lib.exceptions import UserGroupAssignedException,\
38 RepoGroupAssignmentError
38 RepoGroupAssignmentError
39 from rhodecode.lib.utils import jsonify, action_logger
39 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
40 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
40 from rhodecode.lib.auth import (
41 from rhodecode.lib.auth import (
41 LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator,
42 LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator,
42 HasPermissionAnyDecorator)
43 HasPermissionAnyDecorator)
43 from rhodecode.lib.base import BaseController, render
44 from rhodecode.lib.base import BaseController, render
44 from rhodecode.model.permission import PermissionModel
45 from rhodecode.model.permission import PermissionModel
45 from rhodecode.model.scm import UserGroupList
46 from rhodecode.model.scm import UserGroupList
46 from rhodecode.model.user_group import UserGroupModel
47 from rhodecode.model.user_group import UserGroupModel
47 from rhodecode.model.db import (
48 from rhodecode.model.db import (
48 User, UserGroup, UserGroupRepoToPerm, UserGroupRepoGroupToPerm)
49 User, UserGroup, UserGroupRepoToPerm, UserGroupRepoGroupToPerm)
49 from rhodecode.model.forms import (
50 from rhodecode.model.forms import (
50 UserGroupForm, UserGroupPermsForm, UserIndividualPermissionsForm,
51 UserGroupForm, UserGroupPermsForm, UserIndividualPermissionsForm,
51 UserPermissionsForm)
52 UserPermissionsForm)
52 from rhodecode.model.meta import Session
53 from rhodecode.model.meta import Session
53 from rhodecode.lib.utils import action_logger
54 from rhodecode.lib.utils import action_logger
54 from rhodecode.lib.ext_json import json
55 from rhodecode.lib.ext_json import json
55
56
56 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
57
58
58
59
59 class UserGroupsController(BaseController):
60 class UserGroupsController(BaseController):
60 """REST Controller styled on the Atom Publishing Protocol"""
61 """REST Controller styled on the Atom Publishing Protocol"""
61
62
62 @LoginRequired()
63 @LoginRequired()
63 def __before__(self):
64 def __before__(self):
64 super(UserGroupsController, self).__before__()
65 super(UserGroupsController, self).__before__()
65 c.available_permissions = config['available_permissions']
66 c.available_permissions = config['available_permissions']
66 PermissionModel().set_global_permission_choices(c, translator=_)
67 PermissionModel().set_global_permission_choices(c, translator=_)
67
68
68 def __load_data(self, user_group_id):
69 def __load_data(self, user_group_id):
69 c.group_members_obj = [x.user for x in c.user_group.members]
70 c.group_members_obj = [x.user for x in c.user_group.members]
70 c.group_members_obj.sort(key=lambda u: u.username.lower())
71 c.group_members_obj.sort(key=lambda u: u.username.lower())
71
72
72 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
73 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
73
74
74 c.available_members = [(x.user_id, x.username)
75 c.available_members = [(x.user_id, x.username)
75 for x in User.query().all()]
76 for x in User.query().all()]
76 c.available_members.sort(key=lambda u: u[1].lower())
77 c.available_members.sort(key=lambda u: u[1].lower())
77
78
78 def __load_defaults(self, user_group_id):
79 def __load_defaults(self, user_group_id):
79 """
80 """
80 Load defaults settings for edit, and update
81 Load defaults settings for edit, and update
81
82
82 :param user_group_id:
83 :param user_group_id:
83 """
84 """
84 user_group = UserGroup.get_or_404(user_group_id)
85 user_group = UserGroup.get_or_404(user_group_id)
85 data = user_group.get_dict()
86 data = user_group.get_dict()
86 # fill owner
87 # fill owner
87 if user_group.user:
88 if user_group.user:
88 data.update({'user': user_group.user.username})
89 data.update({'user': user_group.user.username})
89 else:
90 else:
90 replacement_user = User.get_first_admin().username
91 replacement_user = User.get_first_admin().username
91 data.update({'user': replacement_user})
92 data.update({'user': replacement_user})
92 return data
93 return data
93
94
94 def _revoke_perms_on_yourself(self, form_result):
95 def _revoke_perms_on_yourself(self, form_result):
95 _updates = filter(lambda u: c.rhodecode_user.user_id == int(u[0]),
96 _updates = filter(lambda u: c.rhodecode_user.user_id == int(u[0]),
96 form_result['perm_updates'])
97 form_result['perm_updates'])
97 _additions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]),
98 _additions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]),
98 form_result['perm_additions'])
99 form_result['perm_additions'])
99 _deletions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]),
100 _deletions = filter(lambda u: c.rhodecode_user.user_id == int(u[0]),
100 form_result['perm_deletions'])
101 form_result['perm_deletions'])
101 admin_perm = 'usergroup.admin'
102 admin_perm = 'usergroup.admin'
102 if _updates and _updates[0][1] != admin_perm or \
103 if _updates and _updates[0][1] != admin_perm or \
103 _additions and _additions[0][1] != admin_perm or \
104 _additions and _additions[0][1] != admin_perm or \
104 _deletions and _deletions[0][1] != admin_perm:
105 _deletions and _deletions[0][1] != admin_perm:
105 return True
106 return True
106 return False
107 return False
107
108
108 # permission check inside
109 # permission check inside
109 @NotAnonymous()
110 @NotAnonymous()
110 def index(self):
111 def index(self):
111 """GET /users_groups: All items in the collection"""
112 """GET /users_groups: All items in the collection"""
112 # url('users_groups')
113 # url('users_groups')
113
114
114 from rhodecode.lib.utils import PartialRenderer
115 from rhodecode.lib.utils import PartialRenderer
115 _render = PartialRenderer('data_table/_dt_elements.html')
116 _render = PartialRenderer('data_table/_dt_elements.html')
116
117
117 def user_group_name(user_group_id, user_group_name):
118 def user_group_name(user_group_id, user_group_name):
118 return _render("user_group_name", user_group_id, user_group_name)
119 return _render("user_group_name", user_group_id, user_group_name)
119
120
120 def user_group_actions(user_group_id, user_group_name):
121 def user_group_actions(user_group_id, user_group_name):
121 return _render("user_group_actions", user_group_id, user_group_name)
122 return _render("user_group_actions", user_group_id, user_group_name)
122
123
123 ## json generate
124 ## json generate
124 group_iter = UserGroupList(UserGroup.query().all(),
125 group_iter = UserGroupList(UserGroup.query().all(),
125 perm_set=['usergroup.admin'])
126 perm_set=['usergroup.admin'])
126
127
127 user_groups_data = []
128 user_groups_data = []
128 for user_gr in group_iter:
129 for user_gr in group_iter:
129 user_groups_data.append({
130 user_groups_data.append({
130 "group_name": user_group_name(
131 "group_name": user_group_name(
131 user_gr.users_group_id, h.escape(user_gr.users_group_name)),
132 user_gr.users_group_id, h.escape(user_gr.users_group_name)),
132 "group_name_raw": user_gr.users_group_name,
133 "group_name_raw": user_gr.users_group_name,
133 "desc": h.escape(user_gr.user_group_description),
134 "desc": h.escape(user_gr.user_group_description),
134 "members": len(user_gr.members),
135 "members": len(user_gr.members),
135 "active": h.bool2icon(user_gr.users_group_active),
136 "active": h.bool2icon(user_gr.users_group_active),
136 "owner": h.escape(h.link_to_user(user_gr.user.username)),
137 "owner": h.escape(h.link_to_user(user_gr.user.username)),
137 "action": user_group_actions(
138 "action": user_group_actions(
138 user_gr.users_group_id, user_gr.users_group_name)
139 user_gr.users_group_id, user_gr.users_group_name)
139 })
140 })
140
141
141 c.data = json.dumps(user_groups_data)
142 c.data = json.dumps(user_groups_data)
142 return render('admin/user_groups/user_groups.html')
143 return render('admin/user_groups/user_groups.html')
143
144
144 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
145 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
145 @auth.CSRFRequired()
146 @auth.CSRFRequired()
146 def create(self):
147 def create(self):
147 """POST /users_groups: Create a new item"""
148 """POST /users_groups: Create a new item"""
148 # url('users_groups')
149 # url('users_groups')
149
150
150 users_group_form = UserGroupForm()()
151 users_group_form = UserGroupForm()()
151 try:
152 try:
152 form_result = users_group_form.to_python(dict(request.POST))
153 form_result = users_group_form.to_python(dict(request.POST))
153 user_group = UserGroupModel().create(
154 user_group = UserGroupModel().create(
154 name=form_result['users_group_name'],
155 name=form_result['users_group_name'],
155 description=form_result['user_group_description'],
156 description=form_result['user_group_description'],
156 owner=c.rhodecode_user.user_id,
157 owner=c.rhodecode_user.user_id,
157 active=form_result['users_group_active'])
158 active=form_result['users_group_active'])
158 Session().flush()
159 Session().flush()
159
160
160 user_group_name = form_result['users_group_name']
161 user_group_name = form_result['users_group_name']
161 action_logger(c.rhodecode_user,
162 action_logger(c.rhodecode_user,
162 'admin_created_users_group:%s' % user_group_name,
163 'admin_created_users_group:%s' % user_group_name,
163 None, self.ip_addr, self.sa)
164 None, self.ip_addr, self.sa)
164 user_group_link = h.link_to(h.escape(user_group_name),
165 user_group_link = h.link_to(h.escape(user_group_name),
165 url('edit_users_group',
166 url('edit_users_group',
166 user_group_id=user_group.users_group_id))
167 user_group_id=user_group.users_group_id))
167 h.flash(h.literal(_('Created user group %(user_group_link)s')
168 h.flash(h.literal(_('Created user group %(user_group_link)s')
168 % {'user_group_link': user_group_link}),
169 % {'user_group_link': user_group_link}),
169 category='success')
170 category='success')
170 Session().commit()
171 Session().commit()
171 except formencode.Invalid as errors:
172 except formencode.Invalid as errors:
172 return htmlfill.render(
173 return htmlfill.render(
173 render('admin/user_groups/user_group_add.html'),
174 render('admin/user_groups/user_group_add.html'),
174 defaults=errors.value,
175 defaults=errors.value,
175 errors=errors.error_dict or {},
176 errors=errors.error_dict or {},
176 prefix_error=False,
177 prefix_error=False,
177 encoding="UTF-8",
178 encoding="UTF-8",
178 force_defaults=False)
179 force_defaults=False)
179 except Exception:
180 except Exception:
180 log.exception("Exception creating user group")
181 log.exception("Exception creating user group")
181 h.flash(_('Error occurred during creation of user group %s') \
182 h.flash(_('Error occurred during creation of user group %s') \
182 % request.POST.get('users_group_name'), category='error')
183 % request.POST.get('users_group_name'), category='error')
183
184
184 return redirect(url('users_groups'))
185 return redirect(
186 url('edit_users_group', user_group_id=user_group.users_group_id))
185
187
186 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
188 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
187 def new(self):
189 def new(self):
188 """GET /user_groups/new: Form to create a new item"""
190 """GET /user_groups/new: Form to create a new item"""
189 # url('new_users_group')
191 # url('new_users_group')
190 return render('admin/user_groups/user_group_add.html')
192 return render('admin/user_groups/user_group_add.html')
191
193
192 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
194 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
193 @auth.CSRFRequired()
195 @auth.CSRFRequired()
194 def update(self, user_group_id):
196 def update(self, user_group_id):
195 """PUT /user_groups/user_group_id: Update an existing item"""
197 """PUT /user_groups/user_group_id: Update an existing item"""
196 # Forms posted to this method should contain a hidden field:
198 # Forms posted to this method should contain a hidden field:
197 # <input type="hidden" name="_method" value="PUT" />
199 # <input type="hidden" name="_method" value="PUT" />
198 # Or using helpers:
200 # Or using helpers:
199 # h.form(url('users_group', user_group_id=ID),
201 # h.form(url('users_group', user_group_id=ID),
200 # method='put')
202 # method='put')
201 # url('users_group', user_group_id=ID)
203 # url('users_group', user_group_id=ID)
202
204
203 user_group_id = safe_int(user_group_id)
205 user_group_id = safe_int(user_group_id)
204 c.user_group = UserGroup.get_or_404(user_group_id)
206 c.user_group = UserGroup.get_or_404(user_group_id)
205 c.active = 'settings'
207 c.active = 'settings'
206 self.__load_data(user_group_id)
208 self.__load_data(user_group_id)
207
209
208 available_members = [safe_unicode(x[0]) for x in c.available_members]
210 available_members = [safe_unicode(x[0]) for x in c.available_members]
209
211
210 users_group_form = UserGroupForm(edit=True,
212 users_group_form = UserGroupForm(edit=True,
211 old_data=c.user_group.get_dict(),
213 old_data=c.user_group.get_dict(),
212 available_members=available_members)()
214 available_members=available_members)()
213
215
214 try:
216 try:
215 form_result = users_group_form.to_python(request.POST)
217 form_result = users_group_form.to_python(request.POST)
216 UserGroupModel().update(c.user_group, form_result)
218 UserGroupModel().update(c.user_group, form_result)
217 gr = form_result['users_group_name']
219 gr = form_result['users_group_name']
218 action_logger(c.rhodecode_user,
220 action_logger(c.rhodecode_user,
219 'admin_updated_users_group:%s' % gr,
221 'admin_updated_users_group:%s' % gr,
220 None, self.ip_addr, self.sa)
222 None, self.ip_addr, self.sa)
221 h.flash(_('Updated user group %s') % gr, category='success')
223 h.flash(_('Updated user group %s') % gr, category='success')
222 Session().commit()
224 Session().commit()
223 except formencode.Invalid as errors:
225 except formencode.Invalid as errors:
224 defaults = errors.value
226 defaults = errors.value
225 e = errors.error_dict or {}
227 e = errors.error_dict or {}
226
228
227 return htmlfill.render(
229 return htmlfill.render(
228 render('admin/user_groups/user_group_edit.html'),
230 render('admin/user_groups/user_group_edit.html'),
229 defaults=defaults,
231 defaults=defaults,
230 errors=e,
232 errors=e,
231 prefix_error=False,
233 prefix_error=False,
232 encoding="UTF-8",
234 encoding="UTF-8",
233 force_defaults=False)
235 force_defaults=False)
234 except Exception:
236 except Exception:
235 log.exception("Exception during update of user group")
237 log.exception("Exception during update of user group")
236 h.flash(_('Error occurred during update of user group %s')
238 h.flash(_('Error occurred during update of user group %s')
237 % request.POST.get('users_group_name'), category='error')
239 % request.POST.get('users_group_name'), category='error')
238
240
239 return redirect(url('edit_users_group', user_group_id=user_group_id))
241 return redirect(url('edit_users_group', user_group_id=user_group_id))
240
242
241 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
243 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
242 @auth.CSRFRequired()
244 @auth.CSRFRequired()
243 def delete(self, user_group_id):
245 def delete(self, user_group_id):
244 """DELETE /user_groups/user_group_id: Delete an existing item"""
246 """DELETE /user_groups/user_group_id: Delete an existing item"""
245 # Forms posted to this method should contain a hidden field:
247 # Forms posted to this method should contain a hidden field:
246 # <input type="hidden" name="_method" value="DELETE" />
248 # <input type="hidden" name="_method" value="DELETE" />
247 # Or using helpers:
249 # Or using helpers:
248 # h.form(url('users_group', user_group_id=ID),
250 # h.form(url('users_group', user_group_id=ID),
249 # method='delete')
251 # method='delete')
250 # url('users_group', user_group_id=ID)
252 # url('users_group', user_group_id=ID)
251 user_group_id = safe_int(user_group_id)
253 user_group_id = safe_int(user_group_id)
252 c.user_group = UserGroup.get_or_404(user_group_id)
254 c.user_group = UserGroup.get_or_404(user_group_id)
253 force = str2bool(request.POST.get('force'))
255 force = str2bool(request.POST.get('force'))
254
256
255 try:
257 try:
256 UserGroupModel().delete(c.user_group, force=force)
258 UserGroupModel().delete(c.user_group, force=force)
257 Session().commit()
259 Session().commit()
258 h.flash(_('Successfully deleted user group'), category='success')
260 h.flash(_('Successfully deleted user group'), category='success')
259 except UserGroupAssignedException as e:
261 except UserGroupAssignedException as e:
260 h.flash(str(e), category='error')
262 h.flash(str(e), category='error')
261 except Exception:
263 except Exception:
262 log.exception("Exception during deletion of user group")
264 log.exception("Exception during deletion of user group")
263 h.flash(_('An error occurred during deletion of user group'),
265 h.flash(_('An error occurred during deletion of user group'),
264 category='error')
266 category='error')
265 return redirect(url('users_groups'))
267 return redirect(url('users_groups'))
266
268
267 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
269 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
268 def edit(self, user_group_id):
270 def edit(self, user_group_id):
269 """GET /user_groups/user_group_id/edit: Form to edit an existing item"""
271 """GET /user_groups/user_group_id/edit: Form to edit an existing item"""
270 # url('edit_users_group', user_group_id=ID)
272 # url('edit_users_group', user_group_id=ID)
271
273
272 user_group_id = safe_int(user_group_id)
274 user_group_id = safe_int(user_group_id)
273 c.user_group = UserGroup.get_or_404(user_group_id)
275 c.user_group = UserGroup.get_or_404(user_group_id)
274 c.active = 'settings'
276 c.active = 'settings'
275 self.__load_data(user_group_id)
277 self.__load_data(user_group_id)
276
278
277 defaults = self.__load_defaults(user_group_id)
279 defaults = self.__load_defaults(user_group_id)
278
280
279 return htmlfill.render(
281 return htmlfill.render(
280 render('admin/user_groups/user_group_edit.html'),
282 render('admin/user_groups/user_group_edit.html'),
281 defaults=defaults,
283 defaults=defaults,
282 encoding="UTF-8",
284 encoding="UTF-8",
283 force_defaults=False
285 force_defaults=False
284 )
286 )
285
287
286 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
288 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
287 def edit_perms(self, user_group_id):
289 def edit_perms(self, user_group_id):
288 user_group_id = safe_int(user_group_id)
290 user_group_id = safe_int(user_group_id)
289 c.user_group = UserGroup.get_or_404(user_group_id)
291 c.user_group = UserGroup.get_or_404(user_group_id)
290 c.active = 'perms'
292 c.active = 'perms'
291
293
292 defaults = {}
294 defaults = {}
293 # fill user group users
295 # fill user group users
294 for p in c.user_group.user_user_group_to_perm:
296 for p in c.user_group.user_user_group_to_perm:
295 defaults.update({'u_perm_%s' % p.user.user_id:
297 defaults.update({'u_perm_%s' % p.user.user_id:
296 p.permission.permission_name})
298 p.permission.permission_name})
297
299
298 for p in c.user_group.user_group_user_group_to_perm:
300 for p in c.user_group.user_group_user_group_to_perm:
299 defaults.update({'g_perm_%s' % p.user_group.users_group_id:
301 defaults.update({'g_perm_%s' % p.user_group.users_group_id:
300 p.permission.permission_name})
302 p.permission.permission_name})
301
303
302 return htmlfill.render(
304 return htmlfill.render(
303 render('admin/user_groups/user_group_edit.html'),
305 render('admin/user_groups/user_group_edit.html'),
304 defaults=defaults,
306 defaults=defaults,
305 encoding="UTF-8",
307 encoding="UTF-8",
306 force_defaults=False
308 force_defaults=False
307 )
309 )
308
310
309 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
311 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
310 @auth.CSRFRequired()
312 @auth.CSRFRequired()
311 def update_perms(self, user_group_id):
313 def update_perms(self, user_group_id):
312 """
314 """
313 grant permission for given usergroup
315 grant permission for given usergroup
314
316
315 :param user_group_id:
317 :param user_group_id:
316 """
318 """
317 user_group_id = safe_int(user_group_id)
319 user_group_id = safe_int(user_group_id)
318 c.user_group = UserGroup.get_or_404(user_group_id)
320 c.user_group = UserGroup.get_or_404(user_group_id)
319 form = UserGroupPermsForm()().to_python(request.POST)
321 form = UserGroupPermsForm()().to_python(request.POST)
320
322
321 if not c.rhodecode_user.is_admin:
323 if not c.rhodecode_user.is_admin:
322 if self._revoke_perms_on_yourself(form):
324 if self._revoke_perms_on_yourself(form):
323 msg = _('Cannot change permission for yourself as admin')
325 msg = _('Cannot change permission for yourself as admin')
324 h.flash(msg, category='warning')
326 h.flash(msg, category='warning')
325 return redirect(url('edit_user_group_perms', user_group_id=user_group_id))
327 return redirect(url('edit_user_group_perms', user_group_id=user_group_id))
326
328
327 try:
329 try:
328 UserGroupModel().update_permissions(user_group_id,
330 UserGroupModel().update_permissions(user_group_id,
329 form['perm_additions'], form['perm_updates'], form['perm_deletions'])
331 form['perm_additions'], form['perm_updates'], form['perm_deletions'])
330 except RepoGroupAssignmentError:
332 except RepoGroupAssignmentError:
331 h.flash(_('Target group cannot be the same'), category='error')
333 h.flash(_('Target group cannot be the same'), category='error')
332 return redirect(url('edit_user_group_perms', user_group_id=user_group_id))
334 return redirect(url('edit_user_group_perms', user_group_id=user_group_id))
333 #TODO: implement this
335 #TODO: implement this
334 #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions',
336 #action_logger(c.rhodecode_user, 'admin_changed_repo_permissions',
335 # repo_name, self.ip_addr, self.sa)
337 # repo_name, self.ip_addr, self.sa)
336 Session().commit()
338 Session().commit()
337 h.flash(_('User Group permissions updated'), category='success')
339 h.flash(_('User Group permissions updated'), category='success')
338 return redirect(url('edit_user_group_perms', user_group_id=user_group_id))
340 return redirect(url('edit_user_group_perms', user_group_id=user_group_id))
339
341
340 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
342 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
341 def edit_perms_summary(self, user_group_id):
343 def edit_perms_summary(self, user_group_id):
342 user_group_id = safe_int(user_group_id)
344 user_group_id = safe_int(user_group_id)
343 c.user_group = UserGroup.get_or_404(user_group_id)
345 c.user_group = UserGroup.get_or_404(user_group_id)
344 c.active = 'perms_summary'
346 c.active = 'perms_summary'
345 permissions = {
347 permissions = {
346 'repositories': {},
348 'repositories': {},
347 'repositories_groups': {},
349 'repositories_groups': {},
348 }
350 }
349 ugroup_repo_perms = UserGroupRepoToPerm.query()\
351 ugroup_repo_perms = UserGroupRepoToPerm.query()\
350 .options(joinedload(UserGroupRepoToPerm.permission))\
352 .options(joinedload(UserGroupRepoToPerm.permission))\
351 .options(joinedload(UserGroupRepoToPerm.repository))\
353 .options(joinedload(UserGroupRepoToPerm.repository))\
352 .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
354 .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
353 .all()
355 .all()
354
356
355 for gr in ugroup_repo_perms:
357 for gr in ugroup_repo_perms:
356 permissions['repositories'][gr.repository.repo_name] \
358 permissions['repositories'][gr.repository.repo_name] \
357 = gr.permission.permission_name
359 = gr.permission.permission_name
358
360
359 ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
361 ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
360 .options(joinedload(UserGroupRepoGroupToPerm.permission))\
362 .options(joinedload(UserGroupRepoGroupToPerm.permission))\
361 .options(joinedload(UserGroupRepoGroupToPerm.group))\
363 .options(joinedload(UserGroupRepoGroupToPerm.group))\
362 .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
364 .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
363 .all()
365 .all()
364
366
365 for gr in ugroup_group_perms:
367 for gr in ugroup_group_perms:
366 permissions['repositories_groups'][gr.group.group_name] \
368 permissions['repositories_groups'][gr.group.group_name] \
367 = gr.permission.permission_name
369 = gr.permission.permission_name
368 c.permissions = permissions
370 c.permissions = permissions
369 return render('admin/user_groups/user_group_edit.html')
371 return render('admin/user_groups/user_group_edit.html')
370
372
371 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
373 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
372 def edit_global_perms(self, user_group_id):
374 def edit_global_perms(self, user_group_id):
373 user_group_id = safe_int(user_group_id)
375 user_group_id = safe_int(user_group_id)
374 c.user_group = UserGroup.get_or_404(user_group_id)
376 c.user_group = UserGroup.get_or_404(user_group_id)
375 c.active = 'global_perms'
377 c.active = 'global_perms'
376
378
377 c.default_user = User.get_default_user()
379 c.default_user = User.get_default_user()
378 defaults = c.user_group.get_dict()
380 defaults = c.user_group.get_dict()
379 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
381 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
380 defaults.update(c.user_group.get_default_perms())
382 defaults.update(c.user_group.get_default_perms())
381
383
382 return htmlfill.render(
384 return htmlfill.render(
383 render('admin/user_groups/user_group_edit.html'),
385 render('admin/user_groups/user_group_edit.html'),
384 defaults=defaults,
386 defaults=defaults,
385 encoding="UTF-8",
387 encoding="UTF-8",
386 force_defaults=False
388 force_defaults=False
387 )
389 )
388
390
389 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
391 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
390 @auth.CSRFRequired()
392 @auth.CSRFRequired()
391 def update_global_perms(self, user_group_id):
393 def update_global_perms(self, user_group_id):
392 """PUT /users_perm/user_group_id: Update an existing item"""
394 """PUT /users_perm/user_group_id: Update an existing item"""
393 # url('users_group_perm', user_group_id=ID, method='put')
395 # url('users_group_perm', user_group_id=ID, method='put')
394 user_group_id = safe_int(user_group_id)
396 user_group_id = safe_int(user_group_id)
395 user_group = UserGroup.get_or_404(user_group_id)
397 user_group = UserGroup.get_or_404(user_group_id)
396 c.active = 'global_perms'
398 c.active = 'global_perms'
397
399
398 try:
400 try:
399 # first stage that verifies the checkbox
401 # first stage that verifies the checkbox
400 _form = UserIndividualPermissionsForm()
402 _form = UserIndividualPermissionsForm()
401 form_result = _form.to_python(dict(request.POST))
403 form_result = _form.to_python(dict(request.POST))
402 inherit_perms = form_result['inherit_default_permissions']
404 inherit_perms = form_result['inherit_default_permissions']
403 user_group.inherit_default_permissions = inherit_perms
405 user_group.inherit_default_permissions = inherit_perms
404 Session().add(user_group)
406 Session().add(user_group)
405
407
406 if not inherit_perms:
408 if not inherit_perms:
407 # only update the individual ones if we un check the flag
409 # only update the individual ones if we un check the flag
408 _form = UserPermissionsForm(
410 _form = UserPermissionsForm(
409 [x[0] for x in c.repo_create_choices],
411 [x[0] for x in c.repo_create_choices],
410 [x[0] for x in c.repo_create_on_write_choices],
412 [x[0] for x in c.repo_create_on_write_choices],
411 [x[0] for x in c.repo_group_create_choices],
413 [x[0] for x in c.repo_group_create_choices],
412 [x[0] for x in c.user_group_create_choices],
414 [x[0] for x in c.user_group_create_choices],
413 [x[0] for x in c.fork_choices],
415 [x[0] for x in c.fork_choices],
414 [x[0] for x in c.inherit_default_permission_choices])()
416 [x[0] for x in c.inherit_default_permission_choices])()
415
417
416 form_result = _form.to_python(dict(request.POST))
418 form_result = _form.to_python(dict(request.POST))
417 form_result.update({'perm_user_group_id': user_group.users_group_id})
419 form_result.update({'perm_user_group_id': user_group.users_group_id})
418
420
419 PermissionModel().update_user_group_permissions(form_result)
421 PermissionModel().update_user_group_permissions(form_result)
420
422
421 Session().commit()
423 Session().commit()
422 h.flash(_('User Group global permissions updated successfully'),
424 h.flash(_('User Group global permissions updated successfully'),
423 category='success')
425 category='success')
424
426
425 except formencode.Invalid as errors:
427 except formencode.Invalid as errors:
426 defaults = errors.value
428 defaults = errors.value
427 c.user_group = user_group
429 c.user_group = user_group
428 return htmlfill.render(
430 return htmlfill.render(
429 render('admin/user_groups/user_group_edit.html'),
431 render('admin/user_groups/user_group_edit.html'),
430 defaults=defaults,
432 defaults=defaults,
431 errors=errors.error_dict or {},
433 errors=errors.error_dict or {},
432 prefix_error=False,
434 prefix_error=False,
433 encoding="UTF-8",
435 encoding="UTF-8",
434 force_defaults=False)
436 force_defaults=False)
435
437
436 except Exception:
438 except Exception:
437 log.exception("Exception during permissions saving")
439 log.exception("Exception during permissions saving")
438 h.flash(_('An error occurred during permissions saving'),
440 h.flash(_('An error occurred during permissions saving'),
439 category='error')
441 category='error')
440
442
441 return redirect(url('edit_user_group_global_perms', user_group_id=user_group_id))
443 return redirect(url('edit_user_group_global_perms', user_group_id=user_group_id))
442
444
443 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
445 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
444 def edit_advanced(self, user_group_id):
446 def edit_advanced(self, user_group_id):
445 user_group_id = safe_int(user_group_id)
447 user_group_id = safe_int(user_group_id)
446 c.user_group = UserGroup.get_or_404(user_group_id)
448 c.user_group = UserGroup.get_or_404(user_group_id)
447 c.active = 'advanced'
449 c.active = 'advanced'
448 c.group_members_obj = sorted(
450 c.group_members_obj = sorted(
449 (x.user for x in c.user_group.members),
451 (x.user for x in c.user_group.members),
450 key=lambda u: u.username.lower())
452 key=lambda u: u.username.lower())
451
453
452 c.group_to_repos = sorted(
454 c.group_to_repos = sorted(
453 (x.repository for x in c.user_group.users_group_repo_to_perm),
455 (x.repository for x in c.user_group.users_group_repo_to_perm),
454 key=lambda u: u.repo_name.lower())
456 key=lambda u: u.repo_name.lower())
455
457
456 c.group_to_repo_groups = sorted(
458 c.group_to_repo_groups = sorted(
457 (x.group for x in c.user_group.users_group_repo_group_to_perm),
459 (x.group for x in c.user_group.users_group_repo_group_to_perm),
458 key=lambda u: u.group_name.lower())
460 key=lambda u: u.group_name.lower())
459
461
460 return render('admin/user_groups/user_group_edit.html')
462 return render('admin/user_groups/user_group_edit.html')
461
463
462 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
464 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
463 def edit_members(self, user_group_id):
465 def edit_members(self, user_group_id):
464 user_group_id = safe_int(user_group_id)
466 user_group_id = safe_int(user_group_id)
465 c.user_group = UserGroup.get_or_404(user_group_id)
467 c.user_group = UserGroup.get_or_404(user_group_id)
466 c.active = 'members'
468 c.active = 'members'
467 c.group_members_obj = sorted((x.user for x in c.user_group.members),
469 c.group_members_obj = sorted((x.user for x in c.user_group.members),
468 key=lambda u: u.username.lower())
470 key=lambda u: u.username.lower())
469
471
470 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
472 group_members = [(x.user_id, x.username) for x in c.group_members_obj]
473
474 if request.is_xhr:
475 return jsonify(lambda *a, **k: {
476 'members': group_members
477 })
478
479 c.group_members = group_members
471 return render('admin/user_groups/user_group_edit.html')
480 return render('admin/user_groups/user_group_edit.html')
@@ -1,45 +1,46 b''
1 /* This file is automatically generated. DO NOT change it manually.
1 /* This file is automatically generated. DO NOT change it manually.
2 * If this file needs to be modified, edit
2 * If this file needs to be modified, edit
3 * rhodecode/utils/file_generation/js_routes_data.py
3 * rhodecode/utils/file_generation/js_routes_data.py
4 * and run the script invoke -r scripts/ generate.js-routes .
4 * and run the script invoke -r scripts/ generate.js-routes .
5 */
5 */
6 function registerRCRoutes() {
6 function registerRCRoutes() {
7 // routes registration
7 // routes registration
8 pyroutes.register('home', '/', []);
8 pyroutes.register('home', '/', []);
9 pyroutes.register('new_gist', '/_admin/gists/new', []);
9 pyroutes.register('new_gist', '/_admin/gists/new', []);
10 pyroutes.register('gists', '/_admin/gists', []);
10 pyroutes.register('gists', '/_admin/gists', []);
11 pyroutes.register('new_repo', '/_admin/create_repository', []);
11 pyroutes.register('new_repo', '/_admin/create_repository', []);
12 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
12 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
13 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
13 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
14 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
14 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
15 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
15 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
16 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
16 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
17 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
17 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
18 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
18 pyroutes.register('user_autocomplete_data', '/_users', []);
19 pyroutes.register('user_autocomplete_data', '/_users', []);
19 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
20 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
20 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
21 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
21 pyroutes.register('changeset_info', '/changeset_info/%(repo_name)s/%(revision)s', ['repo_name', 'revision']);
22 pyroutes.register('changeset_info', '/changeset_info/%(repo_name)s/%(revision)s', ['repo_name', 'revision']);
22 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
23 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
23 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
24 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
24 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
25 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
25 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
26 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
26 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
27 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
27 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
28 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
28 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
29 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
29 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
30 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
30 pyroutes.register('files_metadata_list_home', '/%(repo_name)s/metadata_list/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
31 pyroutes.register('files_metadata_list_home', '/%(repo_name)s/metadata_list/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
31 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
32 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
32 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
33 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
33 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
34 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
34 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
35 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
35 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
36 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
36 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
37 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
37 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
38 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
38 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
39 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
39 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
40 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
40 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
41 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
41 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
42 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
42 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
43 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
43 }
44 }
44
45
45 registerRCRoutes(); No newline at end of file
46 registerRCRoutes();
@@ -1,91 +1,131 b''
1 <div class="panel panel-default">
1 <div class="panel panel-default">
2 <div class="panel-heading">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3>
3 <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3>
4 </div>
4 </div>
5 <div class="panel-body">
5 <div class="panel-body">
6 ${h.secure_form(url('update_users_group', user_group_id=c.user_group.users_group_id),method='put', id='edit_users_group')}
6 ${h.secure_form(url('update_users_group', user_group_id=c.user_group.users_group_id),method='put', id='edit_users_group')}
7 <div class="form">
7 <div class="form">
8 <!-- fields -->
8 <!-- fields -->
9 <div class="fields">
9 <div class="fields">
10 <div class="field">
10 <div class="field">
11 <div class="label">
11 <div class="label">
12 <label for="users_group_name">${_('Group name')}:</label>
12 <label for="users_group_name">${_('Group name')}:</label>
13 </div>
13 </div>
14 <div class="input">
14 <div class="input">
15 ${h.text('users_group_name',class_='medium')}
15 ${h.text('users_group_name',class_='medium')}
16 </div>
16 </div>
17 </div>
17 </div>
18 <div class="field">
18 <div class="field">
19 <div class="label">
19 <div class="label">
20 <label for="user">${_('Owner')}:</label>
20 <label for="user">${_('Owner')}:</label>
21 </div>
21 </div>
22 <div class="input">
22 <div class="input">
23 ${h.text('user', class_="medium", autocomplete="off")}
23 ${h.text('user', class_="medium", autocomplete="off")}
24 <span class="help-block">${_('Change owner of this user group.')}</span>
24 <span class="help-block">${_('Change owner of this user group.')}</span>
25 </div>
25 </div>
26 </div>
26 </div>
27 <div class="field">
27 <div class="field">
28 <div class="label label-textarea">
28 <div class="label label-textarea">
29 <label for="user_group_description">${_('Description')}:</label>
29 <label for="user_group_description">${_('Description')}:</label>
30 </div>
30 </div>
31 <div class="textarea textarea-small editor">
31 <div class="textarea textarea-small editor">
32 ${h.textarea('user_group_description',cols=23,rows=5,class_="medium")}
32 ${h.textarea('user_group_description',cols=23,rows=5,class_="medium")}
33 <span class="help-block">${_('Short, optional description for this user group.')}</span>
33 <span class="help-block">${_('Short, optional description for this user group.')}</span>
34 </div>
34 </div>
35 </div>
35 </div>
36 <div class="field">
36 <div class="field">
37 <div class="label label-checkbox">
37 <div class="label label-checkbox">
38 <label for="users_group_active">${_('Active')}:</label>
38 <label for="users_group_active">${_('Active')}:</label>
39 </div>
39 </div>
40 <div class="checkboxes">
40 <div class="checkboxes">
41 ${h.checkbox('users_group_active',value=True)}
41 ${h.checkbox('users_group_active',value=True)}
42 </div>
42 </div>
43 </div>
43 </div>
44 <div class="field">
44 <div class="field">
45 <div class="label">
45 <div class="label">
46 <label for="users_group_active">${_('Members')}:</label>
46 <label for="users_group_active">${_('Members')}:</label>
47 ${h.text('from_user_group',
48 placeholder="select only users",
49 class_="medium")}
47 </div>
50 </div>
48 <div class="select side-by-side-selector">
51 <div class="select side-by-side-selector">
49 <div class="left-group">
52 <div class="left-group">
50 <label class="text" >${_('Chosen group members')}</label>
53 <label class="text" >${_('Chosen group members')}</label>
51 ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,)}
54 ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,)}
52 <div class="btn" id="remove_all_elements" >
55 <div class="btn" id="remove_all_elements" >
53 ${_('Remove all elements')}
56 ${_('Remove all elements')}
54 <i class="icon-chevron-right"></i>
57 <i class="icon-chevron-right"></i>
55 </div>
58 </div>
56 </div>
59 </div>
57 <div class="middle-group">
60 <div class="middle-group">
58 <i id="add_element" class="icon-chevron-left"></i>
61 <i id="add_element" class="icon-chevron-left"></i>
59 <br />
62 <br />
60 <i id="remove_element" class="icon-chevron-right"></i>
63 <i id="remove_element" class="icon-chevron-right"></i>
61 </div>
64 </div>
62 <div class="right-group">
65 <div class="right-group">
63 <label class="text" >${_('Available members')}</label>
66 <label class="text" >${_('Available members')}
67 </label>
64 ${h.select('available_members',[],c.available_members,multiple=True,size=8,)}
68 ${h.select('available_members',[],c.available_members,multiple=True,size=8,)}
65 <div class="btn" id="add_all_elements" >
69 <div class="btn" id="add_all_elements" >
66 <i class="icon-chevron-left"></i>${_('Add all elements')}
70 <i class="icon-chevron-left"></i>${_('Add all elements')}
67 </div>
71 </div>
68 </div>
72 </div>
69 </div>
73 </div>
70 </div>
74 </div>
71 <div class="buttons">
75 <div class="buttons">
72 ${h.submit('Save',_('Save'),class_="btn")}
76 ${h.submit('Save',_('Save'),class_="btn")}
73 </div>
77 </div>
74 </div>
78 </div>
75 </div>
79 </div>
76 ${h.end_form()}
80 ${h.end_form()}
77 </div>
81 </div>
78 </div>
82 </div>
79 <script>
83 <script>
80 $(document).ready(function(){
84 $(document).ready(function(){
81 MultiSelectWidget('users_group_members','available_members','edit_users_group');
85 MultiSelectWidget('users_group_members','available_members','edit_users_group');
82
86
83 $("#group_parent_id").select2({
87 $("#group_parent_id").select2({
84 'containerCssClass': "drop-menu",
88 'containerCssClass': "drop-menu",
85 'dropdownCssClass': "drop-menu-dropdown",
89 'dropdownCssClass': "drop-menu-dropdown",
86 'dropdownAutoWidth': true
90 'dropdownAutoWidth': true
87 });
91 });
88
92
93 $('#from_user_group').autocomplete({
94 serviceUrl: pyroutes.url('user_autocomplete_data'),
95 minChars:2,
96 maxHeight:400,
97 width:300,
98 deferRequestBy: 300, //miliseconds
99 showNoSuggestionNotice: true,
100 params: { user_groups:true },
101 formatResult: autocompleteFormatResult,
102 lookupFilter: autocompleteFilterResult,
103 onSelect: function(element, suggestion){
104
105 function preSelectUserIds(uids) {
106 $('#available_members').val(uids);
107 $('#users_group_members').val(uids);
108 }
109
110 if (suggestion.value_type == 'user_group') {
111 $.getJSON(
112 pyroutes.url('edit_user_group_members',
113 {'user_group_id': suggestion.id}),
114 function(data) {
115 var uids = [];
116 $.each(data.members, function(idx, user) {
117 var userid = user[0],
118 username = user[1];
119 uids.push(userid.toString());
120 });
121 preSelectUserIds(uids)
122 }
123 );
124 } else if (suggestion.value_type == 'user') {
125 preSelectUserIds([suggestion.id.toString()]);
126 }
127 }
128 });
89 UsersAutoComplete('user', '${c.rhodecode_user.user_id}');
129 UsersAutoComplete('user', '${c.rhodecode_user.user_id}');
90 })
130 })
91 </script>
131 </script>
@@ -1,179 +1,186 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from rhodecode.tests import (
23 from rhodecode.tests import (
24 TestController, url, assert_session_flash, link_to)
24 TestController, url, assert_session_flash, link_to)
25 from rhodecode.model.db import User, UserGroup
25 from rhodecode.model.db import User, UserGroup
26 from rhodecode.model.meta import Session
26 from rhodecode.model.meta import Session
27 from rhodecode.tests.fixture import Fixture
27 from rhodecode.tests.fixture import Fixture
28
28
29 TEST_USER_GROUP = 'admins_test'
29 TEST_USER_GROUP = 'admins_test'
30
30
31 fixture = Fixture()
31 fixture = Fixture()
32
32
33
33
34 class TestAdminUsersGroupsController(TestController):
34 class TestAdminUsersGroupsController(TestController):
35
35
36 def test_index(self):
36 def test_index(self):
37 self.log_user()
37 self.log_user()
38 self.app.get(url('users_groups'))
38 response = self.app.get(url('users_groups'))
39 response.mustcontain('No members yet')
39
40
40 def test_create(self):
41 def test_create(self):
41 self.log_user()
42 self.log_user()
42 users_group_name = TEST_USER_GROUP
43 users_group_name = TEST_USER_GROUP
43 response = self.app.post(url('users_groups'), {
44 response = self.app.post(url('users_groups'), {
44 'users_group_name': users_group_name,
45 'users_group_name': users_group_name,
45 'user_group_description': 'DESC',
46 'user_group_description': 'DESC',
46 'active': True,
47 'active': True,
47 'csrf_token': self.csrf_token})
48 'csrf_token': self.csrf_token})
48
49
49 user_group_link = link_to(
50 user_group_link = link_to(
50 users_group_name,
51 users_group_name,
51 url('edit_users_group',
52 url('edit_users_group',
52 user_group_id=UserGroup.get_by_group_name(
53 user_group_id=UserGroup.get_by_group_name(
53 users_group_name).users_group_id))
54 users_group_name).users_group_id))
54 assert_session_flash(
55 assert_session_flash(
55 response,
56 response,
56 'Created user group %s' % user_group_link)
57 'Created user group %s' % user_group_link)
57
58
58 def test_delete(self):
59 def test_delete(self):
59 self.log_user()
60 self.log_user()
60 users_group_name = TEST_USER_GROUP + 'another'
61 users_group_name = TEST_USER_GROUP + 'another'
61 response = self.app.post(url('users_groups'), {
62 response = self.app.post(url('users_groups'), {
62 'users_group_name': users_group_name,
63 'users_group_name': users_group_name,
63 'user_group_description': 'DESC',
64 'user_group_description': 'DESC',
64 'active': True,
65 'active': True,
65 'csrf_token': self.csrf_token})
66 'csrf_token': self.csrf_token})
66
67
67 user_group_link = link_to(
68 user_group_link = link_to(
68 users_group_name,
69 users_group_name,
69 url('edit_users_group',
70 url('edit_users_group',
70 user_group_id=UserGroup.get_by_group_name(
71 user_group_id=UserGroup.get_by_group_name(
71 users_group_name).users_group_id))
72 users_group_name).users_group_id))
72 assert_session_flash(
73 assert_session_flash(
73 response,
74 response,
74 'Created user group %s' % user_group_link)
75 'Created user group %s' % user_group_link)
75
76
76 group = Session().query(UserGroup).filter(
77 group = Session().query(UserGroup).filter(
77 UserGroup.users_group_name == users_group_name).one()
78 UserGroup.users_group_name == users_group_name).one()
78
79
79 response = self.app.post(
80 response = self.app.post(
80 url('delete_users_group', user_group_id=group.users_group_id),
81 url('delete_users_group', user_group_id=group.users_group_id),
81 params={'_method': 'delete', 'csrf_token': self.csrf_token})
82 params={'_method': 'delete', 'csrf_token': self.csrf_token})
82
83
83 group = Session().query(UserGroup).filter(
84 group = Session().query(UserGroup).filter(
84 UserGroup.users_group_name == users_group_name).scalar()
85 UserGroup.users_group_name == users_group_name).scalar()
85
86
86 assert group is None
87 assert group is None
87
88
88 @pytest.mark.parametrize('repo_create, repo_create_write, user_group_create, repo_group_create, fork_create, inherit_default_permissions, expect_error, expect_form_error', [
89 @pytest.mark.parametrize('repo_create, repo_create_write, user_group_create, repo_group_create, fork_create, inherit_default_permissions, expect_error, expect_form_error', [
89 ('hg.create.none', 'hg.create.write_on_repogroup.false', 'hg.usergroup.create.false', 'hg.repogroup.create.false', 'hg.fork.none', 'hg.inherit_default_perms.false', False, False),
90 ('hg.create.none', 'hg.create.write_on_repogroup.false', 'hg.usergroup.create.false', 'hg.repogroup.create.false', 'hg.fork.none', 'hg.inherit_default_perms.false', False, False),
90 ('hg.create.repository', 'hg.create.write_on_repogroup.true', 'hg.usergroup.create.true', 'hg.repogroup.create.true', 'hg.fork.repository', 'hg.inherit_default_perms.false', False, False),
91 ('hg.create.repository', 'hg.create.write_on_repogroup.true', 'hg.usergroup.create.true', 'hg.repogroup.create.true', 'hg.fork.repository', 'hg.inherit_default_perms.false', False, False),
91 ('hg.create.XXX', 'hg.create.write_on_repogroup.true', 'hg.usergroup.create.true', 'hg.repogroup.create.true', 'hg.fork.repository', 'hg.inherit_default_perms.false', False, True),
92 ('hg.create.XXX', 'hg.create.write_on_repogroup.true', 'hg.usergroup.create.true', 'hg.repogroup.create.true', 'hg.fork.repository', 'hg.inherit_default_perms.false', False, True),
92 ('', '', '', '', '', '', True, False),
93 ('', '', '', '', '', '', True, False),
93 ])
94 ])
94 def test_global_perms_on_group(
95 def test_global_perms_on_group(
95 self, repo_create, repo_create_write, user_group_create,
96 self, repo_create, repo_create_write, user_group_create,
96 repo_group_create, fork_create, expect_error, expect_form_error,
97 repo_group_create, fork_create, expect_error, expect_form_error,
97 inherit_default_permissions):
98 inherit_default_permissions):
98 self.log_user()
99 self.log_user()
99 users_group_name = TEST_USER_GROUP + 'another2'
100 users_group_name = TEST_USER_GROUP + 'another2'
100 response = self.app.post(url('users_groups'),
101 response = self.app.post(url('users_groups'),
101 {'users_group_name': users_group_name,
102 {'users_group_name': users_group_name,
102 'user_group_description': 'DESC',
103 'user_group_description': 'DESC',
103 'active': True,
104 'active': True,
104 'csrf_token': self.csrf_token})
105 'csrf_token': self.csrf_token})
105
106
106 ug = UserGroup.get_by_group_name(users_group_name)
107 ug = UserGroup.get_by_group_name(users_group_name)
107 user_group_link = link_to(
108 user_group_link = link_to(
108 users_group_name,
109 users_group_name,
109 url('edit_users_group', user_group_id=ug.users_group_id))
110 url('edit_users_group', user_group_id=ug.users_group_id))
110 assert_session_flash(
111 assert_session_flash(
111 response,
112 response,
112 'Created user group %s' % user_group_link)
113 'Created user group %s' % user_group_link)
113 response.follow()
114 response.follow()
114
115
115 # ENABLE REPO CREATE ON A GROUP
116 # ENABLE REPO CREATE ON A GROUP
116 perm_params = {
117 perm_params = {
117 'inherit_default_permissions': False,
118 'inherit_default_permissions': False,
118 'default_repo_create': repo_create,
119 'default_repo_create': repo_create,
119 'default_repo_create_on_write': repo_create_write,
120 'default_repo_create_on_write': repo_create_write,
120 'default_user_group_create': user_group_create,
121 'default_user_group_create': user_group_create,
121 'default_repo_group_create': repo_group_create,
122 'default_repo_group_create': repo_group_create,
122 'default_fork_create': fork_create,
123 'default_fork_create': fork_create,
123 'default_inherit_default_permissions': inherit_default_permissions,
124 'default_inherit_default_permissions': inherit_default_permissions,
124
125
125 '_method': 'put',
126 '_method': 'put',
126 'csrf_token': self.csrf_token,
127 'csrf_token': self.csrf_token,
127 }
128 }
128 response = self.app.post(
129 response = self.app.post(
129 url('edit_user_group_global_perms',
130 url('edit_user_group_global_perms',
130 user_group_id=ug.users_group_id),
131 user_group_id=ug.users_group_id),
131 params=perm_params)
132 params=perm_params)
132
133
133 if expect_form_error:
134 if expect_form_error:
134 assert response.status_int == 200
135 assert response.status_int == 200
135 response.mustcontain('Value must be one of')
136 response.mustcontain('Value must be one of')
136 else:
137 else:
137 if expect_error:
138 if expect_error:
138 msg = 'An error occurred during permissions saving'
139 msg = 'An error occurred during permissions saving'
139 else:
140 else:
140 msg = 'User Group global permissions updated successfully'
141 msg = 'User Group global permissions updated successfully'
141 ug = UserGroup.get_by_group_name(users_group_name)
142 ug = UserGroup.get_by_group_name(users_group_name)
142 del perm_params['_method']
143 del perm_params['_method']
143 del perm_params['csrf_token']
144 del perm_params['csrf_token']
144 del perm_params['inherit_default_permissions']
145 del perm_params['inherit_default_permissions']
145 assert perm_params == ug.get_default_perms()
146 assert perm_params == ug.get_default_perms()
146 assert_session_flash(response, msg)
147 assert_session_flash(response, msg)
147
148
148 fixture.destroy_user_group(users_group_name)
149 fixture.destroy_user_group(users_group_name)
149
150
150 def test_edit(self):
151 def test_edit(self):
151 self.app.get(url('edit_users_group', user_group_id=1))
152 self.log_user()
153 response = self.app.get(url('edit_users_group', user_group_id=1))
154
155 def test_edit_user_group_members(self):
156 self.log_user()
157 response = self.app.get(url('edit_user_group_members', user_group_id=1))
158 response.mustcontain('No members yet')
152
159
153 def test_usergroup_escape(self):
160 def test_usergroup_escape(self):
154 user = User.get_by_username('test_admin')
161 user = User.get_by_username('test_admin')
155 user.name = '<img src="/image1" onload="alert(\'Hello, World!\');">'
162 user.name = '<img src="/image1" onload="alert(\'Hello, World!\');">'
156 user.lastname = (
163 user.lastname = (
157 '<img src="/image2" onload="alert(\'Hello, World!\');">')
164 '<img src="/image2" onload="alert(\'Hello, World!\');">')
158 Session().add(user)
165 Session().add(user)
159 Session().commit()
166 Session().commit()
160
167
161 self.log_user()
168 self.log_user()
162 users_group_name = 'samplegroup'
169 users_group_name = 'samplegroup'
163 data = {
170 data = {
164 'users_group_name': users_group_name,
171 'users_group_name': users_group_name,
165 'user_group_description': (
172 'user_group_description': (
166 '<strong onload="alert();">DESC</strong>'),
173 '<strong onload="alert();">DESC</strong>'),
167 'active': True,
174 'active': True,
168 'csrf_token': self.csrf_token
175 'csrf_token': self.csrf_token
169 }
176 }
170
177
171 response = self.app.post(url('users_groups'), data)
178 response = self.app.post(url('users_groups'), data)
172 response = self.app.get(url('users_groups'))
179 response = self.app.get(url('users_groups'))
173
180
174 response.mustcontain(
181 response.mustcontain(
175 '&lt;strong onload=&#34;alert();&#34;&gt;'
182 '&lt;strong onload=&#34;alert();&#34;&gt;'
176 'DESC&lt;/strong&gt;')
183 'DESC&lt;/strong&gt;')
177 response.mustcontain(
184 response.mustcontain(
178 '&lt;img src=&#34;/image2&#34; onload=&#34;'
185 '&lt;img src=&#34;/image2&#34; onload=&#34;'
179 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
186 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
General Comments 0
You need to be logged in to leave comments. Login now