##// END OF EJS Templates
api: enable setting sync flag for user groups on create/edit.
marcink -
r2660:499461c1 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,110 +1,125 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2018 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 mock
22 22 import pytest
23 23
24 24 from rhodecode.model.user import UserModel
25 25 from rhodecode.model.user_group import UserGroupModel
26 26 from rhodecode.tests import TEST_USER_ADMIN_EMAIL
27 27 from rhodecode.api.tests.utils import (
28 28 build_data, api_call, assert_error, assert_ok, crash, jsonify)
29 29
30 30
31 31 @pytest.mark.usefixtures("testuser_api", "app")
32 32 class TestUpdateUserGroup(object):
33 33 @pytest.mark.parametrize("changing_attr, updates", [
34 34 ('group_name', {'group_name': 'new_group_name'}),
35 35 ('group_name', {'group_name': 'test_group_for_update'}),
36 36 # ('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
37 37 ('owner_email', {'owner_email': TEST_USER_ADMIN_EMAIL}),
38 38 ('active', {'active': False}),
39 ('active', {'active': True})
39 ('active', {'active': True}),
40 ('sync', {'sync': False}),
41 ('sync', {'sync': True})
40 42 ])
41 43 def test_api_update_user_group(self, changing_attr, updates, user_util):
42 44 user_group = user_util.create_user_group()
43 45 group_name = user_group.users_group_name
44 46 expected_api_data = user_group.get_api_data()
45 47 expected_api_data.update(updates)
46 48
47 49 id_, params = build_data(
48 50 self.apikey, 'update_user_group', usergroupid=group_name,
49 51 **updates)
50 52 response = api_call(self.app, params)
51 53
54 # special case for sync
55 if changing_attr == 'sync' and updates['sync'] is False:
56 expected_api_data['sync'] = None
57 elif changing_attr == 'sync' and updates['sync'] is True:
58 expected_api_data['sync'] = 'manual_api'
59
52 60 expected = {
53 61 'msg': 'updated user group ID:%s %s' % (
54 62 user_group.users_group_id, user_group.users_group_name),
55 63 'user_group': jsonify(expected_api_data)
56 64 }
57 65 assert_ok(id_, expected, given=response.body)
58 66
59 67 @pytest.mark.parametrize("changing_attr, updates", [
60 68 # TODO: mikhail: decide if we need to test against the commented params
61 69 # ('group_name', {'group_name': 'new_group_name'}),
62 70 # ('group_name', {'group_name': 'test_group_for_update'}),
63 71 # ('owner', {'owner': TEST_USER_REGULAR_LOGIN}),
64 72 ('owner_email', {'owner_email': TEST_USER_ADMIN_EMAIL}),
65 73 ('active', {'active': False}),
66 ('active', {'active': True})
74 ('active', {'active': True}),
75 ('sync', {'sync': False}),
76 ('sync', {'sync': True})
67 77 ])
68 78 def test_api_update_user_group_regular_user(
69 79 self, changing_attr, updates, user_util):
70 80 user_group = user_util.create_user_group()
71 81 group_name = user_group.users_group_name
72 82 expected_api_data = user_group.get_api_data()
73 83 expected_api_data.update(updates)
74 84
75
76 85 # grant permission to this user
77 86 user = UserModel().get_by_username(self.TEST_USER_LOGIN)
78 87
79 88 user_util.grant_user_permission_to_user_group(
80 89 user_group, user, 'usergroup.admin')
81 90 id_, params = build_data(
82 91 self.apikey_regular, 'update_user_group',
83 92 usergroupid=group_name, **updates)
84 93 response = api_call(self.app, params)
94 # special case for sync
95 if changing_attr == 'sync' and updates['sync'] is False:
96 expected_api_data['sync'] = None
97 elif changing_attr == 'sync' and updates['sync'] is True:
98 expected_api_data['sync'] = 'manual_api'
99
85 100 expected = {
86 101 'msg': 'updated user group ID:%s %s' % (
87 102 user_group.users_group_id, user_group.users_group_name),
88 103 'user_group': jsonify(expected_api_data)
89 104 }
90 105 assert_ok(id_, expected, given=response.body)
91 106
92 107 def test_api_update_user_group_regular_user_no_permission(self, user_util):
93 108 user_group = user_util.create_user_group()
94 109 group_name = user_group.users_group_name
95 110 id_, params = build_data(
96 111 self.apikey_regular, 'update_user_group', usergroupid=group_name)
97 112 response = api_call(self.app, params)
98 113
99 114 expected = 'user group `%s` does not exist' % (group_name)
100 115 assert_error(id_, expected, given=response.body)
101 116
102 117 @mock.patch.object(UserGroupModel, 'update', crash)
103 118 def test_api_update_user_group_exception_occurred(self, user_util):
104 119 user_group = user_util.create_user_group()
105 120 group_name = user_group.users_group_name
106 121 id_, params = build_data(
107 122 self.apikey, 'update_user_group', usergroupid=group_name)
108 123 response = api_call(self.app, params)
109 124 expected = 'failed to update user group `%s`' % (group_name,)
110 125 assert_error(id_, expected, given=response.body)
@@ -1,829 +1,858 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2018 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 logging
22 22
23 23 from rhodecode.api import (
24 24 jsonrpc_method, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
25 25 from rhodecode.api.utils import (
26 26 Optional, OAttr, store_update, has_superadmin_permission, get_origin,
27 27 get_user_or_error, get_user_group_or_error, get_perm_or_error)
28 28 from rhodecode.lib import audit_logger
29 29 from rhodecode.lib.auth import HasUserGroupPermissionAnyApi, HasPermissionAnyApi
30 30 from rhodecode.lib.exceptions import UserGroupAssignedException
31 31 from rhodecode.model.db import Session
32 32 from rhodecode.model.scm import UserGroupList
33 33 from rhodecode.model.user_group import UserGroupModel
34 34 from rhodecode.model import validation_schema
35 35 from rhodecode.model.validation_schema.schemas import user_group_schema
36 36
37 37 log = logging.getLogger(__name__)
38 38
39 39
40 40 @jsonrpc_method()
41 41 def get_user_group(request, apiuser, usergroupid):
42 42 """
43 43 Returns the data of an existing user group.
44 44
45 45 This command can only be run using an |authtoken| with admin rights to
46 46 the specified repository.
47 47
48 48 :param apiuser: This is filled automatically from the |authtoken|.
49 49 :type apiuser: AuthUser
50 50 :param usergroupid: Set the user group from which to return data.
51 51 :type usergroupid: str or int
52 52
53 53 Example error output:
54 54
55 55 .. code-block:: bash
56 56
57 57 {
58 58 "error": null,
59 59 "id": <id>,
60 60 "result": {
61 61 "active": true,
62 62 "group_description": "group description",
63 63 "group_name": "group name",
64 64 "permissions": [
65 65 {
66 66 "name": "owner-name",
67 67 "origin": "owner",
68 68 "permission": "usergroup.admin",
69 69 "type": "user"
70 70 },
71 71 {
72 72 {
73 73 "name": "user name",
74 74 "origin": "permission",
75 75 "permission": "usergroup.admin",
76 76 "type": "user"
77 77 },
78 78 {
79 79 "name": "user group name",
80 80 "origin": "permission",
81 81 "permission": "usergroup.write",
82 82 "type": "user_group"
83 83 }
84 84 ],
85 85 "permissions_summary": {
86 86 "repositories": {
87 87 "aa-root-level-repo-1": "repository.admin"
88 88 },
89 89 "repositories_groups": {}
90 90 },
91 91 "owner": "owner name",
92 92 "users": [],
93 93 "users_group_id": 2
94 94 }
95 95 }
96 96
97 97 """
98 98
99 99 user_group = get_user_group_or_error(usergroupid)
100 100 if not has_superadmin_permission(apiuser):
101 101 # check if we have at least read permission for this user group !
102 102 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
103 103 if not HasUserGroupPermissionAnyApi(*_perms)(
104 104 user=apiuser, user_group_name=user_group.users_group_name):
105 105 raise JSONRPCError('user group `%s` does not exist' % (
106 106 usergroupid,))
107 107
108 108 permissions = []
109 109 for _user in user_group.permissions():
110 110 user_data = {
111 111 'name': _user.username,
112 112 'permission': _user.permission,
113 113 'origin': get_origin(_user),
114 114 'type': "user",
115 115 }
116 116 permissions.append(user_data)
117 117
118 118 for _user_group in user_group.permission_user_groups():
119 119 user_group_data = {
120 120 'name': _user_group.users_group_name,
121 121 'permission': _user_group.permission,
122 122 'origin': get_origin(_user_group),
123 123 'type': "user_group",
124 124 }
125 125 permissions.append(user_group_data)
126 126
127 127 data = user_group.get_api_data()
128 128 data["permissions"] = permissions
129 129 data["permissions_summary"] = UserGroupModel().get_perms_summary(
130 130 user_group.users_group_id)
131 131 return data
132 132
133 133
134 134 @jsonrpc_method()
135 135 def get_user_groups(request, apiuser):
136 136 """
137 137 Lists all the existing user groups within RhodeCode.
138 138
139 139 This command can only be run using an |authtoken| with admin rights to
140 140 the specified repository.
141 141
142 142 This command takes the following options:
143 143
144 144 :param apiuser: This is filled automatically from the |authtoken|.
145 145 :type apiuser: AuthUser
146 146
147 147 Example error output:
148 148
149 149 .. code-block:: bash
150 150
151 151 id : <id_given_in_input>
152 152 result : [<user_group_obj>,...]
153 153 error : null
154 154 """
155 155
156 156 include_secrets = has_superadmin_permission(apiuser)
157 157
158 158 result = []
159 159 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
160 160 extras = {'user': apiuser}
161 161 for user_group in UserGroupList(UserGroupModel().get_all(),
162 162 perm_set=_perms, extra_kwargs=extras):
163 163 result.append(
164 164 user_group.get_api_data(include_secrets=include_secrets))
165 165 return result
166 166
167 167
168 168 @jsonrpc_method()
169 169 def create_user_group(
170 170 request, apiuser, group_name, description=Optional(''),
171 owner=Optional(OAttr('apiuser')), active=Optional(True)):
171 owner=Optional(OAttr('apiuser')), active=Optional(True),
172 sync=Optional(None)):
172 173 """
173 174 Creates a new user group.
174 175
175 176 This command can only be run using an |authtoken| with admin rights to
176 177 the specified repository.
177 178
178 179 This command takes the following options:
179 180
180 181 :param apiuser: This is filled automatically from the |authtoken|.
181 182 :type apiuser: AuthUser
182 183 :param group_name: Set the name of the new user group.
183 184 :type group_name: str
184 185 :param description: Give a description of the new user group.
185 186 :type description: str
186 187 :param owner: Set the owner of the new user group.
187 188 If not set, the owner is the |authtoken| user.
188 189 :type owner: Optional(str or int)
189 190 :param active: Set this group as active.
190 191 :type active: Optional(``True`` | ``False``)
192 :param sync: Set enabled or disabled the automatically sync from
193 external authentication types like ldap.
194 :type sync: Optional(``True`` | ``False``)
191 195
192 196 Example output:
193 197
194 198 .. code-block:: bash
195 199
196 200 id : <id_given_in_input>
197 201 result: {
198 202 "msg": "created new user group `<groupname>`",
199 203 "user_group": <user_group_object>
200 204 }
201 205 error: null
202 206
203 207 Example error output:
204 208
205 209 .. code-block:: bash
206 210
207 211 id : <id_given_in_input>
208 212 result : null
209 213 error : {
210 214 "user group `<group name>` already exist"
211 215 or
212 216 "failed to create group `<group name>`"
213 217 }
214 218
215 219 """
216 220
217 221 if not has_superadmin_permission(apiuser):
218 222 if not HasPermissionAnyApi('hg.usergroup.create.true')(user=apiuser):
219 223 raise JSONRPCForbidden()
220 224
221 225 if UserGroupModel().get_by_name(group_name):
222 226 raise JSONRPCError("user group `%s` already exist" % (group_name,))
223 227
224 228 if isinstance(owner, Optional):
225 229 owner = apiuser.user_id
226 230
227 231 owner = get_user_or_error(owner)
228 232 active = Optional.extract(active)
229 233 description = Optional.extract(description)
234 sync = Optional.extract(sync)
235
236 # set the sync option based on group_data
237 group_data = None
238 if sync:
239 group_data = {
240 'extern_type': 'manual_api',
241 'extern_type_set_by': apiuser.username
242 }
230 243
231 244 schema = user_group_schema.UserGroupSchema().bind(
232 245 # user caller
233 246 user=apiuser)
234 247 try:
235 248 schema_data = schema.deserialize(dict(
236 249 user_group_name=group_name,
237 250 user_group_description=description,
238 251 user_group_owner=owner.username,
239 252 user_group_active=active,
240 253 ))
241 254 except validation_schema.Invalid as err:
242 255 raise JSONRPCValidationError(colander_exc=err)
243 256
244 257 try:
245 258 user_group = UserGroupModel().create(
246 259 name=schema_data['user_group_name'],
247 260 description=schema_data['user_group_description'],
248 261 owner=owner,
249 active=schema_data['user_group_active'])
262 active=schema_data['user_group_active'], group_data=group_data)
250 263 Session().flush()
251 264 creation_data = user_group.get_api_data()
252 265 audit_logger.store_api(
253 266 'user_group.create', action_data={'data': creation_data},
254 267 user=apiuser)
255 268 Session().commit()
256 269 return {
257 270 'msg': 'created new user group `%s`' % group_name,
258 271 'user_group': creation_data
259 272 }
260 273 except Exception:
261 274 log.exception("Error occurred during creation of user group")
262 275 raise JSONRPCError('failed to create group `%s`' % (group_name,))
263 276
264 277
265 278 @jsonrpc_method()
266 279 def update_user_group(request, apiuser, usergroupid, group_name=Optional(''),
267 280 description=Optional(''), owner=Optional(None),
268 active=Optional(True)):
281 active=Optional(True), sync=Optional(None)):
269 282 """
270 283 Updates the specified `user group` with the details provided.
271 284
272 285 This command can only be run using an |authtoken| with admin rights to
273 286 the specified repository.
274 287
275 288 :param apiuser: This is filled automatically from the |authtoken|.
276 289 :type apiuser: AuthUser
277 290 :param usergroupid: Set the id of the `user group` to update.
278 291 :type usergroupid: str or int
279 292 :param group_name: Set the new name the `user group`
280 293 :type group_name: str
281 294 :param description: Give a description for the `user group`
282 295 :type description: str
283 296 :param owner: Set the owner of the `user group`.
284 297 :type owner: Optional(str or int)
285 298 :param active: Set the group as active.
286 299 :type active: Optional(``True`` | ``False``)
300 :param sync: Set enabled or disabled the automatically sync from
301 external authentication types like ldap.
302 :type sync: Optional(``True`` | ``False``)
287 303
288 304 Example output:
289 305
290 306 .. code-block:: bash
291 307
292 308 id : <id_given_in_input>
293 309 result : {
294 310 "msg": 'updated user group ID:<user group id> <user group name>',
295 311 "user_group": <user_group_object>
296 312 }
297 313 error : null
298 314
299 315 Example error output:
300 316
301 317 .. code-block:: bash
302 318
303 319 id : <id_given_in_input>
304 320 result : null
305 321 error : {
306 322 "failed to update user group `<user group name>`"
307 323 }
308 324
309 325 """
310 326
311 327 user_group = get_user_group_or_error(usergroupid)
312 328 include_secrets = False
313 329 if not has_superadmin_permission(apiuser):
314 330 # check if we have admin permission for this user group !
315 331 _perms = ('usergroup.admin',)
316 332 if not HasUserGroupPermissionAnyApi(*_perms)(
317 333 user=apiuser, user_group_name=user_group.users_group_name):
318 334 raise JSONRPCError(
319 335 'user group `%s` does not exist' % (usergroupid,))
320 336 else:
321 337 include_secrets = True
322 338
323 339 if not isinstance(owner, Optional):
324 340 owner = get_user_or_error(owner)
325 341
326 342 old_data = user_group.get_api_data()
327 343 updates = {}
328 344 store_update(updates, group_name, 'users_group_name')
329 345 store_update(updates, description, 'user_group_description')
330 346 store_update(updates, owner, 'user')
331 347 store_update(updates, active, 'users_group_active')
348
349 sync = Optional.extract(sync)
350 group_data = None
351 if sync is True:
352 group_data = {
353 'extern_type': 'manual_api',
354 'extern_type_set_by': apiuser.username
355 }
356 if sync is False:
357 group_data = user_group.group_data
358 if group_data and "extern_type" in group_data:
359 del group_data["extern_type"]
360
332 361 try:
333 UserGroupModel().update(user_group, updates)
362 UserGroupModel().update(user_group, updates, group_data=group_data)
334 363 audit_logger.store_api(
335 364 'user_group.edit', action_data={'old_data': old_data},
336 365 user=apiuser)
337 366 Session().commit()
338 367 return {
339 368 'msg': 'updated user group ID:%s %s' % (
340 369 user_group.users_group_id, user_group.users_group_name),
341 370 'user_group': user_group.get_api_data(
342 371 include_secrets=include_secrets)
343 372 }
344 373 except Exception:
345 374 log.exception("Error occurred during update of user group")
346 375 raise JSONRPCError(
347 376 'failed to update user group `%s`' % (usergroupid,))
348 377
349 378
350 379 @jsonrpc_method()
351 380 def delete_user_group(request, apiuser, usergroupid):
352 381 """
353 382 Deletes the specified `user group`.
354 383
355 384 This command can only be run using an |authtoken| with admin rights to
356 385 the specified repository.
357 386
358 387 This command takes the following options:
359 388
360 389 :param apiuser: filled automatically from apikey
361 390 :type apiuser: AuthUser
362 391 :param usergroupid:
363 392 :type usergroupid: int
364 393
365 394 Example output:
366 395
367 396 .. code-block:: bash
368 397
369 398 id : <id_given_in_input>
370 399 result : {
371 400 "msg": "deleted user group ID:<user_group_id> <user_group_name>"
372 401 }
373 402 error : null
374 403
375 404 Example error output:
376 405
377 406 .. code-block:: bash
378 407
379 408 id : <id_given_in_input>
380 409 result : null
381 410 error : {
382 411 "failed to delete user group ID:<user_group_id> <user_group_name>"
383 412 or
384 413 "RepoGroup assigned to <repo_groups_list>"
385 414 }
386 415
387 416 """
388 417
389 418 user_group = get_user_group_or_error(usergroupid)
390 419 if not has_superadmin_permission(apiuser):
391 420 # check if we have admin permission for this user group !
392 421 _perms = ('usergroup.admin',)
393 422 if not HasUserGroupPermissionAnyApi(*_perms)(
394 423 user=apiuser, user_group_name=user_group.users_group_name):
395 424 raise JSONRPCError(
396 425 'user group `%s` does not exist' % (usergroupid,))
397 426
398 427 old_data = user_group.get_api_data()
399 428 try:
400 429 UserGroupModel().delete(user_group)
401 430 audit_logger.store_api(
402 431 'user_group.delete', action_data={'old_data': old_data},
403 432 user=apiuser)
404 433 Session().commit()
405 434 return {
406 435 'msg': 'deleted user group ID:%s %s' % (
407 436 user_group.users_group_id, user_group.users_group_name),
408 437 'user_group': None
409 438 }
410 439 except UserGroupAssignedException as e:
411 440 log.exception("UserGroupAssigned error")
412 441 raise JSONRPCError(str(e))
413 442 except Exception:
414 443 log.exception("Error occurred during deletion of user group")
415 444 raise JSONRPCError(
416 445 'failed to delete user group ID:%s %s' %(
417 446 user_group.users_group_id, user_group.users_group_name))
418 447
419 448
420 449 @jsonrpc_method()
421 450 def add_user_to_user_group(request, apiuser, usergroupid, userid):
422 451 """
423 452 Adds a user to a `user group`. If the user already exists in the group
424 453 this command will return false.
425 454
426 455 This command can only be run using an |authtoken| with admin rights to
427 456 the specified user group.
428 457
429 458 This command takes the following options:
430 459
431 460 :param apiuser: This is filled automatically from the |authtoken|.
432 461 :type apiuser: AuthUser
433 462 :param usergroupid: Set the name of the `user group` to which a
434 463 user will be added.
435 464 :type usergroupid: int
436 465 :param userid: Set the `user_id` of the user to add to the group.
437 466 :type userid: int
438 467
439 468 Example output:
440 469
441 470 .. code-block:: bash
442 471
443 472 id : <id_given_in_input>
444 473 result : {
445 474 "success": True|False # depends on if member is in group
446 475 "msg": "added member `<username>` to user group `<groupname>` |
447 476 User is already in that group"
448 477
449 478 }
450 479 error : null
451 480
452 481 Example error output:
453 482
454 483 .. code-block:: bash
455 484
456 485 id : <id_given_in_input>
457 486 result : null
458 487 error : {
459 488 "failed to add member to user group `<user_group_name>`"
460 489 }
461 490
462 491 """
463 492
464 493 user = get_user_or_error(userid)
465 494 user_group = get_user_group_or_error(usergroupid)
466 495 if not has_superadmin_permission(apiuser):
467 496 # check if we have admin permission for this user group !
468 497 _perms = ('usergroup.admin',)
469 498 if not HasUserGroupPermissionAnyApi(*_perms)(
470 499 user=apiuser, user_group_name=user_group.users_group_name):
471 500 raise JSONRPCError('user group `%s` does not exist' % (
472 501 usergroupid,))
473 502
474 503 old_values = user_group.get_api_data()
475 504 try:
476 505 ugm = UserGroupModel().add_user_to_group(user_group, user)
477 506 success = True if ugm is not True else False
478 507 msg = 'added member `%s` to user group `%s`' % (
479 508 user.username, user_group.users_group_name
480 509 )
481 510 msg = msg if success else 'User is already in that group'
482 511 if success:
483 512 user_data = user.get_api_data()
484 513 audit_logger.store_api(
485 514 'user_group.edit.member.add',
486 515 action_data={'user': user_data, 'old_data': old_values},
487 516 user=apiuser)
488 517
489 518 Session().commit()
490 519
491 520 return {
492 521 'success': success,
493 522 'msg': msg
494 523 }
495 524 except Exception:
496 525 log.exception("Error occurred during adding a member to user group")
497 526 raise JSONRPCError(
498 527 'failed to add member to user group `%s`' % (
499 528 user_group.users_group_name,
500 529 )
501 530 )
502 531
503 532
504 533 @jsonrpc_method()
505 534 def remove_user_from_user_group(request, apiuser, usergroupid, userid):
506 535 """
507 536 Removes a user from a user group.
508 537
509 538 * If the specified user is not in the group, this command will return
510 539 `false`.
511 540
512 541 This command can only be run using an |authtoken| with admin rights to
513 542 the specified user group.
514 543
515 544 :param apiuser: This is filled automatically from the |authtoken|.
516 545 :type apiuser: AuthUser
517 546 :param usergroupid: Sets the user group name.
518 547 :type usergroupid: str or int
519 548 :param userid: The user you wish to remove from |RCE|.
520 549 :type userid: str or int
521 550
522 551 Example output:
523 552
524 553 .. code-block:: bash
525 554
526 555 id : <id_given_in_input>
527 556 result: {
528 557 "success": True|False, # depends on if member is in group
529 558 "msg": "removed member <username> from user group <groupname> |
530 559 User wasn't in group"
531 560 }
532 561 error: null
533 562
534 563 """
535 564
536 565 user = get_user_or_error(userid)
537 566 user_group = get_user_group_or_error(usergroupid)
538 567 if not has_superadmin_permission(apiuser):
539 568 # check if we have admin permission for this user group !
540 569 _perms = ('usergroup.admin',)
541 570 if not HasUserGroupPermissionAnyApi(*_perms)(
542 571 user=apiuser, user_group_name=user_group.users_group_name):
543 572 raise JSONRPCError(
544 573 'user group `%s` does not exist' % (usergroupid,))
545 574
546 575 old_values = user_group.get_api_data()
547 576 try:
548 577 success = UserGroupModel().remove_user_from_group(user_group, user)
549 578 msg = 'removed member `%s` from user group `%s`' % (
550 579 user.username, user_group.users_group_name
551 580 )
552 581 msg = msg if success else "User wasn't in group"
553 582 if success:
554 583 user_data = user.get_api_data()
555 584 audit_logger.store_api(
556 585 'user_group.edit.member.delete',
557 586 action_data={'user': user_data, 'old_data': old_values},
558 587 user=apiuser)
559 588
560 589 Session().commit()
561 590 return {'success': success, 'msg': msg}
562 591 except Exception:
563 592 log.exception("Error occurred during removing an member from user group")
564 593 raise JSONRPCError(
565 594 'failed to remove member from user group `%s`' % (
566 595 user_group.users_group_name,
567 596 )
568 597 )
569 598
570 599
571 600 @jsonrpc_method()
572 601 def grant_user_permission_to_user_group(
573 602 request, apiuser, usergroupid, userid, perm):
574 603 """
575 604 Set permissions for a user in a user group.
576 605
577 606 :param apiuser: This is filled automatically from the |authtoken|.
578 607 :type apiuser: AuthUser
579 608 :param usergroupid: Set the user group to edit permissions on.
580 609 :type usergroupid: str or int
581 610 :param userid: Set the user from whom you wish to set permissions.
582 611 :type userid: str
583 612 :param perm: (usergroup.(none|read|write|admin))
584 613 :type perm: str
585 614
586 615 Example output:
587 616
588 617 .. code-block:: bash
589 618
590 619 id : <id_given_in_input>
591 620 result : {
592 621 "msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
593 622 "success": true
594 623 }
595 624 error : null
596 625 """
597 626
598 627 user_group = get_user_group_or_error(usergroupid)
599 628
600 629 if not has_superadmin_permission(apiuser):
601 630 # check if we have admin permission for this user group !
602 631 _perms = ('usergroup.admin',)
603 632 if not HasUserGroupPermissionAnyApi(*_perms)(
604 633 user=apiuser, user_group_name=user_group.users_group_name):
605 634 raise JSONRPCError(
606 635 'user group `%s` does not exist' % (usergroupid,))
607 636
608 637 user = get_user_or_error(userid)
609 638 perm = get_perm_or_error(perm, prefix='usergroup.')
610 639
611 640 try:
612 641 UserGroupModel().grant_user_permission(
613 642 user_group=user_group, user=user, perm=perm)
614 643 Session().commit()
615 644 return {
616 645 'msg':
617 646 'Granted perm: `%s` for user: `%s` in user group: `%s`' % (
618 647 perm.permission_name, user.username,
619 648 user_group.users_group_name
620 649 ),
621 650 'success': True
622 651 }
623 652 except Exception:
624 653 log.exception("Error occurred during editing permissions "
625 654 "for user in user group")
626 655 raise JSONRPCError(
627 656 'failed to edit permission for user: '
628 657 '`%s` in user group: `%s`' % (
629 658 userid, user_group.users_group_name))
630 659
631 660
632 661 @jsonrpc_method()
633 662 def revoke_user_permission_from_user_group(
634 663 request, apiuser, usergroupid, userid):
635 664 """
636 665 Revoke a users permissions in a user group.
637 666
638 667 :param apiuser: This is filled automatically from the |authtoken|.
639 668 :type apiuser: AuthUser
640 669 :param usergroupid: Set the user group from which to revoke the user
641 670 permissions.
642 671 :type: usergroupid: str or int
643 672 :param userid: Set the userid of the user whose permissions will be
644 673 revoked.
645 674 :type userid: str
646 675
647 676 Example output:
648 677
649 678 .. code-block:: bash
650 679
651 680 id : <id_given_in_input>
652 681 result : {
653 682 "msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
654 683 "success": true
655 684 }
656 685 error : null
657 686 """
658 687
659 688 user_group = get_user_group_or_error(usergroupid)
660 689
661 690 if not has_superadmin_permission(apiuser):
662 691 # check if we have admin permission for this user group !
663 692 _perms = ('usergroup.admin',)
664 693 if not HasUserGroupPermissionAnyApi(*_perms)(
665 694 user=apiuser, user_group_name=user_group.users_group_name):
666 695 raise JSONRPCError(
667 696 'user group `%s` does not exist' % (usergroupid,))
668 697
669 698 user = get_user_or_error(userid)
670 699
671 700 try:
672 701 UserGroupModel().revoke_user_permission(
673 702 user_group=user_group, user=user)
674 703 Session().commit()
675 704 return {
676 705 'msg': 'Revoked perm for user: `%s` in user group: `%s`' % (
677 706 user.username, user_group.users_group_name
678 707 ),
679 708 'success': True
680 709 }
681 710 except Exception:
682 711 log.exception("Error occurred during editing permissions "
683 712 "for user in user group")
684 713 raise JSONRPCError(
685 714 'failed to edit permission for user: `%s` in user group: `%s`'
686 715 % (userid, user_group.users_group_name))
687 716
688 717
689 718 @jsonrpc_method()
690 719 def grant_user_group_permission_to_user_group(
691 720 request, apiuser, usergroupid, sourceusergroupid, perm):
692 721 """
693 722 Give one user group permissions to another user group.
694 723
695 724 :param apiuser: This is filled automatically from the |authtoken|.
696 725 :type apiuser: AuthUser
697 726 :param usergroupid: Set the user group on which to edit permissions.
698 727 :type usergroupid: str or int
699 728 :param sourceusergroupid: Set the source user group to which
700 729 access/permissions will be granted.
701 730 :type sourceusergroupid: str or int
702 731 :param perm: (usergroup.(none|read|write|admin))
703 732 :type perm: str
704 733
705 734 Example output:
706 735
707 736 .. code-block:: bash
708 737
709 738 id : <id_given_in_input>
710 739 result : {
711 740 "msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
712 741 "success": true
713 742 }
714 743 error : null
715 744 """
716 745
717 746 user_group = get_user_group_or_error(sourceusergroupid)
718 747 target_user_group = get_user_group_or_error(usergroupid)
719 748 perm = get_perm_or_error(perm, prefix='usergroup.')
720 749
721 750 if not has_superadmin_permission(apiuser):
722 751 # check if we have admin permission for this user group !
723 752 _perms = ('usergroup.admin',)
724 753 if not HasUserGroupPermissionAnyApi(*_perms)(
725 754 user=apiuser,
726 755 user_group_name=target_user_group.users_group_name):
727 756 raise JSONRPCError(
728 757 'to user group `%s` does not exist' % (usergroupid,))
729 758
730 759 # check if we have at least read permission for source user group !
731 760 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
732 761 if not HasUserGroupPermissionAnyApi(*_perms)(
733 762 user=apiuser, user_group_name=user_group.users_group_name):
734 763 raise JSONRPCError(
735 764 'user group `%s` does not exist' % (sourceusergroupid,))
736 765
737 766 try:
738 767 UserGroupModel().grant_user_group_permission(
739 768 target_user_group=target_user_group,
740 769 user_group=user_group, perm=perm)
741 770 Session().commit()
742 771
743 772 return {
744 773 'msg': 'Granted perm: `%s` for user group: `%s` '
745 774 'in user group: `%s`' % (
746 775 perm.permission_name, user_group.users_group_name,
747 776 target_user_group.users_group_name
748 777 ),
749 778 'success': True
750 779 }
751 780 except Exception:
752 781 log.exception("Error occurred during editing permissions "
753 782 "for user group in user group")
754 783 raise JSONRPCError(
755 784 'failed to edit permission for user group: `%s` in '
756 785 'user group: `%s`' % (
757 786 sourceusergroupid, target_user_group.users_group_name
758 787 )
759 788 )
760 789
761 790
762 791 @jsonrpc_method()
763 792 def revoke_user_group_permission_from_user_group(
764 793 request, apiuser, usergroupid, sourceusergroupid):
765 794 """
766 795 Revoke the permissions that one user group has to another.
767 796
768 797 :param apiuser: This is filled automatically from the |authtoken|.
769 798 :type apiuser: AuthUser
770 799 :param usergroupid: Set the user group on which to edit permissions.
771 800 :type usergroupid: str or int
772 801 :param sourceusergroupid: Set the user group from which permissions
773 802 are revoked.
774 803 :type sourceusergroupid: str or int
775 804
776 805 Example output:
777 806
778 807 .. code-block:: bash
779 808
780 809 id : <id_given_in_input>
781 810 result : {
782 811 "msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
783 812 "success": true
784 813 }
785 814 error : null
786 815 """
787 816
788 817 user_group = get_user_group_or_error(sourceusergroupid)
789 818 target_user_group = get_user_group_or_error(usergroupid)
790 819
791 820 if not has_superadmin_permission(apiuser):
792 821 # check if we have admin permission for this user group !
793 822 _perms = ('usergroup.admin',)
794 823 if not HasUserGroupPermissionAnyApi(*_perms)(
795 824 user=apiuser,
796 825 user_group_name=target_user_group.users_group_name):
797 826 raise JSONRPCError(
798 827 'to user group `%s` does not exist' % (usergroupid,))
799 828
800 829 # check if we have at least read permission
801 830 # for the source user group !
802 831 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
803 832 if not HasUserGroupPermissionAnyApi(*_perms)(
804 833 user=apiuser, user_group_name=user_group.users_group_name):
805 834 raise JSONRPCError(
806 835 'user group `%s` does not exist' % (sourceusergroupid,))
807 836
808 837 try:
809 838 UserGroupModel().revoke_user_group_permission(
810 839 target_user_group=target_user_group, user_group=user_group)
811 840 Session().commit()
812 841
813 842 return {
814 843 'msg': 'Revoked perm for user group: '
815 844 '`%s` in user group: `%s`' % (
816 845 user_group.users_group_name,
817 846 target_user_group.users_group_name
818 847 ),
819 848 'success': True
820 849 }
821 850 except Exception:
822 851 log.exception("Error occurred during editing permissions "
823 852 "for user group in user group")
824 853 raise JSONRPCError(
825 854 'failed to edit permission for user group: '
826 855 '`%s` in user group: `%s`' % (
827 856 sourceusergroupid, target_user_group.users_group_name
828 857 )
829 858 )
@@ -1,246 +1,245 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2018 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 logging
22 22
23 23 import formencode
24 24 import formencode.htmlfill
25 25
26 26 from pyramid.httpexceptions import HTTPFound
27 27 from pyramid.view import view_config
28 28 from pyramid.response import Response
29 29 from pyramid.renderers import render
30 30
31 31 from rhodecode.apps._base import BaseAppView, DataGridAppView
32 32 from rhodecode.lib.auth import (
33 33 LoginRequired, NotAnonymous, CSRFRequired, HasPermissionAnyDecorator)
34 34 from rhodecode.lib import helpers as h, audit_logger
35 35 from rhodecode.lib.utils2 import safe_unicode
36 36
37 37 from rhodecode.model.forms import UserGroupForm
38 38 from rhodecode.model.permission import PermissionModel
39 39 from rhodecode.model.scm import UserGroupList
40 40 from rhodecode.model.db import (
41 41 or_, count, User, UserGroup, UserGroupMember)
42 42 from rhodecode.model.meta import Session
43 43 from rhodecode.model.user_group import UserGroupModel
44 44
45 45 log = logging.getLogger(__name__)
46 46
47 47
48 48 class AdminUserGroupsView(BaseAppView, DataGridAppView):
49 49
50 50 def load_default_context(self):
51 51 c = self._get_local_tmpl_context()
52 52
53 53 PermissionModel().set_global_permission_choices(
54 54 c, gettext_translator=self.request.translate)
55 55
56 56 return c
57 57
58 58 # permission check in data loading of
59 59 # `user_groups_list_data` via UserGroupList
60 60 @LoginRequired()
61 61 @NotAnonymous()
62 62 @view_config(
63 63 route_name='user_groups', request_method='GET',
64 64 renderer='rhodecode:templates/admin/user_groups/user_groups.mako')
65 65 def user_groups_list(self):
66 66 c = self.load_default_context()
67 67 return self._get_template_context(c)
68 68
69 69 # permission check inside
70 70 @LoginRequired()
71 71 @NotAnonymous()
72 72 @view_config(
73 73 route_name='user_groups_data', request_method='GET',
74 74 renderer='json_ext', xhr=True)
75 75 def user_groups_list_data(self):
76 76 self.load_default_context()
77 77 column_map = {
78 78 'active': 'users_group_active',
79 79 'description': 'user_group_description',
80 80 'members': 'members_total',
81 81 'owner': 'user_username',
82 82 'sync': 'group_data'
83 83 }
84 84 draw, start, limit = self._extract_chunk(self.request)
85 85 search_q, order_by, order_dir = self._extract_ordering(
86 86 self.request, column_map=column_map)
87 87
88 88 _render = self.request.get_partial_renderer(
89 89 'rhodecode:templates/data_table/_dt_elements.mako')
90 90
91 91 def user_group_name(user_group_name):
92 92 return _render("user_group_name", user_group_name)
93 93
94 94 def user_group_actions(user_group_id, user_group_name):
95 95 return _render("user_group_actions", user_group_id, user_group_name)
96 96
97 97 def user_profile(username):
98 98 return _render('user_profile', username)
99 99
100 100 auth_user_group_list = UserGroupList(
101 101 UserGroup.query().all(), perm_set=['usergroup.admin'])
102 102
103 103 allowed_ids = [-1]
104 104 for user_group in auth_user_group_list:
105 105 allowed_ids.append(user_group.users_group_id)
106 106
107 107 user_groups_data_total_count = UserGroup.query()\
108 108 .filter(UserGroup.users_group_id.in_(allowed_ids))\
109 109 .count()
110 110
111 111 member_count = count(UserGroupMember.user_id)
112 112 base_q = Session.query(
113 113 UserGroup.users_group_name,
114 114 UserGroup.user_group_description,
115 115 UserGroup.users_group_active,
116 116 UserGroup.users_group_id,
117 117 UserGroup.group_data,
118 118 User,
119 119 member_count.label('member_count')
120 120 ) \
121 121 .filter(UserGroup.users_group_id.in_(allowed_ids)) \
122 122 .outerjoin(UserGroupMember) \
123 123 .join(User, User.user_id == UserGroup.user_id) \
124 124 .group_by(UserGroup, User)
125 125
126 126 if search_q:
127 127 like_expression = u'%{}%'.format(safe_unicode(search_q))
128 128 base_q = base_q.filter(or_(
129 129 UserGroup.users_group_name.ilike(like_expression),
130 130 ))
131 131
132 132 user_groups_data_total_filtered_count = base_q.count()
133 133
134 134 if order_by == 'members_total':
135 135 sort_col = member_count
136 136 elif order_by == 'user_username':
137 137 sort_col = User.username
138 138 else:
139 139 sort_col = getattr(UserGroup, order_by, None)
140 140
141 141 if isinstance(sort_col, count) or sort_col:
142 142 if order_dir == 'asc':
143 143 sort_col = sort_col.asc()
144 144 else:
145 145 sort_col = sort_col.desc()
146 146
147 147 base_q = base_q.order_by(sort_col)
148 148 base_q = base_q.offset(start).limit(limit)
149 149
150 150 # authenticated access to user groups
151 151 auth_user_group_list = base_q.all()
152 152
153 153 user_groups_data = []
154 154 for user_gr in auth_user_group_list:
155 155 user_groups_data.append({
156 156 "users_group_name": user_group_name(user_gr.users_group_name),
157 157 "name_raw": h.escape(user_gr.users_group_name),
158 158 "description": h.escape(user_gr.user_group_description),
159 159 "members": user_gr.member_count,
160 160 # NOTE(marcink): because of advanced query we
161 161 # need to load it like that
162 "sync": UserGroup._load_group_data(
163 user_gr.group_data).get('extern_type'),
162 "sync": UserGroup._load_sync(user_gr.group_data),
164 163 "active": h.bool2icon(user_gr.users_group_active),
165 164 "owner": user_profile(user_gr.User.username),
166 165 "action": user_group_actions(
167 166 user_gr.users_group_id, user_gr.users_group_name)
168 167 })
169 168
170 169 data = ({
171 170 'draw': draw,
172 171 'data': user_groups_data,
173 172 'recordsTotal': user_groups_data_total_count,
174 173 'recordsFiltered': user_groups_data_total_filtered_count,
175 174 })
176 175
177 176 return data
178 177
179 178 @LoginRequired()
180 179 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
181 180 @view_config(
182 181 route_name='user_groups_new', request_method='GET',
183 182 renderer='rhodecode:templates/admin/user_groups/user_group_add.mako')
184 183 def user_groups_new(self):
185 184 c = self.load_default_context()
186 185 return self._get_template_context(c)
187 186
188 187 @LoginRequired()
189 188 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
190 189 @CSRFRequired()
191 190 @view_config(
192 191 route_name='user_groups_create', request_method='POST',
193 192 renderer='rhodecode:templates/admin/user_groups/user_group_add.mako')
194 193 def user_groups_create(self):
195 194 _ = self.request.translate
196 195 c = self.load_default_context()
197 196 users_group_form = UserGroupForm(self.request.translate)()
198 197
199 198 user_group_name = self.request.POST.get('users_group_name')
200 199 try:
201 200 form_result = users_group_form.to_python(dict(self.request.POST))
202 201 user_group = UserGroupModel().create(
203 202 name=form_result['users_group_name'],
204 203 description=form_result['user_group_description'],
205 204 owner=self._rhodecode_user.user_id,
206 205 active=form_result['users_group_active'])
207 206 Session().flush()
208 207 creation_data = user_group.get_api_data()
209 208 user_group_name = form_result['users_group_name']
210 209
211 210 audit_logger.store_web(
212 211 'user_group.create', action_data={'data': creation_data},
213 212 user=self._rhodecode_user)
214 213
215 214 user_group_link = h.link_to(
216 215 h.escape(user_group_name),
217 216 h.route_path(
218 217 'edit_user_group', user_group_id=user_group.users_group_id))
219 218 h.flash(h.literal(_('Created user group %(user_group_link)s')
220 219 % {'user_group_link': user_group_link}),
221 220 category='success')
222 221 Session().commit()
223 222 user_group_id = user_group.users_group_id
224 223 except formencode.Invalid as errors:
225 224
226 225 data = render(
227 226 'rhodecode:templates/admin/user_groups/user_group_add.mako',
228 227 self._get_template_context(c), self.request)
229 228 html = formencode.htmlfill.render(
230 229 data,
231 230 defaults=errors.value,
232 231 errors=errors.error_dict or {},
233 232 prefix_error=False,
234 233 encoding="UTF-8",
235 234 force_defaults=False
236 235 )
237 236 return Response(html)
238 237
239 238 except Exception:
240 239 log.exception("Exception creating user group")
241 240 h.flash(_('Error occurred during creation of user group %s') \
242 241 % user_group_name, category='error')
243 242 raise HTTPFound(h.route_path('user_groups_new'))
244 243
245 244 raise HTTPFound(
246 245 h.route_path('edit_user_group', user_group_id=user_group_id))
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,673 +1,678 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2018 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 logging
22 22 import traceback
23 23
24 24 from rhodecode.lib.utils2 import safe_str, safe_unicode
25 25 from rhodecode.lib.exceptions import (
26 26 UserGroupAssignedException, RepoGroupAssignmentError)
27 27 from rhodecode.lib.utils2 import (
28 28 get_current_rhodecode_user, action_logger_generic)
29 29 from rhodecode.model import BaseModel
30 30 from rhodecode.model.scm import UserGroupList
31 31 from rhodecode.model.db import (
32 32 joinedload, true, func, User, UserGroupMember, UserGroup,
33 33 UserGroupRepoToPerm, Permission, UserGroupToPerm, UserUserGroupToPerm,
34 34 UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm)
35 35
36 36
37 37 log = logging.getLogger(__name__)
38 38
39 39
40 40 class UserGroupModel(BaseModel):
41 41
42 42 cls = UserGroup
43 43
44 44 def _get_user_group(self, user_group):
45 45 return self._get_instance(UserGroup, user_group,
46 46 callback=UserGroup.get_by_group_name)
47 47
48 48 def _create_default_perms(self, user_group):
49 49 # create default permission
50 50 default_perm = 'usergroup.read'
51 51 def_user = User.get_default_user()
52 52 for p in def_user.user_perms:
53 53 if p.permission.permission_name.startswith('usergroup.'):
54 54 default_perm = p.permission.permission_name
55 55 break
56 56
57 57 user_group_to_perm = UserUserGroupToPerm()
58 58 user_group_to_perm.permission = Permission.get_by_key(default_perm)
59 59
60 60 user_group_to_perm.user_group = user_group
61 61 user_group_to_perm.user_id = def_user.user_id
62 62 return user_group_to_perm
63 63
64 64 def update_permissions(
65 65 self, user_group, perm_additions=None, perm_updates=None,
66 66 perm_deletions=None, check_perms=True, cur_user=None):
67 67
68 68 from rhodecode.lib.auth import HasUserGroupPermissionAny
69 69 if not perm_additions:
70 70 perm_additions = []
71 71 if not perm_updates:
72 72 perm_updates = []
73 73 if not perm_deletions:
74 74 perm_deletions = []
75 75
76 76 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
77 77
78 78 changes = {
79 79 'added': [],
80 80 'updated': [],
81 81 'deleted': []
82 82 }
83 83 # update permissions
84 84 for member_id, perm, member_type in perm_updates:
85 85 member_id = int(member_id)
86 86 if member_type == 'user':
87 87 member_name = User.get(member_id).username
88 88 # this updates existing one
89 89 self.grant_user_permission(
90 90 user_group=user_group, user=member_id, perm=perm
91 91 )
92 92 else:
93 93 # check if we have permissions to alter this usergroup
94 94 member_name = UserGroup.get(member_id).users_group_name
95 95 if not check_perms or HasUserGroupPermissionAny(
96 96 *req_perms)(member_name, user=cur_user):
97 97 self.grant_user_group_permission(
98 98 target_user_group=user_group, user_group=member_id, perm=perm)
99 99
100 100 changes['updated'].append({'type': member_type, 'id': member_id,
101 101 'name': member_name, 'new_perm': perm})
102 102
103 103 # set new permissions
104 104 for member_id, perm, member_type in perm_additions:
105 105 member_id = int(member_id)
106 106 if member_type == 'user':
107 107 member_name = User.get(member_id).username
108 108 self.grant_user_permission(
109 109 user_group=user_group, user=member_id, perm=perm)
110 110 else:
111 111 # check if we have permissions to alter this usergroup
112 112 member_name = UserGroup.get(member_id).users_group_name
113 113 if not check_perms or HasUserGroupPermissionAny(
114 114 *req_perms)(member_name, user=cur_user):
115 115 self.grant_user_group_permission(
116 116 target_user_group=user_group, user_group=member_id, perm=perm)
117 117
118 118 changes['added'].append({'type': member_type, 'id': member_id,
119 119 'name': member_name, 'new_perm': perm})
120 120
121 121 # delete permissions
122 122 for member_id, perm, member_type in perm_deletions:
123 123 member_id = int(member_id)
124 124 if member_type == 'user':
125 125 member_name = User.get(member_id).username
126 126 self.revoke_user_permission(user_group=user_group, user=member_id)
127 127 else:
128 128 # check if we have permissions to alter this usergroup
129 129 member_name = UserGroup.get(member_id).users_group_name
130 130 if not check_perms or HasUserGroupPermissionAny(
131 131 *req_perms)(member_name, user=cur_user):
132 132 self.revoke_user_group_permission(
133 133 target_user_group=user_group, user_group=member_id)
134 134
135 135 changes['deleted'].append({'type': member_type, 'id': member_id,
136 136 'name': member_name, 'new_perm': perm})
137 137 return changes
138 138
139 139 def get(self, user_group_id, cache=False):
140 140 return UserGroup.get(user_group_id)
141 141
142 142 def get_group(self, user_group):
143 143 return self._get_user_group(user_group)
144 144
145 145 def get_by_name(self, name, cache=False, case_insensitive=False):
146 146 return UserGroup.get_by_group_name(name, cache, case_insensitive)
147 147
148 148 def create(self, name, description, owner, active=True, group_data=None):
149 149 try:
150 150 new_user_group = UserGroup()
151 151 new_user_group.user = self._get_user(owner)
152 152 new_user_group.users_group_name = name
153 153 new_user_group.user_group_description = description
154 154 new_user_group.users_group_active = active
155 155 if group_data:
156 156 new_user_group.group_data = group_data
157 157 self.sa.add(new_user_group)
158 158 perm_obj = self._create_default_perms(new_user_group)
159 159 self.sa.add(perm_obj)
160 160
161 161 self.grant_user_permission(user_group=new_user_group,
162 162 user=owner, perm='usergroup.admin')
163 163
164 164 return new_user_group
165 165 except Exception:
166 166 log.error(traceback.format_exc())
167 167 raise
168 168
169 169 def _get_memberships_for_user_ids(self, user_group, user_id_list):
170 170 members = []
171 171 for user_id in user_id_list:
172 172 member = self._get_membership(user_group.users_group_id, user_id)
173 173 members.append(member)
174 174 return members
175 175
176 176 def _get_added_and_removed_user_ids(self, user_group, user_id_list):
177 177 current_members = user_group.members or []
178 178 current_members_ids = [m.user.user_id for m in current_members]
179 179
180 180 added_members = [
181 181 user_id for user_id in user_id_list
182 182 if user_id not in current_members_ids]
183 183 if user_id_list == []:
184 184 # all members were deleted
185 185 deleted_members = current_members_ids
186 186 else:
187 187 deleted_members = [
188 188 user_id for user_id in current_members_ids
189 189 if user_id not in user_id_list]
190 190
191 191 return added_members, deleted_members
192 192
193 193 def _set_users_as_members(self, user_group, user_ids):
194 194 user_group.members = []
195 195 self.sa.flush()
196 196 members = self._get_memberships_for_user_ids(
197 197 user_group, user_ids)
198 198 user_group.members = members
199 199 self.sa.add(user_group)
200 200
201 201 def _update_members_from_user_ids(self, user_group, user_ids):
202 202 added, removed = self._get_added_and_removed_user_ids(
203 203 user_group, user_ids)
204 204 self._set_users_as_members(user_group, user_ids)
205 205 self._log_user_changes('added to', user_group, added)
206 206 self._log_user_changes('removed from', user_group, removed)
207 207 return added, removed
208 208
209 209 def _clean_members_data(self, members_data):
210 210 if not members_data:
211 211 members_data = []
212 212
213 213 members = []
214 214 for user in members_data:
215 215 uid = int(user['member_user_id'])
216 216 if uid not in members and user['type'] in ['new', 'existing']:
217 217 members.append(uid)
218 218 return members
219 219
220 def update(self, user_group, form_data):
220 def update(self, user_group, form_data, group_data=None):
221 221 user_group = self._get_user_group(user_group)
222 222 if 'users_group_name' in form_data:
223 223 user_group.users_group_name = form_data['users_group_name']
224 224 if 'users_group_active' in form_data:
225 225 user_group.users_group_active = form_data['users_group_active']
226 226 if 'user_group_description' in form_data:
227 227 user_group.user_group_description = form_data[
228 228 'user_group_description']
229 229
230 230 # handle owner change
231 231 if 'user' in form_data:
232 232 owner = form_data['user']
233 233 if isinstance(owner, basestring):
234 234 owner = User.get_by_username(form_data['user'])
235 235
236 236 if not isinstance(owner, User):
237 237 raise ValueError(
238 238 'invalid owner for user group: %s' % form_data['user'])
239 239
240 240 user_group.user = owner
241 241
242 242 added_user_ids = []
243 243 removed_user_ids = []
244 244 if 'users_group_members' in form_data:
245 245 members_id_list = self._clean_members_data(
246 246 form_data['users_group_members'])
247 247 added_user_ids, removed_user_ids = \
248 248 self._update_members_from_user_ids(user_group, members_id_list)
249 249
250 if group_data:
251 new_group_data = {}
252 new_group_data.update(group_data)
253 user_group.group_data = new_group_data
254
250 255 self.sa.add(user_group)
251 256 return user_group, added_user_ids, removed_user_ids
252 257
253 258 def delete(self, user_group, force=False):
254 259 """
255 260 Deletes repository group, unless force flag is used
256 261 raises exception if there are members in that group, else deletes
257 262 group and users
258 263
259 264 :param user_group:
260 265 :param force:
261 266 """
262 267 user_group = self._get_user_group(user_group)
263 268 if not user_group:
264 269 return
265 270
266 271 try:
267 272 # check if this group is not assigned to repo
268 273 assigned_to_repo = [x.repository for x in UserGroupRepoToPerm.query()\
269 274 .filter(UserGroupRepoToPerm.users_group == user_group).all()]
270 275 # check if this group is not assigned to repo
271 276 assigned_to_repo_group = [x.group for x in UserGroupRepoGroupToPerm.query()\
272 277 .filter(UserGroupRepoGroupToPerm.users_group == user_group).all()]
273 278
274 279 if (assigned_to_repo or assigned_to_repo_group) and not force:
275 280 assigned = ','.join(map(safe_str,
276 281 assigned_to_repo+assigned_to_repo_group))
277 282
278 283 raise UserGroupAssignedException(
279 284 'UserGroup assigned to %s' % (assigned,))
280 285 self.sa.delete(user_group)
281 286 except Exception:
282 287 log.error(traceback.format_exc())
283 288 raise
284 289
285 290 def _log_user_changes(self, action, user_group, user_or_users):
286 291 users = user_or_users
287 292 if not isinstance(users, (list, tuple)):
288 293 users = [users]
289 294
290 295 group_name = user_group.users_group_name
291 296
292 297 for user_or_user_id in users:
293 298 user = self._get_user(user_or_user_id)
294 299 log_text = 'User {user} {action} {group}'.format(
295 300 action=action, user=user.username, group=group_name)
296 301 action_logger_generic(log_text)
297 302
298 303 def _find_user_in_group(self, user, user_group):
299 304 user_group_member = None
300 305 for m in user_group.members:
301 306 if m.user_id == user.user_id:
302 307 # Found this user's membership row
303 308 user_group_member = m
304 309 break
305 310
306 311 return user_group_member
307 312
308 313 def _get_membership(self, user_group_id, user_id):
309 314 user_group_member = UserGroupMember(user_group_id, user_id)
310 315 return user_group_member
311 316
312 317 def add_user_to_group(self, user_group, user):
313 318 user_group = self._get_user_group(user_group)
314 319 user = self._get_user(user)
315 320 user_member = self._find_user_in_group(user, user_group)
316 321 if user_member:
317 322 # user already in the group, skip
318 323 return True
319 324
320 325 member = self._get_membership(
321 326 user_group.users_group_id, user.user_id)
322 327 user_group.members.append(member)
323 328
324 329 try:
325 330 self.sa.add(member)
326 331 except Exception:
327 332 # what could go wrong here?
328 333 log.error(traceback.format_exc())
329 334 raise
330 335
331 336 self._log_user_changes('added to', user_group, user)
332 337 return member
333 338
334 339 def remove_user_from_group(self, user_group, user):
335 340 user_group = self._get_user_group(user_group)
336 341 user = self._get_user(user)
337 342 user_group_member = self._find_user_in_group(user, user_group)
338 343
339 344 if not user_group_member:
340 345 # User isn't in that group
341 346 return False
342 347
343 348 try:
344 349 self.sa.delete(user_group_member)
345 350 except Exception:
346 351 log.error(traceback.format_exc())
347 352 raise
348 353
349 354 self._log_user_changes('removed from', user_group, user)
350 355 return True
351 356
352 357 def has_perm(self, user_group, perm):
353 358 user_group = self._get_user_group(user_group)
354 359 perm = self._get_perm(perm)
355 360
356 361 return UserGroupToPerm.query()\
357 362 .filter(UserGroupToPerm.users_group == user_group)\
358 363 .filter(UserGroupToPerm.permission == perm).scalar() is not None
359 364
360 365 def grant_perm(self, user_group, perm):
361 366 user_group = self._get_user_group(user_group)
362 367 perm = self._get_perm(perm)
363 368
364 369 # if this permission is already granted skip it
365 370 _perm = UserGroupToPerm.query()\
366 371 .filter(UserGroupToPerm.users_group == user_group)\
367 372 .filter(UserGroupToPerm.permission == perm)\
368 373 .scalar()
369 374 if _perm:
370 375 return
371 376
372 377 new = UserGroupToPerm()
373 378 new.users_group = user_group
374 379 new.permission = perm
375 380 self.sa.add(new)
376 381 return new
377 382
378 383 def revoke_perm(self, user_group, perm):
379 384 user_group = self._get_user_group(user_group)
380 385 perm = self._get_perm(perm)
381 386
382 387 obj = UserGroupToPerm.query()\
383 388 .filter(UserGroupToPerm.users_group == user_group)\
384 389 .filter(UserGroupToPerm.permission == perm).scalar()
385 390 if obj:
386 391 self.sa.delete(obj)
387 392
388 393 def grant_user_permission(self, user_group, user, perm):
389 394 """
390 395 Grant permission for user on given user group, or update
391 396 existing one if found
392 397
393 398 :param user_group: Instance of UserGroup, users_group_id,
394 399 or users_group_name
395 400 :param user: Instance of User, user_id or username
396 401 :param perm: Instance of Permission, or permission_name
397 402 """
398 403
399 404 user_group = self._get_user_group(user_group)
400 405 user = self._get_user(user)
401 406 permission = self._get_perm(perm)
402 407
403 408 # check if we have that permission already
404 409 obj = self.sa.query(UserUserGroupToPerm)\
405 410 .filter(UserUserGroupToPerm.user == user)\
406 411 .filter(UserUserGroupToPerm.user_group == user_group)\
407 412 .scalar()
408 413 if obj is None:
409 414 # create new !
410 415 obj = UserUserGroupToPerm()
411 416 obj.user_group = user_group
412 417 obj.user = user
413 418 obj.permission = permission
414 419 self.sa.add(obj)
415 420 log.debug('Granted perm %s to %s on %s', perm, user, user_group)
416 421 action_logger_generic(
417 422 'granted permission: {} to user: {} on usergroup: {}'.format(
418 423 perm, user, user_group), namespace='security.usergroup')
419 424
420 425 return obj
421 426
422 427 def revoke_user_permission(self, user_group, user):
423 428 """
424 429 Revoke permission for user on given user group
425 430
426 431 :param user_group: Instance of UserGroup, users_group_id,
427 432 or users_group name
428 433 :param user: Instance of User, user_id or username
429 434 """
430 435
431 436 user_group = self._get_user_group(user_group)
432 437 user = self._get_user(user)
433 438
434 439 obj = self.sa.query(UserUserGroupToPerm)\
435 440 .filter(UserUserGroupToPerm.user == user)\
436 441 .filter(UserUserGroupToPerm.user_group == user_group)\
437 442 .scalar()
438 443 if obj:
439 444 self.sa.delete(obj)
440 445 log.debug('Revoked perm on %s on %s', user_group, user)
441 446 action_logger_generic(
442 447 'revoked permission from user: {} on usergroup: {}'.format(
443 448 user, user_group), namespace='security.usergroup')
444 449
445 450 def grant_user_group_permission(self, target_user_group, user_group, perm):
446 451 """
447 452 Grant user group permission for given target_user_group
448 453
449 454 :param target_user_group:
450 455 :param user_group:
451 456 :param perm:
452 457 """
453 458 target_user_group = self._get_user_group(target_user_group)
454 459 user_group = self._get_user_group(user_group)
455 460 permission = self._get_perm(perm)
456 461 # forbid assigning same user group to itself
457 462 if target_user_group == user_group:
458 463 raise RepoGroupAssignmentError('target repo:%s cannot be '
459 464 'assigned to itself' % target_user_group)
460 465
461 466 # check if we have that permission already
462 467 obj = self.sa.query(UserGroupUserGroupToPerm)\
463 468 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
464 469 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
465 470 .scalar()
466 471 if obj is None:
467 472 # create new !
468 473 obj = UserGroupUserGroupToPerm()
469 474 obj.user_group = user_group
470 475 obj.target_user_group = target_user_group
471 476 obj.permission = permission
472 477 self.sa.add(obj)
473 478 log.debug(
474 479 'Granted perm %s to %s on %s', perm, target_user_group, user_group)
475 480 action_logger_generic(
476 481 'granted permission: {} to usergroup: {} on usergroup: {}'.format(
477 482 perm, user_group, target_user_group),
478 483 namespace='security.usergroup')
479 484
480 485 return obj
481 486
482 487 def revoke_user_group_permission(self, target_user_group, user_group):
483 488 """
484 489 Revoke user group permission for given target_user_group
485 490
486 491 :param target_user_group:
487 492 :param user_group:
488 493 """
489 494 target_user_group = self._get_user_group(target_user_group)
490 495 user_group = self._get_user_group(user_group)
491 496
492 497 obj = self.sa.query(UserGroupUserGroupToPerm)\
493 498 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
494 499 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
495 500 .scalar()
496 501 if obj:
497 502 self.sa.delete(obj)
498 503 log.debug(
499 504 'Revoked perm on %s on %s', target_user_group, user_group)
500 505 action_logger_generic(
501 506 'revoked permission from usergroup: {} on usergroup: {}'.format(
502 507 user_group, target_user_group),
503 508 namespace='security.repogroup')
504 509
505 510 def get_perms_summary(self, user_group_id):
506 511 permissions = {
507 512 'repositories': {},
508 513 'repositories_groups': {},
509 514 }
510 515 ugroup_repo_perms = UserGroupRepoToPerm.query()\
511 516 .options(joinedload(UserGroupRepoToPerm.permission))\
512 517 .options(joinedload(UserGroupRepoToPerm.repository))\
513 518 .filter(UserGroupRepoToPerm.users_group_id == user_group_id)\
514 519 .all()
515 520
516 521 for gr in ugroup_repo_perms:
517 522 permissions['repositories'][gr.repository.repo_name] \
518 523 = gr.permission.permission_name
519 524
520 525 ugroup_group_perms = UserGroupRepoGroupToPerm.query()\
521 526 .options(joinedload(UserGroupRepoGroupToPerm.permission))\
522 527 .options(joinedload(UserGroupRepoGroupToPerm.group))\
523 528 .filter(UserGroupRepoGroupToPerm.users_group_id == user_group_id)\
524 529 .all()
525 530
526 531 for gr in ugroup_group_perms:
527 532 permissions['repositories_groups'][gr.group.group_name] \
528 533 = gr.permission.permission_name
529 534 return permissions
530 535
531 536 def enforce_groups(self, user, groups, extern_type=None):
532 537 user = self._get_user(user)
533 538 current_groups = user.group_member
534 539
535 540 # find the external created groups, i.e automatically created
536 541 log.debug('Enforcing user group set `%s` on user %s', groups, user)
537 542 # calculate from what groups user should be removed
538 543 # external_groups that are not in groups
539 544 for gr in [x.users_group for x in current_groups]:
540 545 managed = gr.group_data.get('extern_type')
541 546 if managed:
542 547 if gr.users_group_name not in groups:
543 548 log.debug('Removing user %s from user group %s. '
544 549 'Group sync managed by: %s', user, gr, managed)
545 550 self.remove_user_from_group(gr, user)
546 551 else:
547 552 log.debug('Skipping removal from group %s since it is '
548 553 'not set to be automatically synchronized' % gr)
549 554
550 555 # now we calculate in which groups user should be == groups params
551 556 owner = User.get_first_super_admin().username
552 557 for gr in set(groups):
553 558 existing_group = UserGroup.get_by_group_name(gr)
554 559 if not existing_group:
555 560 desc = 'Automatically created from plugin:%s' % extern_type
556 561 # we use first admin account to set the owner of the group
557 562 existing_group = UserGroupModel().create(
558 563 gr, desc, owner, group_data={'extern_type': extern_type})
559 564
560 565 # we can only add users to groups which have set sync flag via
561 566 # extern_type attribute.
562 567 # This is either set and created via plugins, or manually
563 568 managed = existing_group.group_data.get('extern_type')
564 569 if managed:
565 570 log.debug('Adding user %s to user group %s', user, gr)
566 571 UserGroupModel().add_user_to_group(existing_group, user)
567 572 else:
568 573 log.debug('Skipping addition to group %s since it is '
569 574 'not set to be automatically synchronized' % gr)
570 575
571 576 def change_groups(self, user, groups):
572 577 """
573 578 This method changes user group assignment
574 579 :param user: User
575 580 :param groups: array of UserGroupModel
576 581 """
577 582 user = self._get_user(user)
578 583 log.debug('Changing user(%s) assignment to groups(%s)', user, groups)
579 584 current_groups = user.group_member
580 585 current_groups = [x.users_group for x in current_groups]
581 586
582 587 # calculate from what groups user should be removed/add
583 588 groups = set(groups)
584 589 current_groups = set(current_groups)
585 590
586 591 groups_to_remove = current_groups - groups
587 592 groups_to_add = groups - current_groups
588 593
589 594 removed_from_groups = []
590 595 added_to_groups = []
591 596 for gr in groups_to_remove:
592 597 log.debug('Removing user %s from user group %s',
593 598 user.username, gr.users_group_name)
594 599 removed_from_groups.append(gr.users_group_id)
595 600 self.remove_user_from_group(gr.users_group_name, user.username)
596 601 for gr in groups_to_add:
597 602 log.debug('Adding user %s to user group %s',
598 603 user.username, gr.users_group_name)
599 604 added_to_groups.append(gr.users_group_id)
600 605 UserGroupModel().add_user_to_group(
601 606 gr.users_group_name, user.username)
602 607
603 608 return added_to_groups, removed_from_groups
604 609
605 610 def _serialize_user_group(self, user_group):
606 611 import rhodecode.lib.helpers as h
607 612 return {
608 613 'id': user_group.users_group_id,
609 614 # TODO: marcink figure out a way to generate the url for the
610 615 # icon
611 616 'icon_link': '',
612 617 'value_display': 'Group: %s (%d members)' % (
613 618 user_group.users_group_name, len(user_group.members),),
614 619 'value': user_group.users_group_name,
615 620 'description': user_group.user_group_description,
616 621 'owner': user_group.user.username,
617 622
618 623 'owner_icon': h.gravatar_url(user_group.user.email, 30),
619 624 'value_display_owner': h.person(user_group.user.email),
620 625
621 626 'value_type': 'user_group',
622 627 'active': user_group.users_group_active,
623 628 }
624 629
625 630 def get_user_groups(self, name_contains=None, limit=20, only_active=True,
626 631 expand_groups=False):
627 632 query = self.sa.query(UserGroup)
628 633 if only_active:
629 634 query = query.filter(UserGroup.users_group_active == true())
630 635
631 636 if name_contains:
632 637 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
633 638 query = query.filter(
634 639 UserGroup.users_group_name.ilike(ilike_expression))\
635 640 .order_by(func.length(UserGroup.users_group_name))\
636 641 .order_by(UserGroup.users_group_name)
637 642
638 643 query = query.limit(limit)
639 644 user_groups = query.all()
640 645 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
641 646 user_groups = UserGroupList(user_groups, perm_set=perm_set)
642 647
643 648 # store same serialize method to extract data from User
644 649 from rhodecode.model.user import UserModel
645 650 serialize_user = UserModel()._serialize_user
646 651
647 652 _groups = []
648 653 for group in user_groups:
649 654 entry = self._serialize_user_group(group)
650 655 if expand_groups:
651 656 expanded_members = []
652 657 for member in group.members:
653 658 expanded_members.append(serialize_user(member.user))
654 659 entry['members'] = expanded_members
655 660 _groups.append(entry)
656 661 return _groups
657 662
658 663 @staticmethod
659 664 def get_user_groups_as_dict(user_group):
660 665 import rhodecode.lib.helpers as h
661 666
662 667 data = {
663 668 'users_group_id': user_group.users_group_id,
664 669 'group_name': user_group.users_group_name,
665 670 'group_description': user_group.user_group_description,
666 671 'active': user_group.users_group_active,
667 672 "owner": user_group.user.username,
668 673 'owner_icon': h.gravatar_url(user_group.user.email, 30),
669 674 "owner_data": {
670 675 'owner': user_group.user.username,
671 676 'owner_icon': h.gravatar_url(user_group.user.email, 30)}
672 677 }
673 678 return data
General Comments 0
You need to be logged in to leave comments. Login now