##// END OF EJS Templates
user-groups: new selector for user group memebers....
marcink -
r1089:4d236b89 default
parent child Browse files
Show More
@@ -67,7 +67,6 b''
67 "<%= dirs.js.src %>/rhodecode/utils/ie.js",
67 "<%= dirs.js.src %>/rhodecode/utils/ie.js",
68 "<%= dirs.js.src %>/rhodecode/utils/os.js",
68 "<%= dirs.js.src %>/rhodecode/utils/os.js",
69 "<%= dirs.js.src %>/rhodecode/utils/topics.js",
69 "<%= dirs.js.src %>/rhodecode/utils/topics.js",
70 "<%= dirs.js.src %>/rhodecode/widgets/multiselect.js",
71 "<%= dirs.js.src %>/rhodecode/init.js",
70 "<%= dirs.js.src %>/rhodecode/init.js",
72 "<%= dirs.js.src %>/rhodecode/codemirror.js",
71 "<%= dirs.js.src %>/rhodecode/codemirror.js",
73 "<%= dirs.js.src %>/rhodecode/comments.js",
72 "<%= dirs.js.src %>/rhodecode/comments.js",
@@ -305,7 +305,7 b' def make_map(config):'
305 m.connect('delete_user', '/users/{user_id}',
305 m.connect('delete_user', '/users/{user_id}',
306 action='delete', conditions={'method': ['DELETE']})
306 action='delete', conditions={'method': ['DELETE']})
307 m.connect('edit_user', '/users/{user_id}/edit',
307 m.connect('edit_user', '/users/{user_id}/edit',
308 action='edit', conditions={'method': ['GET']})
308 action='edit', conditions={'method': ['GET']}, jsroute=True)
309 m.connect('user', '/users/{user_id}',
309 m.connect('user', '/users/{user_id}',
310 action='show', conditions={'method': ['GET']})
310 action='show', conditions={'method': ['GET']})
311 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
311 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
@@ -389,7 +389,7 b' def make_map(config):'
389
389
390 m.connect('edit_user_group_members',
390 m.connect('edit_user_group_members',
391 '/user_groups/{user_group_id}/edit/members', jsroute=True,
391 '/user_groups/{user_group_id}/edit/members', jsroute=True,
392 action='edit_members', conditions={'method': ['GET']})
392 action='user_group_members', conditions={'method': ['GET']})
393
393
394 # ADMIN PERMISSIONS ROUTES
394 # ADMIN PERMISSIONS ROUTES
395 with rmap.submapper(path_prefix=ADMIN_PREFIX,
395 with rmap.submapper(path_prefix=ADMIN_PREFIX,
@@ -25,6 +25,7 b' User Groups crud controller for pylons'
25 import logging
25 import logging
26 import formencode
26 import formencode
27
27
28 import peppercorn
28 from formencode import htmlfill
29 from formencode import htmlfill
29 from pylons import request, tmpl_context as c, url, config
30 from pylons import request, tmpl_context as c, url, config
30 from pylons.controllers.util import redirect
31 from pylons.controllers.util import redirect
@@ -40,7 +41,7 b' from rhodecode.lib.utils import jsonify,'
40 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
41 from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
41 from rhodecode.lib.auth import (
42 from rhodecode.lib.auth import (
42 LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator,
43 LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator,
43 HasPermissionAnyDecorator)
44 HasPermissionAnyDecorator, XHRRequired)
44 from rhodecode.lib.base import BaseController, render
45 from rhodecode.lib.base import BaseController, render
45 from rhodecode.model.permission import PermissionModel
46 from rhodecode.model.permission import PermissionModel
46 from rhodecode.model.scm import UserGroupList
47 from rhodecode.model.scm import UserGroupList
@@ -69,13 +70,8 b' class UserGroupsController(BaseControlle'
69 def __load_data(self, user_group_id):
70 def __load_data(self, user_group_id):
70 c.group_members_obj = [x.user for x in c.user_group.members]
71 c.group_members_obj = [x.user for x in c.user_group.members]
71 c.group_members_obj.sort(key=lambda u: u.username.lower())
72 c.group_members_obj.sort(key=lambda u: u.username.lower())
72
73 c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
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 def __load_defaults(self, user_group_id):
75 def __load_defaults(self, user_group_id):
80 """
76 """
81 Load defaults settings for edit, and update
77 Load defaults settings for edit, and update
@@ -207,20 +203,21 b' class UserGroupsController(BaseControlle'
207 c.active = 'settings'
203 c.active = 'settings'
208 self.__load_data(user_group_id)
204 self.__load_data(user_group_id)
209
205
210 available_members = [safe_unicode(x[0]) for x in c.available_members]
211
212 users_group_form = UserGroupForm(
206 users_group_form = UserGroupForm(
213 edit=True, old_data=c.user_group.get_dict(),
207 edit=True, old_data=c.user_group.get_dict(), allow_disabled=True)()
214 available_members=available_members, allow_disabled=True)()
215
208
216 try:
209 try:
217 form_result = users_group_form.to_python(request.POST)
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 UserGroupModel().update(c.user_group, form_result)
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 action_logger(c.rhodecode_user,
216 action_logger(c.rhodecode_user,
221 'admin_updated_users_group:%s' % gr,
217 'admin_updated_users_group:%s' % updated_user_group,
222 None, self.ip_addr, self.sa)
218 None, self.ip_addr, self.sa)
223 h.flash(_('Updated user group %s') % gr, category='success')
219 h.flash(_('Updated user group %s') % updated_user_group,
220 category='success')
224 Session().commit()
221 Session().commit()
225 except formencode.Invalid as errors:
222 except formencode.Invalid as errors:
226 defaults = errors.value
223 defaults = errors.value
@@ -462,19 +459,29 b' class UserGroupsController(BaseControlle'
462 return render('admin/user_groups/user_group_edit.html')
459 return render('admin/user_groups/user_group_edit.html')
463
460
464 @HasUserGroupPermissionAnyDecorator('usergroup.admin')
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 user_group_id = safe_int(user_group_id)
465 user_group_id = safe_int(user_group_id)
467 c.user_group = UserGroup.get_or_404(user_group_id)
466 user_group = UserGroup.get_or_404(user_group_id)
468 c.active = 'members'
467 group_members_obj = sorted((x.user for x in user_group.members),
469 c.group_members_obj = sorted((x.user for x in c.user_group.members),
468 key=lambda u: u.username.lower())
470 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:
485 return {
475 return jsonify(lambda *a, **k: {
486 'members': group_members
476 'members': group_members
487 }
477 })
478
479 c.group_members = group_members
480 return render('admin/user_groups/user_group_edit.html')
@@ -143,10 +143,8 b' def UserForm(edit=False, available_langu'
143 return _UserForm
143 return _UserForm
144
144
145
145
146 def UserGroupForm(edit=False, old_data=None, available_members=None,
146 def UserGroupForm(edit=False, old_data=None, allow_disabled=False):
147 allow_disabled=False):
148 old_data = old_data or {}
147 old_data = old_data or {}
149 available_members = available_members or []
150
148
151 class _UserGroupForm(formencode.Schema):
149 class _UserGroupForm(formencode.Schema):
152 allow_extra_fields = True
150 allow_extra_fields = True
@@ -162,10 +160,6 b' def UserGroupForm(edit=False, old_data=N'
162 users_group_active = v.StringBoolean(if_missing=False)
160 users_group_active = v.StringBoolean(if_missing=False)
163
161
164 if edit:
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 # this is user group owner
163 # this is user group owner
170 user = All(
164 user = All(
171 v.UnicodeString(not_empty=True),
165 v.UnicodeString(not_empty=True),
@@ -189,18 +189,15 b' class UserGroupModel(BaseModel):'
189 self._log_user_changes('removed from', user_group, removed)
189 self._log_user_changes('removed from', user_group, removed)
190
190
191 def _clean_members_data(self, members_data):
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 if not members_data:
192 if not members_data:
195 members_data = []
193 members_data = []
196
194
197 if isinstance(members_data, basestring):
195 members = []
198 new_members = [members_data]
196 for user in members_data:
199 else:
197 uid = int(user['member_user_id'])
200 new_members = members_data
198 if uid not in members and user['type'] in ['new', 'existing']:
201
199 members.append(uid)
202 new_members = [int(uid) for uid in new_members]
200 return members
203 return new_members
204
201
205 def update(self, user_group, form_data):
202 def update(self, user_group, form_data):
206 user_group = self._get_user_group(user_group)
203 user_group = self._get_user_group(user_group)
@@ -1370,7 +1370,27 b' table.integrations {'
1370 margin-right: .5em;
1370 margin-right: .5em;
1371 margin-left: 3px;
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 .reviewer_ac .ac-input {
1394 .reviewer_ac .ac-input {
1375 width: 92%;
1395 width: 92%;
1376 margin-bottom: 1em;
1396 margin-bottom: 1em;
@@ -16,6 +16,7 b' function registerRCRoutes() {'
16 pyroutes.register('user_autocomplete_data', '/_users', []);
16 pyroutes.register('user_autocomplete_data', '/_users', []);
17 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
17 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
18 pyroutes.register('new_repo', '/_admin/create_repository', []);
18 pyroutes.register('new_repo', '/_admin/create_repository', []);
19 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
19 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
20 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
20 pyroutes.register('gists', '/_admin/gists', []);
21 pyroutes.register('gists', '/_admin/gists', []);
21 pyroutes.register('new_gist', '/_admin/gists/new', []);
22 pyroutes.register('new_gist', '/_admin/gists/new', []);
@@ -35,7 +35,6 b''
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>
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 <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>
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 <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>
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 </ul>
38 </ul>
40 </div>
39 </div>
41
40
@@ -54,40 +54,53 b''
54 ${h.checkbox('users_group_active',value=True)}
54 ${h.checkbox('users_group_active',value=True)}
55 </div>
55 </div>
56 </div>
56 </div>
57 <div class="field">
57
58 <div class="label">
58 <div class="field">
59 <label for="users_group_active">${_('Search')}:</label>
59 <div class="label label-checkbox">
60 ${h.text('from_user_group',
60 <label for="users_group_active">${_('Add members')}:</label>
61 placeholder="user/usergroup",
61 </div>
62 class_="medium")}
62 <div class="input">
63 ${h.text('user_group_add_members', placeholder="user/usergroup", class_="medium")}
63 </div>
64 </div>
64 <div class="select side-by-side-selector">
65 </div>
65 <div class="left-group">
66
66 <label class="text"><strong>${_('Chosen group members')}</strong></label>
67 <input type="hidden" name="__start__" value="user_group_members:sequence"/>
67 ${h.select('users_group_members',[x[0] for x in c.group_members],c.group_members,multiple=True,size=8,)}
68 <table id="group_members_placeholder" class="rctable group_members">
68 <div class="btn" id="remove_all_elements" >
69 <tr>
69 ${_('Remove all elements')}
70 <th>${_('Username')}</th>
70 <i class="icon-chevron-right"></i>
71 <th>${_('Action')}</th>
71 </div>
72 </tr>
72 </div>
73
73 <div class="middle-group">
74 % if c.group_members_obj:
74 <i id="add_element" class="icon-chevron-left"></i>
75 % for user in c.group_members_obj:
75 <br />
76 <tr>
76 <i id="remove_element" class="icon-chevron-right"></i>
77 <td id="member_user_${user.user_id}" class="td-author">
77 </div>
78 <div class="group_member">
78 <div class="right-group">
79 ${base.gravatar(user.email, 16)}
79 <label class="text" >${_('Available users')}
80 <span class="username user">${h.link_to(h.person(user), h.url( 'edit_user',user_id=user.user_id))}</span>
80 </label>
81 <input type="hidden" name="__start__" value="member:mapping">
81 ${h.select('available_members',[],c.available_members,multiple=True,size=8,)}
82 <input type="hidden" name="member_user_id" value="${user.user_id}">
82 <div class="btn" id="add_all_elements" >
83 <input type="hidden" name="type" value="existing" id="member_${user.user_id}">
83 <i class="icon-chevron-left"></i>${_('Add all elements')}
84 <input type="hidden" name="__end__" value="member:mapping">
84 </div>
85 </div>
85 </div>
86 </td>
86 </div>
87 <td class="">
87 </div>
88 <div class="usergroup_member_remove action_button" onclick="removeUserGroupMember(${user.user_id}, true)" style="visibility: visible;">
88 <div class="buttons">
89 <i class="icon-remove-sign"></i>
89 ${h.submit('Save',_('Save'),class_="btn")}
90 </div>
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 </div>
104 </div>
92 </div>
105 </div>
93 ${h.end_form()}
106 ${h.end_form()}
@@ -95,15 +108,18 b''
95 </div>
108 </div>
96 <script>
109 <script>
97 $(document).ready(function(){
110 $(document).ready(function(){
98 MultiSelectWidget('users_group_members','available_members','edit_users_group');
99
100 $("#group_parent_id").select2({
111 $("#group_parent_id").select2({
101 'containerCssClass': "drop-menu",
112 'containerCssClass': "drop-menu",
102 'dropdownCssClass': "drop-menu-dropdown",
113 'dropdownCssClass': "drop-menu-dropdown",
103 'dropdownAutoWidth': true
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 serviceUrl: pyroutes.url('user_autocomplete_data'),
123 serviceUrl: pyroutes.url('user_autocomplete_data'),
108 minChars:2,
124 minChars:2,
109 maxHeight:400,
125 maxHeight:400,
@@ -115,9 +131,37 b''
115 lookupFilter: autocompleteFilterResult,
131 lookupFilter: autocompleteFilterResult,
116 onSelect: function(element, suggestion){
132 onSelect: function(element, suggestion){
117
133
118 function preSelectUserIds(uids) {
134 function addMember(user, fromUserGroup) {
119 $('#available_members').val(uids);
135 var gravatar = user.icon_link;
120 $('#users_group_members').val(uids);
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 if (suggestion.value_type == 'user_group') {
167 if (suggestion.value_type == 'user_group') {
@@ -125,20 +169,18 b''
125 pyroutes.url('edit_user_group_members',
169 pyroutes.url('edit_user_group_members',
126 {'user_group_id': suggestion.id}),
170 {'user_group_id': suggestion.id}),
127 function(data) {
171 function(data) {
128 var uids = [];
129 $.each(data.members, function(idx, user) {
172 $.each(data.members, function(idx, user) {
130 var userid = user[0],
173 addMember(user, suggestion.value)
131 username = user[1];
132 uids.push(userid.toString());
133 });
174 });
134 preSelectUserIds(uids)
135 }
175 }
136 );
176 );
137 } else if (suggestion.value_type == 'user') {
177 } else if (suggestion.value_type == 'user') {
138 preSelectUserIds([suggestion.id.toString()]);
178 addMember(suggestion, null);
139 }
179 }
140 }
180 }
141 });
181 });
182
183
142 UsersAutoComplete('user', '${c.rhodecode_user.user_id}');
184 UsersAutoComplete('user', '${c.rhodecode_user.user_id}');
143 })
185 })
144 </script>
186 </script>
@@ -545,12 +545,6 b''
545 </div>
545 </div>
546 </div>
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 </div>
548 </div>
555
549
556 <div class='field'>
550 <div class='field'>
@@ -595,12 +589,6 b''
595 </div>
589 </div>
596 </div>
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 </div>
592 </div>
605
593
606 <div class='field'>
594 <div class='field'>
@@ -36,7 +36,7 b' class TestAdminUsersGroupsController(Tes'
36 def test_index(self):
36 def test_index(self):
37 self.log_user()
37 self.log_user()
38 response = self.app.get(url('users_groups'))
38 response = self.app.get(url('users_groups'))
39 response.status_int == 200
39 assert response.status_int == 200
40
40
41 def test_create(self):
41 def test_create(self):
42 self.log_user()
42 self.log_user()
@@ -148,19 +148,21 b' class TestAdminUsersGroupsController(Tes'
148
148
149 fixture.destroy_user_group(users_group_name)
149 fixture.destroy_user_group(users_group_name)
150
150
151 def test_edit(self):
151 def test_edit_autocomplete(self):
152 self.log_user()
152 self.log_user()
153 ug = fixture.create_user_group(TEST_USER_GROUP, skip_if_exists=True)
153 ug = fixture.create_user_group(TEST_USER_GROUP, skip_if_exists=True)
154 response = self.app.get(
154 response = self.app.get(
155 url('edit_users_group', user_group_id=ug.users_group_id))
155 url('edit_users_group', user_group_id=ug.users_group_id))
156 fixture.destroy_user_group(TEST_USER_GROUP)
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 self.log_user()
159 self.log_user()
160 ug = fixture.create_user_group(TEST_USER_GROUP, skip_if_exists=True)
160 ug = fixture.create_user_group(TEST_USER_GROUP, skip_if_exists=True)
161 response = self.app.get(
161 response = self.app.get(
162 url('edit_user_group_members', user_group_id=ug.users_group_id))
162 url('edit_user_group_members', user_group_id=ug.users_group_id),
163 response.mustcontain('No members yet')
163 extra_environ=xhr_header)
164
165 assert response.body == '{"members": []}'
164 fixture.destroy_user_group(TEST_USER_GROUP)
166 fixture.destroy_user_group(TEST_USER_GROUP)
165
167
166 def test_usergroup_escape(self):
168 def test_usergroup_escape(self):
@@ -181,7 +183,7 b' class TestAdminUsersGroupsController(Tes'
181 'csrf_token': self.csrf_token
183 'csrf_token': self.csrf_token
182 }
184 }
183
185
184 response = self.app.post(url('users_groups'), data)
186 self.app.post(url('users_groups'), data)
185 response = self.app.get(url('users_groups'))
187 response = self.app.get(url('users_groups'))
186
188
187 response.mustcontain(
189 response.mustcontain(
@@ -190,3 +192,42 b' class TestAdminUsersGroupsController(Tes'
190 response.mustcontain(
192 response.mustcontain(
191 '&lt;img src=&#34;/image2&#34; onload=&#34;'
193 '&lt;img src=&#34;/image2&#34; onload=&#34;'
192 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
194 'alert(&#39;Hello, World!&#39;);&#34;&gt;')
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 assert user_group.members == []
113 assert user_group.members == []
114
114
115
115
116 @pytest.mark.parametrize(
116 @pytest.mark.parametrize('data, expected', [
117 'data, expected', [
117 ([], []),
118 ("1", [1]), (["1", "2"], [1, 2])
118 ([{"member_user_id": 1, "type": "new"}], [1]),
119 ]
119 ([{"member_user_id": 1, "type": "new"},
120 )
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 def test_clean_members_data(data, expected):
125 def test_clean_members_data(data, expected):
122 cleaned = UserGroupModel()._clean_members_data(data)
126 cleaned = UserGroupModel()._clean_members_data(data)
123 assert cleaned == expected
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 def _create_test_members():
130 def _create_test_members():
151 members = []
131 members = []
152 for member_number in range(3):
132 for member_number in range(3):
@@ -38,6 +38,7 b' import requests'
38 from webtest.app import TestApp
38 from webtest.app import TestApp
39
39
40 import rhodecode
40 import rhodecode
41 from rhodecode.lib.utils2 import AttributeDict
41 from rhodecode.model.changeset_status import ChangesetStatusModel
42 from rhodecode.model.changeset_status import ChangesetStatusModel
42 from rhodecode.model.comment import ChangesetCommentsModel
43 from rhodecode.model.comment import ChangesetCommentsModel
43 from rhodecode.model.db import (
44 from rhodecode.model.db import (
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now