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