diff --git a/grunt_config.json b/grunt_config.json
--- a/grunt_config.json
+++ b/grunt_config.json
@@ -67,7 +67,6 @@
"<%= dirs.js.src %>/rhodecode/utils/ie.js",
"<%= dirs.js.src %>/rhodecode/utils/os.js",
"<%= dirs.js.src %>/rhodecode/utils/topics.js",
- "<%= dirs.js.src %>/rhodecode/widgets/multiselect.js",
"<%= dirs.js.src %>/rhodecode/init.js",
"<%= dirs.js.src %>/rhodecode/codemirror.js",
"<%= dirs.js.src %>/rhodecode/comments.js",
diff --git a/rhodecode/config/routing.py b/rhodecode/config/routing.py
--- a/rhodecode/config/routing.py
+++ b/rhodecode/config/routing.py
@@ -305,7 +305,7 @@ def make_map(config):
m.connect('delete_user', '/users/{user_id}',
action='delete', conditions={'method': ['DELETE']})
m.connect('edit_user', '/users/{user_id}/edit',
- action='edit', conditions={'method': ['GET']})
+ action='edit', conditions={'method': ['GET']}, jsroute=True)
m.connect('user', '/users/{user_id}',
action='show', conditions={'method': ['GET']})
m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
@@ -389,7 +389,7 @@ def make_map(config):
m.connect('edit_user_group_members',
'/user_groups/{user_group_id}/edit/members', jsroute=True,
- action='edit_members', conditions={'method': ['GET']})
+ action='user_group_members', conditions={'method': ['GET']})
# ADMIN PERMISSIONS ROUTES
with rmap.submapper(path_prefix=ADMIN_PREFIX,
diff --git a/rhodecode/controllers/admin/user_groups.py b/rhodecode/controllers/admin/user_groups.py
--- a/rhodecode/controllers/admin/user_groups.py
+++ b/rhodecode/controllers/admin/user_groups.py
@@ -25,6 +25,7 @@ User Groups crud controller for pylons
import logging
import formencode
+import peppercorn
from formencode import htmlfill
from pylons import request, tmpl_context as c, url, config
from pylons.controllers.util import redirect
@@ -40,7 +41,7 @@ from rhodecode.lib.utils import jsonify,
from rhodecode.lib.utils2 import safe_unicode, str2bool, safe_int
from rhodecode.lib.auth import (
LoginRequired, NotAnonymous, HasUserGroupPermissionAnyDecorator,
- HasPermissionAnyDecorator)
+ HasPermissionAnyDecorator, XHRRequired)
from rhodecode.lib.base import BaseController, render
from rhodecode.model.permission import PermissionModel
from rhodecode.model.scm import UserGroupList
@@ -69,13 +70,8 @@ class UserGroupsController(BaseControlle
def __load_data(self, user_group_id):
c.group_members_obj = [x.user for x in c.user_group.members]
c.group_members_obj.sort(key=lambda u: u.username.lower())
-
c.group_members = [(x.user_id, x.username) for x in c.group_members_obj]
- c.available_members = [(x.user_id, x.username)
- for x in User.query().all()]
- c.available_members.sort(key=lambda u: u[1].lower())
-
def __load_defaults(self, user_group_id):
"""
Load defaults settings for edit, and update
@@ -207,20 +203,21 @@ class UserGroupsController(BaseControlle
c.active = 'settings'
self.__load_data(user_group_id)
- available_members = [safe_unicode(x[0]) for x in c.available_members]
-
users_group_form = UserGroupForm(
- edit=True, old_data=c.user_group.get_dict(),
- available_members=available_members, allow_disabled=True)()
+ edit=True, old_data=c.user_group.get_dict(), allow_disabled=True)()
try:
form_result = users_group_form.to_python(request.POST)
+ pstruct = peppercorn.parse(request.POST.items())
+ form_result['users_group_members'] = pstruct['user_group_members']
+
UserGroupModel().update(c.user_group, form_result)
- gr = form_result['users_group_name']
+ updated_user_group = form_result['users_group_name']
action_logger(c.rhodecode_user,
- 'admin_updated_users_group:%s' % gr,
+ 'admin_updated_users_group:%s' % updated_user_group,
None, self.ip_addr, self.sa)
- h.flash(_('Updated user group %s') % gr, category='success')
+ h.flash(_('Updated user group %s') % updated_user_group,
+ category='success')
Session().commit()
except formencode.Invalid as errors:
defaults = errors.value
@@ -462,19 +459,29 @@ class UserGroupsController(BaseControlle
return render('admin/user_groups/user_group_edit.html')
@HasUserGroupPermissionAnyDecorator('usergroup.admin')
- def edit_members(self, user_group_id):
+ @XHRRequired()
+ @jsonify
+ def user_group_members(self, user_group_id):
user_group_id = safe_int(user_group_id)
- c.user_group = UserGroup.get_or_404(user_group_id)
- c.active = 'members'
- c.group_members_obj = sorted((x.user for x in c.user_group.members),
- key=lambda u: u.username.lower())
+ user_group = UserGroup.get_or_404(user_group_id)
+ group_members_obj = sorted((x.user for x in user_group.members),
+ key=lambda u: u.username.lower())
- group_members = [(x.user_id, x.username) for x in c.group_members_obj]
+ group_members = [
+ {
+ 'id': user.user_id,
+ 'first_name': user.name,
+ 'last_name': user.lastname,
+ 'username': user.username,
+ 'icon_link': h.gravatar_url(user.email, 30),
+ 'value_display': h.person(user.email),
+ 'value': user.username,
+ 'value_type': 'user',
+ 'active': user.active,
+ }
+ for user in group_members_obj
+ ]
- if request.is_xhr:
- return jsonify(lambda *a, **k: {
- 'members': group_members
- })
-
- c.group_members = group_members
- return render('admin/user_groups/user_group_edit.html')
+ return {
+ 'members': group_members
+ }
diff --git a/rhodecode/model/forms.py b/rhodecode/model/forms.py
--- a/rhodecode/model/forms.py
+++ b/rhodecode/model/forms.py
@@ -143,10 +143,8 @@ def UserForm(edit=False, available_langu
return _UserForm
-def UserGroupForm(edit=False, old_data=None, available_members=None,
- allow_disabled=False):
+def UserGroupForm(edit=False, old_data=None, allow_disabled=False):
old_data = old_data or {}
- available_members = available_members or []
class _UserGroupForm(formencode.Schema):
allow_extra_fields = True
@@ -162,10 +160,6 @@ def UserGroupForm(edit=False, old_data=N
users_group_active = v.StringBoolean(if_missing=False)
if edit:
- users_group_members = v.OneOf(
- available_members, hideList=False, testValueList=True,
- if_missing=None, not_empty=False
- )
# this is user group owner
user = All(
v.UnicodeString(not_empty=True),
diff --git a/rhodecode/model/user_group.py b/rhodecode/model/user_group.py
--- a/rhodecode/model/user_group.py
+++ b/rhodecode/model/user_group.py
@@ -189,18 +189,15 @@ class UserGroupModel(BaseModel):
self._log_user_changes('removed from', user_group, removed)
def _clean_members_data(self, members_data):
- # TODO: anderson: this should be in the form validation but I couldn't
- # make it work there as it conflicts with the other validator
if not members_data:
members_data = []
- if isinstance(members_data, basestring):
- new_members = [members_data]
- else:
- new_members = members_data
-
- new_members = [int(uid) for uid in new_members]
- return new_members
+ members = []
+ for user in members_data:
+ uid = int(user['member_user_id'])
+ if uid not in members and user['type'] in ['new', 'existing']:
+ members.append(uid)
+ return members
def update(self, user_group, form_data):
user_group = self._get_user_group(user_group)
diff --git a/rhodecode/public/css/main.less b/rhodecode/public/css/main.less
--- a/rhodecode/public/css/main.less
+++ b/rhodecode/public/css/main.less
@@ -1370,7 +1370,27 @@ table.integrations {
margin-right: .5em;
margin-left: 3px;
}
+
+ .to-delete {
+ .user {
+ text-decoration: line-through;
+ }
+ }
}
+
+// new entry in group_members
+.td-author-new-entry {
+ background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
+}
+
+.usergroup_member_remove {
+ width: 16px;
+ margin-bottom: 10px;
+ padding: 0;
+ color: black !important;
+ cursor: pointer;
+}
+
.reviewer_ac .ac-input {
width: 92%;
margin-bottom: 1em;
diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js
--- a/rhodecode/public/js/rhodecode/routes.js
+++ b/rhodecode/public/js/rhodecode/routes.js
@@ -16,6 +16,7 @@ function registerRCRoutes() {
pyroutes.register('user_autocomplete_data', '/_users', []);
pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
pyroutes.register('new_repo', '/_admin/create_repository', []);
+ pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
pyroutes.register('gists', '/_admin/gists', []);
pyroutes.register('new_gist', '/_admin/gists/new', []);
diff --git a/rhodecode/public/js/src/rhodecode/widgets/multiselect.js b/rhodecode/public/js/src/rhodecode/widgets/multiselect.js
deleted file mode 100644
--- a/rhodecode/public/js/src/rhodecode/widgets/multiselect.js
+++ /dev/null
@@ -1,132 +0,0 @@
-// # Copyright (C) 2010-2016 RhodeCode GmbH
-// #
-// # This program is free software: you can redistribute it and/or modify
-// # it under the terms of the GNU Affero General Public License, version 3
-// # (only), as published by the Free Software Foundation.
-// #
-// # This program is distributed in the hope that it will be useful,
-// # but WITHOUT ANY WARRANTY; without even the implied warranty of
-// # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// # GNU General Public License for more details.
-// #
-// # You should have received a copy of the GNU Affero General Public License
-// # along with this program. If not, see
Username | -Name | -
---|---|
-
- ${base.gravatar(user.email, 16)}
- ${h.link_to(user.username, h.url( 'edit_user',user_id=user.user_id))}
-
- |
- ${user.full_name} | -
${_('No members yet')}
- %endif -${_('Username')} | +${_('Action')} | +
---|---|
+
+ ${base.gravatar(user.email, 16)}
+ ${h.link_to(h.person(user), h.url( 'edit_user',user_id=user.user_id))}
+
+
+
+
+
+ |
+ + | + +
${_('No members yet')} |