##// END OF EJS Templates
user-groups: fix potential problem with group sync of external plugins....
marcink -
r2193:20e24a44 stable
parent child Browse files
Show More
@@ -1,623 +1,629 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2017 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 """
23 23 user group model for RhodeCode
24 24 """
25 25
26 26
27 27 import logging
28 28 import traceback
29 29
30 30 from rhodecode.lib.utils2 import safe_str, safe_unicode
31 31 from rhodecode.lib.exceptions import (
32 32 UserGroupAssignedException, RepoGroupAssignmentError)
33 33 from rhodecode.lib.utils2 import (
34 34 get_current_rhodecode_user, action_logger_generic)
35 35 from rhodecode.model import BaseModel
36 36 from rhodecode.model.scm import UserGroupList
37 37 from rhodecode.model.db import (
38 38 true, func, User, UserGroupMember, UserGroup,
39 39 UserGroupRepoToPerm, Permission, UserGroupToPerm, UserUserGroupToPerm,
40 40 UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm)
41 41
42 42
43 43 log = logging.getLogger(__name__)
44 44
45 45
46 46 class UserGroupModel(BaseModel):
47 47
48 48 cls = UserGroup
49 49
50 50 def _get_user_group(self, user_group):
51 51 return self._get_instance(UserGroup, user_group,
52 52 callback=UserGroup.get_by_group_name)
53 53
54 54 def _create_default_perms(self, user_group):
55 55 # create default permission
56 56 default_perm = 'usergroup.read'
57 57 def_user = User.get_default_user()
58 58 for p in def_user.user_perms:
59 59 if p.permission.permission_name.startswith('usergroup.'):
60 60 default_perm = p.permission.permission_name
61 61 break
62 62
63 63 user_group_to_perm = UserUserGroupToPerm()
64 64 user_group_to_perm.permission = Permission.get_by_key(default_perm)
65 65
66 66 user_group_to_perm.user_group = user_group
67 67 user_group_to_perm.user_id = def_user.user_id
68 68 return user_group_to_perm
69 69
70 70 def update_permissions(self, user_group, perm_additions=None, perm_updates=None,
71 71 perm_deletions=None, check_perms=True, cur_user=None):
72 72 from rhodecode.lib.auth import HasUserGroupPermissionAny
73 73 if not perm_additions:
74 74 perm_additions = []
75 75 if not perm_updates:
76 76 perm_updates = []
77 77 if not perm_deletions:
78 78 perm_deletions = []
79 79
80 80 req_perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin')
81 81
82 82 # update permissions
83 83 for member_id, perm, member_type in perm_updates:
84 84 member_id = int(member_id)
85 85 if member_type == 'user':
86 86 # this updates existing one
87 87 self.grant_user_permission(
88 88 user_group=user_group, user=member_id, perm=perm
89 89 )
90 90 else:
91 91 # check if we have permissions to alter this usergroup
92 92 member_name = UserGroup.get(member_id).users_group_name
93 93 if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user):
94 94 self.grant_user_group_permission(
95 95 target_user_group=user_group, user_group=member_id, perm=perm
96 96 )
97 97
98 98 # set new permissions
99 99 for member_id, perm, member_type in perm_additions:
100 100 member_id = int(member_id)
101 101 if member_type == 'user':
102 102 self.grant_user_permission(
103 103 user_group=user_group, user=member_id, perm=perm
104 104 )
105 105 else:
106 106 # check if we have permissions to alter this usergroup
107 107 member_name = UserGroup.get(member_id).users_group_name
108 108 if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user):
109 109 self.grant_user_group_permission(
110 110 target_user_group=user_group, user_group=member_id, perm=perm
111 111 )
112 112
113 113 # delete permissions
114 114 for member_id, perm, member_type in perm_deletions:
115 115 member_id = int(member_id)
116 116 if member_type == 'user':
117 117 self.revoke_user_permission(user_group=user_group, user=member_id)
118 118 else:
119 119 # check if we have permissions to alter this usergroup
120 120 member_name = UserGroup.get(member_id).users_group_name
121 121 if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user):
122 122 self.revoke_user_group_permission(
123 123 target_user_group=user_group, user_group=member_id
124 124 )
125 125
126 126 def get(self, user_group_id, cache=False):
127 127 return UserGroup.get(user_group_id)
128 128
129 129 def get_group(self, user_group):
130 130 return self._get_user_group(user_group)
131 131
132 132 def get_by_name(self, name, cache=False, case_insensitive=False):
133 133 return UserGroup.get_by_group_name(name, cache, case_insensitive)
134 134
135 135 def create(self, name, description, owner, active=True, group_data=None):
136 136 try:
137 137 new_user_group = UserGroup()
138 138 new_user_group.user = self._get_user(owner)
139 139 new_user_group.users_group_name = name
140 140 new_user_group.user_group_description = description
141 141 new_user_group.users_group_active = active
142 142 if group_data:
143 143 new_user_group.group_data = group_data
144 144 self.sa.add(new_user_group)
145 145 perm_obj = self._create_default_perms(new_user_group)
146 146 self.sa.add(perm_obj)
147 147
148 148 self.grant_user_permission(user_group=new_user_group,
149 149 user=owner, perm='usergroup.admin')
150 150
151 151 return new_user_group
152 152 except Exception:
153 153 log.error(traceback.format_exc())
154 154 raise
155 155
156 156 def _get_memberships_for_user_ids(self, user_group, user_id_list):
157 157 members = []
158 158 for user_id in user_id_list:
159 159 member = self._get_membership(user_group.users_group_id, user_id)
160 160 members.append(member)
161 161 return members
162 162
163 163 def _get_added_and_removed_user_ids(self, user_group, user_id_list):
164 164 current_members = user_group.members or []
165 165 current_members_ids = [m.user.user_id for m in current_members]
166 166
167 167 added_members = [
168 168 user_id for user_id in user_id_list
169 169 if user_id not in current_members_ids]
170 170 if user_id_list == []:
171 171 # all members were deleted
172 172 deleted_members = current_members_ids
173 173 else:
174 174 deleted_members = [
175 175 user_id for user_id in current_members_ids
176 176 if user_id not in user_id_list]
177 177
178 178 return added_members, deleted_members
179 179
180 180 def _set_users_as_members(self, user_group, user_ids):
181 181 user_group.members = []
182 182 self.sa.flush()
183 183 members = self._get_memberships_for_user_ids(
184 184 user_group, user_ids)
185 185 user_group.members = members
186 186 self.sa.add(user_group)
187 187
188 188 def _update_members_from_user_ids(self, user_group, user_ids):
189 189 added, removed = self._get_added_and_removed_user_ids(
190 190 user_group, user_ids)
191 191 self._set_users_as_members(user_group, user_ids)
192 192 self._log_user_changes('added to', user_group, added)
193 193 self._log_user_changes('removed from', user_group, removed)
194 194 return added, removed
195 195
196 196 def _clean_members_data(self, members_data):
197 197 if not members_data:
198 198 members_data = []
199 199
200 200 members = []
201 201 for user in members_data:
202 202 uid = int(user['member_user_id'])
203 203 if uid not in members and user['type'] in ['new', 'existing']:
204 204 members.append(uid)
205 205 return members
206 206
207 207 def update(self, user_group, form_data):
208 208 user_group = self._get_user_group(user_group)
209 209 if 'users_group_name' in form_data:
210 210 user_group.users_group_name = form_data['users_group_name']
211 211 if 'users_group_active' in form_data:
212 212 user_group.users_group_active = form_data['users_group_active']
213 213 if 'user_group_description' in form_data:
214 214 user_group.user_group_description = form_data[
215 215 'user_group_description']
216 216
217 217 # handle owner change
218 218 if 'user' in form_data:
219 219 owner = form_data['user']
220 220 if isinstance(owner, basestring):
221 221 owner = User.get_by_username(form_data['user'])
222 222
223 223 if not isinstance(owner, User):
224 224 raise ValueError(
225 225 'invalid owner for user group: %s' % form_data['user'])
226 226
227 227 user_group.user = owner
228 228
229 229 added_user_ids = []
230 230 removed_user_ids = []
231 231 if 'users_group_members' in form_data:
232 232 members_id_list = self._clean_members_data(
233 233 form_data['users_group_members'])
234 234 added_user_ids, removed_user_ids = \
235 235 self._update_members_from_user_ids(user_group, members_id_list)
236 236
237 237 self.sa.add(user_group)
238 238 return user_group, added_user_ids, removed_user_ids
239 239
240 240 def delete(self, user_group, force=False):
241 241 """
242 242 Deletes repository group, unless force flag is used
243 243 raises exception if there are members in that group, else deletes
244 244 group and users
245 245
246 246 :param user_group:
247 247 :param force:
248 248 """
249 249 user_group = self._get_user_group(user_group)
250 250 try:
251 251 # check if this group is not assigned to repo
252 252 assigned_to_repo = [x.repository for x in UserGroupRepoToPerm.query()\
253 253 .filter(UserGroupRepoToPerm.users_group == user_group).all()]
254 254 # check if this group is not assigned to repo
255 255 assigned_to_repo_group = [x.group for x in UserGroupRepoGroupToPerm.query()\
256 256 .filter(UserGroupRepoGroupToPerm.users_group == user_group).all()]
257 257
258 258 if (assigned_to_repo or assigned_to_repo_group) and not force:
259 259 assigned = ','.join(map(safe_str,
260 260 assigned_to_repo+assigned_to_repo_group))
261 261
262 262 raise UserGroupAssignedException(
263 263 'UserGroup assigned to %s' % (assigned,))
264 264 self.sa.delete(user_group)
265 265 except Exception:
266 266 log.error(traceback.format_exc())
267 267 raise
268 268
269 269 def _log_user_changes(self, action, user_group, user_or_users):
270 270 users = user_or_users
271 271 if not isinstance(users, (list, tuple)):
272 272 users = [users]
273 273 rhodecode_user = get_current_rhodecode_user()
274 274 ipaddr = getattr(rhodecode_user, 'ip_addr', '')
275 275 group_name = user_group.users_group_name
276 276
277 277 for user_or_user_id in users:
278 278 user = self._get_user(user_or_user_id)
279 279 log_text = 'User {user} {action} {group}'.format(
280 280 action=action, user=user.username, group=group_name)
281 281 log.info('Logging action: {0} by {1} ip:{2}'.format(
282 282 log_text, rhodecode_user, ipaddr))
283 283
284 284 def _find_user_in_group(self, user, user_group):
285 285 user_group_member = None
286 286 for m in user_group.members:
287 287 if m.user_id == user.user_id:
288 288 # Found this user's membership row
289 289 user_group_member = m
290 290 break
291 291
292 292 return user_group_member
293 293
294 294 def _get_membership(self, user_group_id, user_id):
295 295 user_group_member = UserGroupMember(user_group_id, user_id)
296 296 return user_group_member
297 297
298 298 def add_user_to_group(self, user_group, user):
299 299 user_group = self._get_user_group(user_group)
300 300 user = self._get_user(user)
301 301 user_member = self._find_user_in_group(user, user_group)
302 302 if user_member:
303 303 # user already in the group, skip
304 304 return True
305 305
306 306 member = self._get_membership(
307 307 user_group.users_group_id, user.user_id)
308 308 user_group.members.append(member)
309 309
310 310 try:
311 311 self.sa.add(member)
312 312 except Exception:
313 313 # what could go wrong here?
314 314 log.error(traceback.format_exc())
315 315 raise
316 316
317 317 self._log_user_changes('added to', user_group, user)
318 318 return member
319 319
320 320 def remove_user_from_group(self, user_group, user):
321 321 user_group = self._get_user_group(user_group)
322 322 user = self._get_user(user)
323 323 user_group_member = self._find_user_in_group(user, user_group)
324 324
325 325 if not user_group_member:
326 326 # User isn't in that group
327 327 return False
328 328
329 329 try:
330 330 self.sa.delete(user_group_member)
331 331 except Exception:
332 332 log.error(traceback.format_exc())
333 333 raise
334 334
335 335 self._log_user_changes('removed from', user_group, user)
336 336 return True
337 337
338 338 def has_perm(self, user_group, perm):
339 339 user_group = self._get_user_group(user_group)
340 340 perm = self._get_perm(perm)
341 341
342 342 return UserGroupToPerm.query()\
343 343 .filter(UserGroupToPerm.users_group == user_group)\
344 344 .filter(UserGroupToPerm.permission == perm).scalar() is not None
345 345
346 346 def grant_perm(self, user_group, perm):
347 347 user_group = self._get_user_group(user_group)
348 348 perm = self._get_perm(perm)
349 349
350 350 # if this permission is already granted skip it
351 351 _perm = UserGroupToPerm.query()\
352 352 .filter(UserGroupToPerm.users_group == user_group)\
353 353 .filter(UserGroupToPerm.permission == perm)\
354 354 .scalar()
355 355 if _perm:
356 356 return
357 357
358 358 new = UserGroupToPerm()
359 359 new.users_group = user_group
360 360 new.permission = perm
361 361 self.sa.add(new)
362 362 return new
363 363
364 364 def revoke_perm(self, user_group, perm):
365 365 user_group = self._get_user_group(user_group)
366 366 perm = self._get_perm(perm)
367 367
368 368 obj = UserGroupToPerm.query()\
369 369 .filter(UserGroupToPerm.users_group == user_group)\
370 370 .filter(UserGroupToPerm.permission == perm).scalar()
371 371 if obj:
372 372 self.sa.delete(obj)
373 373
374 374 def grant_user_permission(self, user_group, user, perm):
375 375 """
376 376 Grant permission for user on given user group, or update
377 377 existing one if found
378 378
379 379 :param user_group: Instance of UserGroup, users_group_id,
380 380 or users_group_name
381 381 :param user: Instance of User, user_id or username
382 382 :param perm: Instance of Permission, or permission_name
383 383 """
384 384
385 385 user_group = self._get_user_group(user_group)
386 386 user = self._get_user(user)
387 387 permission = self._get_perm(perm)
388 388
389 389 # check if we have that permission already
390 390 obj = self.sa.query(UserUserGroupToPerm)\
391 391 .filter(UserUserGroupToPerm.user == user)\
392 392 .filter(UserUserGroupToPerm.user_group == user_group)\
393 393 .scalar()
394 394 if obj is None:
395 395 # create new !
396 396 obj = UserUserGroupToPerm()
397 397 obj.user_group = user_group
398 398 obj.user = user
399 399 obj.permission = permission
400 400 self.sa.add(obj)
401 401 log.debug('Granted perm %s to %s on %s', perm, user, user_group)
402 402 action_logger_generic(
403 403 'granted permission: {} to user: {} on usergroup: {}'.format(
404 404 perm, user, user_group), namespace='security.usergroup')
405 405
406 406 return obj
407 407
408 408 def revoke_user_permission(self, user_group, user):
409 409 """
410 410 Revoke permission for user on given user group
411 411
412 412 :param user_group: Instance of UserGroup, users_group_id,
413 413 or users_group name
414 414 :param user: Instance of User, user_id or username
415 415 """
416 416
417 417 user_group = self._get_user_group(user_group)
418 418 user = self._get_user(user)
419 419
420 420 obj = self.sa.query(UserUserGroupToPerm)\
421 421 .filter(UserUserGroupToPerm.user == user)\
422 422 .filter(UserUserGroupToPerm.user_group == user_group)\
423 423 .scalar()
424 424 if obj:
425 425 self.sa.delete(obj)
426 426 log.debug('Revoked perm on %s on %s', user_group, user)
427 427 action_logger_generic(
428 428 'revoked permission from user: {} on usergroup: {}'.format(
429 429 user, user_group), namespace='security.usergroup')
430 430
431 431 def grant_user_group_permission(self, target_user_group, user_group, perm):
432 432 """
433 433 Grant user group permission for given target_user_group
434 434
435 435 :param target_user_group:
436 436 :param user_group:
437 437 :param perm:
438 438 """
439 439 target_user_group = self._get_user_group(target_user_group)
440 440 user_group = self._get_user_group(user_group)
441 441 permission = self._get_perm(perm)
442 442 # forbid assigning same user group to itself
443 443 if target_user_group == user_group:
444 444 raise RepoGroupAssignmentError('target repo:%s cannot be '
445 445 'assigned to itself' % target_user_group)
446 446
447 447 # check if we have that permission already
448 448 obj = self.sa.query(UserGroupUserGroupToPerm)\
449 449 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
450 450 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
451 451 .scalar()
452 452 if obj is None:
453 453 # create new !
454 454 obj = UserGroupUserGroupToPerm()
455 455 obj.user_group = user_group
456 456 obj.target_user_group = target_user_group
457 457 obj.permission = permission
458 458 self.sa.add(obj)
459 459 log.debug(
460 460 'Granted perm %s to %s on %s', perm, target_user_group, user_group)
461 461 action_logger_generic(
462 462 'granted permission: {} to usergroup: {} on usergroup: {}'.format(
463 463 perm, user_group, target_user_group),
464 464 namespace='security.usergroup')
465 465
466 466 return obj
467 467
468 468 def revoke_user_group_permission(self, target_user_group, user_group):
469 469 """
470 470 Revoke user group permission for given target_user_group
471 471
472 472 :param target_user_group:
473 473 :param user_group:
474 474 """
475 475 target_user_group = self._get_user_group(target_user_group)
476 476 user_group = self._get_user_group(user_group)
477 477
478 478 obj = self.sa.query(UserGroupUserGroupToPerm)\
479 479 .filter(UserGroupUserGroupToPerm.target_user_group == target_user_group)\
480 480 .filter(UserGroupUserGroupToPerm.user_group == user_group)\
481 481 .scalar()
482 482 if obj:
483 483 self.sa.delete(obj)
484 484 log.debug(
485 485 'Revoked perm on %s on %s', target_user_group, user_group)
486 486 action_logger_generic(
487 487 'revoked permission from usergroup: {} on usergroup: {}'.format(
488 488 user_group, target_user_group),
489 489 namespace='security.repogroup')
490 490
491 491 def enforce_groups(self, user, groups, extern_type=None):
492 492 user = self._get_user(user)
493 log.debug('Enforcing groups %s on user %s', groups, user)
494 493 current_groups = user.group_member
495 # find the external created groups
496 externals = [x.users_group for x in current_groups
497 if 'extern_type' in x.users_group.group_data]
498 494
495 # find the external created groups, i.e automatically created
496 log.debug('Enforcing user group set `%s` on user %s', groups, user)
499 497 # calculate from what groups user should be removed
500 # externals that are not in groups
501 for gr in externals:
502 if gr.users_group_name not in groups:
503 log.debug('Removing user %s from user group %s', user, gr)
504 self.remove_user_from_group(gr, user)
498 # external_groups that are not in groups
499 for gr in [x.users_group for x in current_groups]:
500 managed = gr.group_data.get('extern_type')
501 if managed:
502 if gr.users_group_name not in groups:
503 log.debug('Removing user %s from user group %s. '
504 'Group sync managed by: %s', user, gr, managed)
505 self.remove_user_from_group(gr, user)
506 else:
507 log.debug('Skipping removal from group %s since it is '
508 'not set to be automatically synchronized' % gr)
505 509
506 510 # now we calculate in which groups user should be == groups params
507 511 owner = User.get_first_super_admin().username
508 512 for gr in set(groups):
509 513 existing_group = UserGroup.get_by_group_name(gr)
510 514 if not existing_group:
511 515 desc = 'Automatically created from plugin:%s' % extern_type
512 516 # we use first admin account to set the owner of the group
513 517 existing_group = UserGroupModel().create(
514 518 gr, desc, owner, group_data={'extern_type': extern_type})
515 519
516 # we can only add users to special groups created via plugins
517 managed = 'extern_type' in existing_group.group_data
520 # we can only add users to groups which have set sync flag via
521 # extern_type attribute.
522 # This is either set and created via plugins, or manually
523 managed = existing_group.group_data.get('extern_type')
518 524 if managed:
519 525 log.debug('Adding user %s to user group %s', user, gr)
520 526 UserGroupModel().add_user_to_group(existing_group, user)
521 527 else:
522 528 log.debug('Skipping addition to group %s since it is '
523 529 'not set to be automatically synchronized' % gr)
524 530
525 531 def change_groups(self, user, groups):
526 532 """
527 533 This method changes user group assignment
528 534 :param user: User
529 535 :param groups: array of UserGroupModel
530 536 :return:
531 537 """
532 538 user = self._get_user(user)
533 539 log.debug('Changing user(%s) assignment to groups(%s)', user, groups)
534 540 current_groups = user.group_member
535 541 current_groups = [x.users_group for x in current_groups]
536 542
537 543 # calculate from what groups user should be removed/add
538 544 groups = set(groups)
539 545 current_groups = set(current_groups)
540 546
541 547 groups_to_remove = current_groups - groups
542 548 groups_to_add = groups - current_groups
543 549
544 550 for gr in groups_to_remove:
545 551 log.debug('Removing user %s from user group %s', user.username, gr.users_group_name)
546 552 self.remove_user_from_group(gr.users_group_name, user.username)
547 553 for gr in groups_to_add:
548 554 log.debug('Adding user %s to user group %s', user.username, gr.users_group_name)
549 555 UserGroupModel().add_user_to_group(gr.users_group_name, user.username)
550 556
551 557 def _serialize_user_group(self, user_group):
552 558 import rhodecode.lib.helpers as h
553 559 return {
554 560 'id': user_group.users_group_id,
555 561 # TODO: marcink figure out a way to generate the url for the
556 562 # icon
557 563 'icon_link': '',
558 564 'value_display': 'Group: %s (%d members)' % (
559 565 user_group.users_group_name, len(user_group.members),),
560 566 'value': user_group.users_group_name,
561 567 'description': user_group.user_group_description,
562 568 'owner': user_group.user.username,
563 569
564 570 'owner_icon': h.gravatar_url(user_group.user.email, 30),
565 571 'value_display_owner': h.person(user_group.user.email),
566 572
567 573 'value_type': 'user_group',
568 574 'active': user_group.users_group_active,
569 575 }
570 576
571 577 def get_user_groups(self, name_contains=None, limit=20, only_active=True,
572 578 expand_groups=False):
573 579 query = self.sa.query(UserGroup)
574 580 if only_active:
575 581 query = query.filter(UserGroup.users_group_active == true())
576 582
577 583 if name_contains:
578 584 ilike_expression = u'%{}%'.format(safe_unicode(name_contains))
579 585 query = query.filter(
580 586 UserGroup.users_group_name.ilike(ilike_expression))\
581 587 .order_by(func.length(UserGroup.users_group_name))\
582 588 .order_by(UserGroup.users_group_name)
583 589
584 590 query = query.limit(limit)
585 591 user_groups = query.all()
586 592 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
587 593 user_groups = UserGroupList(user_groups, perm_set=perm_set)
588 594
589 595 # store same serialize method to extract data from User
590 596 from rhodecode.model.user import UserModel
591 597 serialize_user = UserModel()._serialize_user
592 598
593 599 _groups = []
594 600 for group in user_groups:
595 601 entry = self._serialize_user_group(group)
596 602 if expand_groups:
597 603 expanded_members = []
598 604 for member in group.members:
599 605 expanded_members.append(serialize_user(member.user))
600 606 entry['members'] = expanded_members
601 607 _groups.append(entry)
602 608 return _groups
603 609
604 610 @staticmethod
605 611 def get_user_groups_as_dict(user_group):
606 612 import rhodecode.lib.helpers as h
607 613
608 614 data = {
609 615 'users_group_id': user_group.users_group_id,
610 616 'group_name': user_group.users_group_name,
611 617 'group_description': user_group.user_group_description,
612 618 'active': user_group.users_group_active,
613 619 "owner": user_group.user.username,
614 620 'owner_icon': h.gravatar_url(user_group.user.email, 30),
615 621 "owner_data": {
616 622 'owner': user_group.user.username,
617 623 'owner_icon': h.gravatar_url(user_group.user.email, 30)}
618 624 }
619 625 return data
620 626
621 627
622 628
623 629
General Comments 0
You need to be logged in to leave comments. Login now