Show More
@@ -374,6 +374,10 b' def make_map(config):' | |||||
374 | '/user_groups/{user_group_id}/edit/advanced', |
|
374 | '/user_groups/{user_group_id}/edit/advanced', | |
375 | action='edit_advanced', conditions={'method': ['GET']}) |
|
375 | action='edit_advanced', conditions={'method': ['GET']}) | |
376 |
|
376 | |||
|
377 | m.connect('edit_user_group_advanced_sync', | |||
|
378 | '/user_groups/{user_group_id}/edit/advanced/sync', | |||
|
379 | action='edit_advanced_set_synchronization', conditions={'method': ['POST']}) | |||
|
380 | ||||
377 | m.connect('edit_user_group_members', |
|
381 | m.connect('edit_user_group_members', | |
378 | '/user_groups/{user_group_id}/edit/members', jsroute=True, |
|
382 | '/user_groups/{user_group_id}/edit/members', jsroute=True, | |
379 | action='user_group_members', conditions={'method': ['GET']}) |
|
383 | action='user_group_members', conditions={'method': ['GET']}) |
@@ -117,7 +117,7 b' class UserGroupsController(BaseControlle' | |||||
117 | def user_group_actions(user_group_id, user_group_name): |
|
117 | def user_group_actions(user_group_id, user_group_name): | |
118 | return _render("user_group_actions", user_group_id, user_group_name) |
|
118 | return _render("user_group_actions", user_group_id, user_group_name) | |
119 |
|
119 | |||
120 |
|
|
120 | # json generate | |
121 | group_iter = UserGroupList(UserGroup.query().all(), |
|
121 | group_iter = UserGroupList(UserGroup.query().all(), | |
122 | perm_set=['usergroup.admin']) |
|
122 | perm_set=['usergroup.admin']) | |
123 |
|
123 | |||
@@ -129,6 +129,7 b' class UserGroupsController(BaseControlle' | |||||
129 | "group_name_raw": user_gr.users_group_name, |
|
129 | "group_name_raw": user_gr.users_group_name, | |
130 | "desc": h.escape(user_gr.user_group_description), |
|
130 | "desc": h.escape(user_gr.user_group_description), | |
131 | "members": len(user_gr.members), |
|
131 | "members": len(user_gr.members), | |
|
132 | "sync": user_gr.group_data.get('extern_type'), | |||
132 | "active": h.bool2icon(user_gr.users_group_active), |
|
133 | "active": h.bool2icon(user_gr.users_group_active), | |
133 | "owner": h.escape(h.link_to_user(user_gr.user.username)), |
|
134 | "owner": h.escape(h.link_to_user(user_gr.user.username)), | |
134 | "action": user_group_actions( |
|
135 | "action": user_group_actions( | |
@@ -431,7 +432,6 b' class UserGroupsController(BaseControlle' | |||||
431 | prefix_error=False, |
|
432 | prefix_error=False, | |
432 | encoding="UTF-8", |
|
433 | encoding="UTF-8", | |
433 | force_defaults=False) |
|
434 | force_defaults=False) | |
434 |
|
||||
435 | except Exception: |
|
435 | except Exception: | |
436 | log.exception("Exception during permissions saving") |
|
436 | log.exception("Exception during permissions saving") | |
437 | h.flash(_('An error occurred during permissions saving'), |
|
437 | h.flash(_('An error occurred during permissions saving'), | |
@@ -459,6 +459,36 b' class UserGroupsController(BaseControlle' | |||||
459 | return render('admin/user_groups/user_group_edit.mako') |
|
459 | return render('admin/user_groups/user_group_edit.mako') | |
460 |
|
460 | |||
461 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
461 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') | |
|
462 | def edit_advanced_set_synchronization(self, user_group_id): | |||
|
463 | user_group_id = safe_int(user_group_id) | |||
|
464 | user_group = UserGroup.get_or_404(user_group_id) | |||
|
465 | ||||
|
466 | existing = user_group.group_data.get('extern_type') | |||
|
467 | ||||
|
468 | if existing: | |||
|
469 | new_state = user_group.group_data | |||
|
470 | new_state['extern_type'] = None | |||
|
471 | else: | |||
|
472 | new_state = user_group.group_data | |||
|
473 | new_state['extern_type'] = 'manual' | |||
|
474 | new_state['extern_type_set_by'] = c.rhodecode_user.username | |||
|
475 | ||||
|
476 | try: | |||
|
477 | user_group.group_data = new_state | |||
|
478 | Session().add(user_group) | |||
|
479 | Session().commit() | |||
|
480 | ||||
|
481 | h.flash(_('User Group synchronization updated successfully'), | |||
|
482 | category='success') | |||
|
483 | except Exception: | |||
|
484 | log.exception("Exception during sync settings saving") | |||
|
485 | h.flash(_('An error occurred during synchronization update'), | |||
|
486 | category='error') | |||
|
487 | ||||
|
488 | return redirect( | |||
|
489 | url('edit_user_group_advanced', user_group_id=user_group_id)) | |||
|
490 | ||||
|
491 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') | |||
462 | @XHRRequired() |
|
492 | @XHRRequired() | |
463 | @jsonify |
|
493 | @jsonify | |
464 | def user_group_members(self, user_group_id): |
|
494 | def user_group_members(self, user_group_id): |
@@ -501,8 +501,8 b' class UserGroupModel(BaseModel):' | |||||
501 | if not existing_group: |
|
501 | if not existing_group: | |
502 | desc = 'Automatically created from plugin:%s' % extern_type |
|
502 | desc = 'Automatically created from plugin:%s' % extern_type | |
503 | # we use first admin account to set the owner of the group |
|
503 | # we use first admin account to set the owner of the group | |
504 |
existing_group = UserGroupModel().create( |
|
504 | existing_group = UserGroupModel().create( | |
505 |
|
|
505 | gr, desc, owner, group_data={'extern_type': extern_type}) | |
506 |
|
506 | |||
507 | # we can only add users to special groups created via plugins |
|
507 | # we can only add users to special groups created via plugins | |
508 | managed = 'extern_type' in existing_group.group_data |
|
508 | managed = 'extern_type' in existing_group.group_data | |
@@ -511,8 +511,7 b' class UserGroupModel(BaseModel):' | |||||
511 | UserGroupModel().add_user_to_group(existing_group, user) |
|
511 | UserGroupModel().add_user_to_group(existing_group, user) | |
512 | else: |
|
512 | else: | |
513 | log.debug('Skipping addition to group %s since it is ' |
|
513 | log.debug('Skipping addition to group %s since it is ' | |
514 |
'not |
|
514 | 'not set to be automatically synchronized' % gr) | |
515 |
|
||||
516 |
|
515 | |||
517 | def change_groups(self, user, groups): |
|
516 | def change_groups(self, user, groups): | |
518 | """ |
|
517 | """ |
@@ -6,6 +6,8 b'' | |||||
6 | (_('Created on'), h.format_date(c.user_group.created_on), '', '',), |
|
6 | (_('Created on'), h.format_date(c.user_group.created_on), '', '',), | |
7 |
|
7 | |||
8 | (_('Members'), len(c.group_members_obj),'', [x for x in c.group_members_obj]), |
|
8 | (_('Members'), len(c.group_members_obj),'', [x for x in c.group_members_obj]), | |
|
9 | (_('Automatic member sync'), 'Yes' if c.user_group.group_data.get('extern_type') else 'No', '', '',), | |||
|
10 | ||||
9 | (_('Assigned to repositories'), len(c.group_to_repos),'', [x for x in c.group_to_repos]), |
|
11 | (_('Assigned to repositories'), len(c.group_to_repos),'', [x for x in c.group_to_repos]), | |
10 | (_('Assigned to repo groups'), len(c.group_to_repo_groups), '', [x for x in c.group_to_repo_groups]), |
|
12 | (_('Assigned to repo groups'), len(c.group_to_repo_groups), '', [x for x in c.group_to_repo_groups]), | |
11 |
|
13 | |||
@@ -19,8 +21,55 b'' | |||||
19 | <div class="panel-body"> |
|
21 | <div class="panel-body"> | |
20 | ${base.dt_info_panel(elems)} |
|
22 | ${base.dt_info_panel(elems)} | |
21 | </div> |
|
23 | </div> | |
|
24 | ||||
22 | </div> |
|
25 | </div> | |
23 |
|
26 | |||
|
27 | <div class="panel panel-default"> | |||
|
28 | <div class="panel-heading"> | |||
|
29 | <h3 class="panel-title">${_('Group members sync')}</h3> | |||
|
30 | </div> | |||
|
31 | <div class="panel-body"> | |||
|
32 | <% sync_type = c.user_group.group_data.get('extern_type') %> | |||
|
33 | ||||
|
34 | % if sync_type: | |||
|
35 | <p> | |||
|
36 | ${_('This group is set to be automatically synchronised.')}<br/> | |||
|
37 | ${_('Each member will be added or removed from this groups once they interact with RhodeCode system.')}<br/> | |||
|
38 | ${_('This group synchronization was set by')}: <strong>${sync_type}</strong> | |||
|
39 | </p> | |||
|
40 | % else: | |||
|
41 | <p> | |||
|
42 | ${_('This group is not set to be automatically synchronised')} | |||
|
43 | </p> | |||
|
44 | % endif | |||
|
45 | ||||
|
46 | <div> | |||
|
47 | ${h.secure_form(h.url('edit_user_group_advanced_sync', user_group_id=c.user_group.users_group_id), method='post')} | |||
|
48 | <div class="field"> | |||
|
49 | <button class="btn btn-default" type="submit"> | |||
|
50 | %if sync_type: | |||
|
51 | ${_('Disable synchronization')} | |||
|
52 | %else: | |||
|
53 | ${_('Enable synchronization')} | |||
|
54 | %endif | |||
|
55 | </button> | |||
|
56 | </div> | |||
|
57 | <div class="field"> | |||
|
58 | <span class="help-block"> | |||
|
59 | %if sync_type: | |||
|
60 | ${_('User group will no longer synchronize membership')} | |||
|
61 | %else: | |||
|
62 | ${_('User group will start to synchronize membership')} | |||
|
63 | %endif | |||
|
64 | </span> | |||
|
65 | </div> | |||
|
66 | ${h.end_form()} | |||
|
67 | </div> | |||
|
68 | ||||
|
69 | </div> | |||
|
70 | </div> | |||
|
71 | ||||
|
72 | ||||
24 | <div class="panel panel-danger"> |
|
73 | <div class="panel panel-danger"> | |
25 | <div class="panel-heading"> |
|
74 | <div class="panel-heading"> | |
26 | <h3 class="panel-title">${_('Delete User Group')}</h3> |
|
75 | <h3 class="panel-title">${_('Delete User Group')}</h3> |
@@ -58,8 +58,10 b'' | |||||
58 | { data: {"_": "members", |
|
58 | { data: {"_": "members", | |
59 | "sort": "members", |
|
59 | "sort": "members", | |
60 | "type": Number}, title: "${_('Members')}", className: "td-number" }, |
|
60 | "type": Number}, title: "${_('Members')}", className: "td-number" }, | |
|
61 | { data: {"_": "sync", | |||
|
62 | "sort": "sync"}, title: "${_('Sync')}", className: "td-sync" }, | |||
61 | { data: {"_": "active", |
|
63 | { data: {"_": "active", | |
62 |
"sort": "active"}, title: "${_('Active')}", className: "td-active" |
|
64 | "sort": "active"}, title: "${_('Active')}", className: "td-active" }, | |
63 | { data: {"_": "owner", |
|
65 | { data: {"_": "owner", | |
64 | "sort": "owner"}, title: "${_('Owner')}", className: "td-user" }, |
|
66 | "sort": "owner"}, title: "${_('Owner')}", className: "td-user" }, | |
65 | { data: {"_": "action", |
|
67 | { data: {"_": "action", |
@@ -21,7 +21,7 b'' | |||||
21 | import pytest |
|
21 | import pytest | |
22 |
|
22 | |||
23 | from rhodecode.tests import ( |
|
23 | from rhodecode.tests import ( | |
24 | TestController, url, assert_session_flash, link_to) |
|
24 | TestController, url, assert_session_flash, link_to, TEST_USER_ADMIN_LOGIN) | |
25 | from rhodecode.model.db import User, UserGroup |
|
25 | from rhodecode.model.db import User, UserGroup | |
26 | from rhodecode.model.meta import Session |
|
26 | from rhodecode.model.meta import Session | |
27 | from rhodecode.tests.fixture import Fixture |
|
27 | from rhodecode.tests.fixture import Fixture | |
@@ -56,6 +56,41 b' class TestAdminUsersGroupsController(Tes' | |||||
56 | response, |
|
56 | response, | |
57 | 'Created user group %s' % user_group_link) |
|
57 | 'Created user group %s' % user_group_link) | |
58 |
|
58 | |||
|
59 | def test_set_synchronization(self): | |||
|
60 | self.log_user() | |||
|
61 | users_group_name = TEST_USER_GROUP + 'sync' | |||
|
62 | response = self.app.post(url('users_groups'), { | |||
|
63 | 'users_group_name': users_group_name, | |||
|
64 | 'user_group_description': 'DESC', | |||
|
65 | 'active': True, | |||
|
66 | 'csrf_token': self.csrf_token}) | |||
|
67 | ||||
|
68 | group = Session().query(UserGroup).filter( | |||
|
69 | UserGroup.users_group_name == users_group_name).one() | |||
|
70 | ||||
|
71 | assert group.group_data.get('extern_type') is None | |||
|
72 | ||||
|
73 | # enable | |||
|
74 | self.app.post( | |||
|
75 | url('edit_user_group_advanced_sync', user_group_id=group.users_group_id), | |||
|
76 | params={'csrf_token': self.csrf_token}, status=302) | |||
|
77 | ||||
|
78 | group = Session().query(UserGroup).filter( | |||
|
79 | UserGroup.users_group_name == users_group_name).one() | |||
|
80 | assert group.group_data.get('extern_type') == 'manual' | |||
|
81 | assert group.group_data.get('extern_type_set_by') == TEST_USER_ADMIN_LOGIN | |||
|
82 | ||||
|
83 | # disable | |||
|
84 | self.app.post( | |||
|
85 | url('edit_user_group_advanced_sync', | |||
|
86 | user_group_id=group.users_group_id), | |||
|
87 | params={'csrf_token': self.csrf_token}, status=302) | |||
|
88 | ||||
|
89 | group = Session().query(UserGroup).filter( | |||
|
90 | UserGroup.users_group_name == users_group_name).one() | |||
|
91 | assert group.group_data.get('extern_type') is None | |||
|
92 | assert group.group_data.get('extern_type_set_by') == TEST_USER_ADMIN_LOGIN | |||
|
93 | ||||
59 | def test_delete(self): |
|
94 | def test_delete(self): | |
60 | self.log_user() |
|
95 | self.log_user() | |
61 | users_group_name = TEST_USER_GROUP + 'another' |
|
96 | users_group_name = TEST_USER_GROUP + 'another' | |
@@ -77,7 +112,7 b' class TestAdminUsersGroupsController(Tes' | |||||
77 | group = Session().query(UserGroup).filter( |
|
112 | group = Session().query(UserGroup).filter( | |
78 | UserGroup.users_group_name == users_group_name).one() |
|
113 | UserGroup.users_group_name == users_group_name).one() | |
79 |
|
114 | |||
80 |
|
|
115 | self.app.post( | |
81 | url('delete_users_group', user_group_id=group.users_group_id), |
|
116 | url('delete_users_group', user_group_id=group.users_group_id), | |
82 | params={'_method': 'delete', 'csrf_token': self.csrf_token}) |
|
117 | params={'_method': 'delete', 'csrf_token': self.csrf_token}) | |
83 |
|
118 |
General Comments 0
You need to be logged in to leave comments.
Login now