Show More
@@ -67,7 +67,6 b'' | |||
|
67 | 67 | "<%= dirs.js.src %>/rhodecode/utils/ie.js", |
|
68 | 68 | "<%= dirs.js.src %>/rhodecode/utils/os.js", |
|
69 | 69 | "<%= dirs.js.src %>/rhodecode/utils/topics.js", |
|
70 | "<%= dirs.js.src %>/rhodecode/widgets/multiselect.js", | |
|
71 | 70 | "<%= dirs.js.src %>/rhodecode/init.js", |
|
72 | 71 | "<%= dirs.js.src %>/rhodecode/codemirror.js", |
|
73 | 72 | "<%= dirs.js.src %>/rhodecode/comments.js", |
@@ -305,7 +305,7 b' def make_map(config):' | |||
|
305 | 305 | m.connect('delete_user', '/users/{user_id}', |
|
306 | 306 | action='delete', conditions={'method': ['DELETE']}) |
|
307 | 307 | m.connect('edit_user', '/users/{user_id}/edit', |
|
308 | action='edit', conditions={'method': ['GET']}) | |
|
308 | action='edit', conditions={'method': ['GET']}, jsroute=True) | |
|
309 | 309 | m.connect('user', '/users/{user_id}', |
|
310 | 310 | action='show', conditions={'method': ['GET']}) |
|
311 | 311 | m.connect('force_password_reset_user', '/users/{user_id}/password_reset', |
@@ -389,7 +389,7 b' def make_map(config):' | |||
|
389 | 389 | |
|
390 | 390 | m.connect('edit_user_group_members', |
|
391 | 391 | '/user_groups/{user_group_id}/edit/members', jsroute=True, |
|
392 |
action=' |
|
|
392 | action='user_group_members', conditions={'method': ['GET']}) | |
|
393 | 393 | |
|
394 | 394 | # ADMIN PERMISSIONS ROUTES |
|
395 | 395 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
@@ -25,6 +25,7 b' User Groups crud controller for pylons' | |||
|
25 | 25 | import logging |
|
26 | 26 | import formencode |
|
27 | 27 | |
|
28 | import peppercorn | |
|
28 | 29 | from formencode import htmlfill |
|
29 | 30 | from pylons import request, tmpl_context as c, url, config |
|
30 | 31 | from pylons.controllers.util import redirect |
@@ -40,7 +41,7 b' from rhodecode.lib.utils import jsonify,' | |||
|
40 | 41 | from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int |
|
41 | 42 | from rhodecode.lib.auth import ( |
|
42 | 43 | LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator, |
|
43 | HasPermissionAnyDecorator) | |
|
44 | HasPermissionAnyDecorator, XHRRequired) | |
|
44 | 45 | from rhodecode.lib.base import BaseController, render |
|
45 | 46 | from rhodecode.model.permission import PermissionModel |
|
46 | 47 | from rhodecode.model.scm import UserGroupList |
@@ -69,13 +70,8 b' class UserGroupsController(BaseControlle' | |||
|
69 | 70 | def __load_data(self, user_group_id): |
|
70 | 71 | c.group_members_obj = [x.user for x in c.user_group.members] |
|
71 | 72 | c.group_members_obj.sort(key=lambda u: u.username.lower()) |
|
72 | ||
|
73 | 73 | c.group_members = [(x.user_id, x.username) for x in c.group_members_obj] |
|
74 | 74 | |
|
75 | c.available_members = [(x.user_id, x.username) | |
|
76 | for x in User.query().all()] | |
|
77 | c.available_members.sort(key=lambda u: u[1].lower()) | |
|
78 | ||
|
79 | 75 | def __load_defaults(self, user_group_id): |
|
80 | 76 | """ |
|
81 | 77 | Load defaults settings for edit, and update |
@@ -207,20 +203,21 b' class UserGroupsController(BaseControlle' | |||
|
207 | 203 | c.active = 'settings' |
|
208 | 204 | self.__load_data(user_group_id) |
|
209 | 205 | |
|
210 | available_members = [safe_unicode(x[0]) for x in c.available_members] | |
|
211 | ||
|
212 | 206 | users_group_form = UserGroupForm( |
|
213 | edit=True, old_data=c.user_group.get_dict(), | |
|
214 | available_members=available_members, allow_disabled=True)() | |
|
207 | edit=True, old_data=c.user_group.get_dict(), allow_disabled=True)() | |
|
215 | 208 | |
|
216 | 209 | try: |
|
217 | 210 | form_result = users_group_form.to_python(request.POST) |
|
211 | pstruct = peppercorn.parse(request.POST.items()) | |
|
212 | form_result['users_group_members'] = pstruct['user_group_members'] | |
|
213 | ||
|
218 | 214 | UserGroupModel().update(c.user_group, form_result) |
|
219 | gr = form_result['users_group_name'] | |
|
215 | updated_user_group = form_result['users_group_name'] | |
|
220 | 216 | action_logger(c.rhodecode_user, |
|
221 | 'admin_updated_users_group:%s' % gr, | |
|
217 | 'admin_updated_users_group:%s' % updated_user_group, | |
|
222 | 218 | None, self.ip_addr, self.sa) |
|
223 |
h.flash(_('Updated user group %s') % gr, |
|
|
219 | h.flash(_('Updated user group %s') % updated_user_group, | |
|
220 | category='success') | |
|
224 | 221 | Session().commit() |
|
225 | 222 | except formencode.Invalid as errors: |
|
226 | 223 | defaults = errors.value |
@@ -462,19 +459,29 b' class UserGroupsController(BaseControlle' | |||
|
462 | 459 | return render('admin/user_groups/user_group_edit.html') |
|
463 | 460 | |
|
464 | 461 | @HasUserGroupPermissionAnyDecorator('usergroup.admin') |
|
465 | def edit_members(self, user_group_id): | |
|
462 | @XHRRequired() | |
|
463 | @jsonify | |
|
464 | def user_group_members(self, user_group_id): | |
|
466 | 465 | user_group_id = safe_int(user_group_id) |
|
467 |
|
|
|
468 | c.active = 'members' | |
|
469 | c.group_members_obj = sorted((x.user for x in c.user_group.members), | |
|
470 | key=lambda u: u.username.lower()) | |
|
466 | user_group = UserGroup.get_or_404(user_group_id) | |
|
467 | group_members_obj = sorted((x.user for x in user_group.members), | |
|
468 | key=lambda u: u.username.lower()) | |
|
471 | 469 | |
|
472 | group_members = [(x.user_id, x.username) for x in c.group_members_obj] | |
|
470 | group_members = [ | |
|
471 | { | |
|
472 | 'id': user.user_id, | |
|
473 | 'first_name': user.name, | |
|
474 | 'last_name': user.lastname, | |
|
475 | 'username': user.username, | |
|
476 | 'icon_link': h.gravatar_url(user.email, 30), | |
|
477 | 'value_display': h.person(user.email), | |
|
478 | 'value': user.username, | |
|
479 | 'value_type': 'user', | |
|
480 | 'active': user.active, | |
|
481 | } | |
|
482 | for user in group_members_obj | |
|
483 | ] | |
|
473 | 484 | |
|
474 | if request.is_xhr: | |
|
475 | return jsonify(lambda *a, **k: { | |
|
476 | 'members': group_members | |
|
477 | }) | |
|
478 | ||
|
479 | c.group_members = group_members | |
|
480 | return render('admin/user_groups/user_group_edit.html') | |
|
485 | return { | |
|
486 | 'members': group_members | |
|
487 | } |
@@ -143,10 +143,8 b' def UserForm(edit=False, available_langu' | |||
|
143 | 143 | return _UserForm |
|
144 | 144 | |
|
145 | 145 | |
|
146 |
def UserGroupForm(edit=False, old_data=None, a |
|
|
147 | allow_disabled=False): | |
|
146 | def UserGroupForm(edit=False, old_data=None, allow_disabled=False): | |
|
148 | 147 | old_data = old_data or {} |
|
149 | available_members = available_members or [] | |
|
150 | 148 | |
|
151 | 149 | class _UserGroupForm(formencode.Schema): |
|
152 | 150 | allow_extra_fields = True |
@@ -162,10 +160,6 b' def UserGroupForm(edit=False, old_data=N' | |||
|
162 | 160 | users_group_active = v.StringBoolean(if_missing=False) |
|
163 | 161 | |
|
164 | 162 | if edit: |
|
165 | users_group_members = v.OneOf( | |
|
166 | available_members, hideList=False, testValueList=True, | |
|
167 | if_missing=None, not_empty=False | |
|
168 | ) | |
|
169 | 163 | # this is user group owner |
|
170 | 164 | user = All( |
|
171 | 165 | v.UnicodeString(not_empty=True), |
@@ -189,18 +189,15 b' class UserGroupModel(BaseModel):' | |||
|
189 | 189 | self._log_user_changes('removed from', user_group, removed) |
|
190 | 190 | |
|
191 | 191 | def _clean_members_data(self, members_data): |
|
192 | # TODO: anderson: this should be in the form validation but I couldn't | |
|
193 | # make it work there as it conflicts with the other validator | |
|
194 | 192 | if not members_data: |
|
195 | 193 | members_data = [] |
|
196 | 194 | |
|
197 | if isinstance(members_data, basestring): | |
|
198 |
|
|
|
199 | else: | |
|
200 | new_members = members_data | |
|
201 | ||
|
202 | new_members = [int(uid) for uid in new_members] | |
|
203 | return new_members | |
|
195 | members = [] | |
|
196 | for user in members_data: | |
|
197 | uid = int(user['member_user_id']) | |
|
198 | if uid not in members and user['type'] in ['new', 'existing']: | |
|
199 | members.append(uid) | |
|
200 | return members | |
|
204 | 201 | |
|
205 | 202 | def update(self, user_group, form_data): |
|
206 | 203 | user_group = self._get_user_group(user_group) |
@@ -1370,7 +1370,27 b' table.integrations {' | |||
|
1370 | 1370 | margin-right: .5em; |
|
1371 | 1371 | margin-left: 3px; |
|
1372 | 1372 | } |
|
1373 | ||
|
1374 | .to-delete { | |
|
1375 | .user { | |
|
1376 | text-decoration: line-through; | |
|
1377 | } | |
|
1378 | } | |
|
1373 | 1379 | } |
|
1380 | ||
|
1381 | // new entry in group_members | |
|
1382 | .td-author-new-entry { | |
|
1383 | background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3); | |
|
1384 | } | |
|
1385 | ||
|
1386 | .usergroup_member_remove { | |
|
1387 | width: 16px; | |
|
1388 | margin-bottom: 10px; | |
|
1389 | padding: 0; | |
|
1390 | color: black !important; | |
|
1391 | cursor: pointer; | |
|
1392 | } | |
|
1393 | ||
|
1374 | 1394 | .reviewer_ac .ac-input { |
|
1375 | 1395 | width: 92%; |
|
1376 | 1396 | margin-bottom: 1em; |
@@ -16,6 +16,7 b' function registerRCRoutes() {' | |||
|
16 | 16 | pyroutes.register('user_autocomplete_data', '/_users', []); |
|
17 | 17 | pyroutes.register('user_group_autocomplete_data', '/_user_groups', []); |
|
18 | 18 | pyroutes.register('new_repo', '/_admin/create_repository', []); |
|
19 | pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']); | |
|
19 | 20 | pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']); |
|
20 | 21 | pyroutes.register('gists', '/_admin/gists', []); |
|
21 | 22 | pyroutes.register('new_gist', '/_admin/gists/new', []); |
@@ -35,7 +35,6 b'' | |||
|
35 | 35 | <li class="${'active' if c.active=='advanced' else ''}"><a href="${h.url('edit_user_group_advanced', user_group_id=c.user_group.users_group_id)}">${_('Advanced')}</a></li> |
|
36 | 36 | <li class="${'active' if c.active=='global_perms' else ''}"><a href="${h.url('edit_user_group_global_perms', user_group_id=c.user_group.users_group_id)}">${_('Global permissions')}</a></li> |
|
37 | 37 | <li class="${'active' if c.active=='perms_summary' else ''}"><a href="${h.url('edit_user_group_perms_summary', user_group_id=c.user_group.users_group_id)}">${_('Permissions summary')}</a></li> |
|
38 | <li class="${'active' if c.active=='members' else ''}"><a href="${h.url('edit_user_group_members', user_group_id=c.user_group.users_group_id)}">${_('Members')}</a></li> | |
|
39 | 38 | </ul> |
|
40 | 39 | </div> |
|
41 | 40 |
@@ -54,40 +54,53 b'' | |||
|
54 | 54 | ${h.checkbox('users_group_active',value=True)} |
|
55 | 55 | </div> |
|
56 | 56 | </div> |
|
57 | <div class="field"> | |
|
58 |
|
|
|
59 | <label for="users_group_active">${_('Search')}:</label> | |
|
60 | ${h.text('from_user_group', | |
|
61 | placeholder="user/usergroup", | |
|
62 |
|
|
|
57 | ||
|
58 | <div class="field"> | |
|
59 | <div class="label label-checkbox"> | |
|
60 | <label for="users_group_active">${_('Add members')}:</label> | |
|
61 | </div> | |
|
62 | <div class="input"> | |
|
63 | ${h.text('user_group_add_members', placeholder="user/usergroup", class_="medium")} | |
|
63 | 64 | </div> |
|
64 | <div class="select side-by-side-selector"> | |
|
65 | <div class="left-group"> | |
|
66 | <label class="text"><strong>${_('Chosen group members')}</strong></label> | |
|
67 | ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,)} | |
|
68 | <div class="btn" id="remove_all_elements" > | |
|
69 |
|
|
|
70 | <i class="icon-chevron-right"></i> | |
|
71 |
|
|
|
72 | </div> | |
|
73 |
|
|
|
74 | <i id="add_element" class="icon-chevron-left"></i> | |
|
75 |
|
|
|
76 |
|
|
|
77 |
< |
|
|
78 | <div class="right-group"> | |
|
79 | <label class="text" >${_('Available users')} | |
|
80 | </label> | |
|
81 | ${h.select('available_members',[],c.available_members,multiple=True,size=8,)} | |
|
82 | <div class="btn" id="add_all_elements" > | |
|
83 | <i class="icon-chevron-left"></i>${_('Add all elements')} | |
|
84 |
|
|
|
85 |
</d |
|
|
86 |
< |
|
|
87 | </div> | |
|
88 |
< |
|
|
89 | ${h.submit('Save',_('Save'),class_="btn")} | |
|
90 |
</d |
|
|
65 | </div> | |
|
66 | ||
|
67 | <input type="hidden" name="__start__" value="user_group_members:sequence"/> | |
|
68 | <table id="group_members_placeholder" class="rctable group_members"> | |
|
69 | <tr> | |
|
70 | <th>${_('Username')}</th> | |
|
71 | <th>${_('Action')}</th> | |
|
72 | </tr> | |
|
73 | ||
|
74 | % if c.group_members_obj: | |
|
75 | % for user in c.group_members_obj: | |
|
76 | <tr> | |
|
77 | <td id="member_user_${user.user_id}" class="td-author"> | |
|
78 | <div class="group_member"> | |
|
79 | ${base.gravatar(user.email, 16)} | |
|
80 | <span class="username user">${h.link_to(h.person(user), h.url( 'edit_user',user_id=user.user_id))}</span> | |
|
81 | <input type="hidden" name="__start__" value="member:mapping"> | |
|
82 | <input type="hidden" name="member_user_id" value="${user.user_id}"> | |
|
83 | <input type="hidden" name="type" value="existing" id="member_${user.user_id}"> | |
|
84 | <input type="hidden" name="__end__" value="member:mapping"> | |
|
85 | </div> | |
|
86 | </td> | |
|
87 | <td class=""> | |
|
88 | <div class="usergroup_member_remove action_button" onclick="removeUserGroupMember(${user.user_id}, true)" style="visibility: visible;"> | |
|
89 | <i class="icon-remove-sign"></i> | |
|
90 | </div> | |
|
91 | </td> | |
|
92 | </tr> | |
|
93 | % endfor | |
|
94 | ||
|
95 | % else: | |
|
96 | <tr><td colspan="2">${_('No members yet')}</td></tr> | |
|
97 | % endif | |
|
98 | </table> | |
|
99 | <input type="hidden" name="__end__" value="user_group_members:sequence"/> | |
|
100 | ||
|
101 | <div class="buttons"> | |
|
102 | ${h.submit('Save',_('Save'),class_="btn")} | |
|
103 | </div> | |
|
91 | 104 | </div> |
|
92 | 105 | </div> |
|
93 | 106 | ${h.end_form()} |
@@ -95,15 +108,18 b'' | |||
|
95 | 108 | </div> |
|
96 | 109 | <script> |
|
97 | 110 | $(document).ready(function(){ |
|
98 | MultiSelectWidget('users_group_members','available_members','edit_users_group'); | |
|
99 | ||
|
100 | 111 | $("#group_parent_id").select2({ |
|
101 | 112 | 'containerCssClass': "drop-menu", |
|
102 | 113 | 'dropdownCssClass': "drop-menu-dropdown", |
|
103 | 114 | 'dropdownAutoWidth': true |
|
104 | 115 | }); |
|
105 | 116 | |
|
106 | $('#from_user_group').autocomplete({ | |
|
117 | removeUserGroupMember = function(userId){ | |
|
118 | $('#member_'+userId).val('remove'); | |
|
119 | $('#member_user_'+userId).addClass('to-delete'); | |
|
120 | }; | |
|
121 | ||
|
122 | $('#user_group_add_members').autocomplete({ | |
|
107 | 123 | serviceUrl: pyroutes.url('user_autocomplete_data'), |
|
108 | 124 | minChars:2, |
|
109 | 125 | maxHeight:400, |
@@ -115,9 +131,37 b'' | |||
|
115 | 131 | lookupFilter: autocompleteFilterResult, |
|
116 | 132 | onSelect: function(element, suggestion){ |
|
117 | 133 | |
|
118 |
function |
|
|
119 | $('#available_members').val(uids); | |
|
120 |
|
|
|
134 | function addMember(user, fromUserGroup) { | |
|
135 | var gravatar = user.icon_link; | |
|
136 | var username = user.value_display; | |
|
137 | var userLink = pyroutes.url('edit_user', {"user_id": user.id}); | |
|
138 | var uid = user.id; | |
|
139 | ||
|
140 | if (fromUserGroup) { | |
|
141 | username = username +" "+ _gettext('(from usergroup {0})'.format(fromUserGroup)) | |
|
142 | } | |
|
143 | ||
|
144 | var elem = $( | |
|
145 | ('<tr>'+ | |
|
146 | '<td id="member_user_{6}" class="td-author td-author-new-entry">'+ | |
|
147 | '<div class="group_member">'+ | |
|
148 | '<img class="gravatar" src="{0}" height="16" width="16">'+ | |
|
149 | '<span class="username user"><a href="{1}">{2}</a></span>'+ | |
|
150 | '<input type="hidden" name="__start__" value="member:mapping">'+ | |
|
151 | '<input type="hidden" name="member_user_id" value="{3}">'+ | |
|
152 | '<input type="hidden" name="type" value="new" id="member_{4}">'+ | |
|
153 | '<input type="hidden" name="__end__" value="member:mapping">'+ | |
|
154 | '</div>'+ | |
|
155 | '</td>'+ | |
|
156 | '<td class="td-author-new-entry">'+ | |
|
157 | '<div class="usergroup_member_remove action_button" onclick="removeUserGroupMember({5}, true)" style="visibility: visible;">'+ | |
|
158 | '<i class="icon-remove-sign"></i>'+ | |
|
159 | '</div>'+ | |
|
160 | '</td>'+ | |
|
161 | '</tr>').format(gravatar, userLink, username, | |
|
162 | uid, uid, uid, uid) | |
|
163 | ); | |
|
164 | $('#group_members_placeholder').append(elem) | |
|
121 | 165 | } |
|
122 | 166 | |
|
123 | 167 | if (suggestion.value_type == 'user_group') { |
@@ -125,20 +169,18 b'' | |||
|
125 | 169 | pyroutes.url('edit_user_group_members', |
|
126 | 170 | {'user_group_id': suggestion.id}), |
|
127 | 171 | function(data) { |
|
128 | var uids = []; | |
|
129 | 172 | $.each(data.members, function(idx, user) { |
|
130 |
|
|
|
131 | username = user[1]; | |
|
132 | uids.push(userid.toString()); | |
|
173 | addMember(user, suggestion.value) | |
|
133 | 174 | }); |
|
134 | preSelectUserIds(uids) | |
|
135 | 175 | } |
|
136 | 176 | ); |
|
137 | 177 | } else if (suggestion.value_type == 'user') { |
|
138 |
|
|
|
178 | addMember(suggestion, null); | |
|
139 | 179 | } |
|
140 | 180 | } |
|
141 | 181 | }); |
|
182 | ||
|
183 | ||
|
142 | 184 | UsersAutoComplete('user', '${c.rhodecode_user.user_id}'); |
|
143 | 185 | }) |
|
144 | 186 | </script> |
@@ -545,12 +545,6 b'' | |||
|
545 | 545 | </div> |
|
546 | 546 | </div> |
|
547 | 547 | |
|
548 | <script> | |
|
549 | $(document).ready(function(){ | |
|
550 | MultiSelectWidget('users_group_members','available_members','edit_users_group'); | |
|
551 | }) | |
|
552 | </script> | |
|
553 | ||
|
554 | 548 | </div> |
|
555 | 549 | |
|
556 | 550 | <div class='field'> |
@@ -595,12 +589,6 b'' | |||
|
595 | 589 | </div> |
|
596 | 590 | </div> |
|
597 | 591 | |
|
598 | <script> | |
|
599 | $(document).ready(function(){ | |
|
600 | MultiSelectWidget('users_group_members2','available_members','edit_users_group'); | |
|
601 | }) | |
|
602 | </script> | |
|
603 | ||
|
604 | 592 | </div> |
|
605 | 593 | |
|
606 | 594 | <div class='field'> |
@@ -36,7 +36,7 b' class TestAdminUsersGroupsController(Tes' | |||
|
36 | 36 | def test_index(self): |
|
37 | 37 | self.log_user() |
|
38 | 38 | response = self.app.get(url('users_groups')) |
|
39 | response.status_int == 200 | |
|
39 | assert response.status_int == 200 | |
|
40 | 40 | |
|
41 | 41 | def test_create(self): |
|
42 | 42 | self.log_user() |
@@ -148,19 +148,21 b' class TestAdminUsersGroupsController(Tes' | |||
|
148 | 148 | |
|
149 | 149 | fixture.destroy_user_group(users_group_name) |
|
150 | 150 | |
|
151 | def test_edit(self): | |
|
151 | def test_edit_autocomplete(self): | |
|
152 | 152 | self.log_user() |
|
153 | 153 | ug = fixture.create_user_group(TEST_USER_GROUP, skip_if_exists=True) |
|
154 | 154 | response = self.app.get( |
|
155 | 155 | url('edit_users_group', user_group_id=ug.users_group_id)) |
|
156 | 156 | fixture.destroy_user_group(TEST_USER_GROUP) |
|
157 | 157 | |
|
158 | def test_edit_user_group_members(self): | |
|
158 | def test_edit_user_group_autocomplete_members(self, xhr_header): | |
|
159 | 159 | self.log_user() |
|
160 | 160 | ug = fixture.create_user_group(TEST_USER_GROUP, skip_if_exists=True) |
|
161 | 161 | response = self.app.get( |
|
162 |
url('edit_user_group_members', user_group_id=ug.users_group_id) |
|
|
163 | response.mustcontain('No members yet') | |
|
162 | url('edit_user_group_members', user_group_id=ug.users_group_id), | |
|
163 | extra_environ=xhr_header) | |
|
164 | ||
|
165 | assert response.body == '{"members": []}' | |
|
164 | 166 | fixture.destroy_user_group(TEST_USER_GROUP) |
|
165 | 167 | |
|
166 | 168 | def test_usergroup_escape(self): |
@@ -181,7 +183,7 b' class TestAdminUsersGroupsController(Tes' | |||
|
181 | 183 | 'csrf_token': self.csrf_token |
|
182 | 184 | } |
|
183 | 185 | |
|
184 |
|
|
|
186 | self.app.post(url('users_groups'), data) | |
|
185 | 187 | response = self.app.get(url('users_groups')) |
|
186 | 188 | |
|
187 | 189 | response.mustcontain( |
@@ -190,3 +192,42 b' class TestAdminUsersGroupsController(Tes' | |||
|
190 | 192 | response.mustcontain( |
|
191 | 193 | '<img src="/image2" onload="' |
|
192 | 194 | 'alert('Hello, World!');">') |
|
195 | ||
|
196 | def test_update_members_from_user_ids(self, user_regular): | |
|
197 | uid = user_regular.user_id | |
|
198 | username = user_regular.username | |
|
199 | self.log_user() | |
|
200 | ||
|
201 | user_group = fixture.create_user_group('test_gr_ids') | |
|
202 | assert user_group.members == [] | |
|
203 | assert user_group.user != user_regular | |
|
204 | expected_active_state = not user_group.users_group_active | |
|
205 | ||
|
206 | form_data = [ | |
|
207 | ('csrf_token', self.csrf_token), | |
|
208 | ('_method', 'put'), | |
|
209 | ('user', username), | |
|
210 | ('users_group_name', 'changed_name'), | |
|
211 | ('users_group_active', expected_active_state), | |
|
212 | ('user_group_description', 'changed_description'), | |
|
213 | ||
|
214 | ('__start__', 'user_group_members:sequence'), | |
|
215 | ('__start__', 'member:mapping'), | |
|
216 | ('member_user_id', uid), | |
|
217 | ('type', 'existing'), | |
|
218 | ('__end__', 'member:mapping'), | |
|
219 | ('__end__', 'user_group_members:sequence'), | |
|
220 | ] | |
|
221 | ugid = user_group.users_group_id | |
|
222 | self.app.post(url('update_users_group', user_group_id=ugid), form_data) | |
|
223 | ||
|
224 | user_group = UserGroup.get(ugid) | |
|
225 | assert user_group | |
|
226 | ||
|
227 | assert user_group.members[0].user_id == uid | |
|
228 | assert user_group.user_id == uid | |
|
229 | assert 'changed_name' in user_group.users_group_name | |
|
230 | assert 'changed_description' in user_group.user_group_description | |
|
231 | assert user_group.users_group_active == expected_active_state | |
|
232 | ||
|
233 | fixture.destroy_user_group(user_group) |
@@ -113,40 +113,20 b' def test_add_and_remove_user_from_group(' | |||
|
113 | 113 | assert user_group.members == [] |
|
114 | 114 | |
|
115 | 115 | |
|
116 | @pytest.mark.parametrize( | |
|
117 | 'data, expected', [ | |
|
118 | ("1", [1]), (["1", "2"], [1, 2]) | |
|
119 | ] | |
|
120 | ) | |
|
116 | @pytest.mark.parametrize('data, expected', [ | |
|
117 | ([], []), | |
|
118 | ([{"member_user_id": 1, "type": "new"}], [1]), | |
|
119 | ([{"member_user_id": 1, "type": "new"}, | |
|
120 | {"member_user_id": 1, "type": "existing"}], [1]), | |
|
121 | ([{"member_user_id": 1, "type": "new"}, | |
|
122 | {"member_user_id": 2, "type": "new"}, | |
|
123 | {"member_user_id": 3, "type": "remove"}], [1, 2]) | |
|
124 | ]) | |
|
121 | 125 | def test_clean_members_data(data, expected): |
|
122 | 126 | cleaned = UserGroupModel()._clean_members_data(data) |
|
123 | 127 | assert cleaned == expected |
|
124 | 128 | |
|
125 | 129 | |
|
126 | def test_update_members_from_user_ids(user_regular, user_util): | |
|
127 | user_group = user_util.create_user_group() | |
|
128 | assert user_group.members == [] | |
|
129 | assert user_group.user != user_regular | |
|
130 | expected_active_state = not user_group.users_group_active | |
|
131 | ||
|
132 | form_data = { | |
|
133 | 'users_group_members': str(user_regular.user_id), | |
|
134 | 'user': str(user_regular.username), | |
|
135 | 'users_group_name': 'changed_name', | |
|
136 | 'users_group_active': expected_active_state, | |
|
137 | 'user_group_description': 'changed_description' | |
|
138 | } | |
|
139 | ||
|
140 | UserGroupModel().update(user_group, form_data) | |
|
141 | assert user_group.members[0].user_id == user_regular.user_id | |
|
142 | assert user_group.user_id == user_regular.user_id | |
|
143 | assert 'changed_name' in user_group.users_group_name | |
|
144 | assert 'changed_description' in user_group.user_group_description | |
|
145 | assert user_group.users_group_active == expected_active_state | |
|
146 | # Ignore changes on the test | |
|
147 | Session().rollback() | |
|
148 | ||
|
149 | ||
|
150 | 130 | def _create_test_members(): |
|
151 | 131 | members = [] |
|
152 | 132 | for member_number in range(3): |
@@ -38,6 +38,7 b' import requests' | |||
|
38 | 38 | from webtest.app import TestApp |
|
39 | 39 | |
|
40 | 40 | import rhodecode |
|
41 | from rhodecode.lib.utils2 import AttributeDict | |
|
41 | 42 | from rhodecode.model.changeset_status import ChangesetStatusModel |
|
42 | 43 | from rhodecode.model.comment import ChangesetCommentsModel |
|
43 | 44 | from rhodecode.model.db import ( |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now