diff --git a/rhodecode/apps/home/views.py b/rhodecode/apps/home/views.py --- a/rhodecode/apps/home/views.py +++ b/rhodecode/apps/home/views.py @@ -53,6 +53,7 @@ class HomeView(BaseAppView): query = self.request.GET.get('query') active = str2bool(self.request.GET.get('active') or True) include_groups = str2bool(self.request.GET.get('user_groups')) + expand_groups = str2bool(self.request.GET.get('user_groups_expand')) log.debug('generating user list, query:%s, active:%s, with_groups:%s', query, active, include_groups) @@ -63,7 +64,8 @@ class HomeView(BaseAppView): if include_groups: # extend with user groups _user_groups = UserGroupModel().get_user_groups( - name_contains=query, only_active=active) + name_contains=query, only_active=active, + expand_groups=expand_groups) _users = _users + _user_groups return {'suggestions': _users} @@ -76,11 +78,14 @@ class HomeView(BaseAppView): def user_group_autocomplete_data(self): query = self.request.GET.get('query') active = str2bool(self.request.GET.get('active') or True) + expand_groups = str2bool(self.request.GET.get('user_groups_expand')) + log.debug('generating user group list, query:%s, active:%s', query, active) _user_groups = UserGroupModel().get_user_groups( - name_contains=query, only_active=active) + name_contains=query, only_active=active, + expand_groups=expand_groups) _user_groups = _user_groups return {'suggestions': _user_groups} diff --git a/rhodecode/model/user.py b/rhodecode/model/user.py --- a/rhodecode/model/user.py +++ b/rhodecode/model/user.py @@ -65,8 +65,23 @@ class UserModel(BaseModel): def get_user(self, user): return self._get_user(user) + def _serialize_user(self, user): + import rhodecode.lib.helpers as h + + return { + 'id': user.user_id, + 'first_name': user.name, + 'last_name': user.lastname, + 'username': user.username, + 'email': user.email, + 'icon_link': h.gravatar_url(user.email, 30), + 'value_display': h.person(user), + 'value': user.username, + 'value_type': 'user', + 'active': user.active, + } + def get_users(self, name_contains=None, limit=20, only_active=True): - import rhodecode.lib.helpers as h query = self.sa.query(User) if only_active: @@ -85,19 +100,7 @@ class UserModel(BaseModel): users = query.all() _users = [ - { - 'id': user.user_id, - 'first_name': user.name, - 'last_name': user.lastname, - 'username': user.username, - 'email': user.email, - 'icon_link': h.gravatar_url(user.email, 30), - 'value_display': h.person(user), - 'value': user.username, - 'value_type': 'user', - 'active': user.active, - } - for user in users + self._serialize_user(user) for user in users ] return _users 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 @@ -30,12 +30,14 @@ import traceback from rhodecode.lib.utils2 import safe_str, safe_unicode from rhodecode.model import BaseModel from rhodecode.model.scm import UserGroupList -from rhodecode.model.db import true, func, UserGroupMember, UserGroup,\ - UserGroupRepoToPerm, Permission, UserGroupToPerm, User, UserUserGroupToPerm,\ - UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm -from rhodecode.lib.exceptions import UserGroupAssignedException,\ - RepoGroupAssignmentError -from rhodecode.lib.utils2 import get_current_rhodecode_user, action_logger_generic +from rhodecode.model.db import ( + true, func, User, UserGroupMember, UserGroup, + UserGroupRepoToPerm, Permission, UserGroupToPerm, UserUserGroupToPerm, + UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm) +from rhodecode.lib.exceptions import ( + UserGroupAssignedException, RepoGroupAssignmentError) +from rhodecode.lib.utils2 import ( + get_current_rhodecode_user, action_logger_generic) log = logging.getLogger(__name__) @@ -113,7 +115,7 @@ class UserGroupModel(BaseModel): if member_type == 'user': self.revoke_user_permission(user_group=user_group, user=member_id) else: - #check if we have permissions to alter this usergroup + # check if we have permissions to alter this usergroup member_name = UserGroup.get(member_id).users_group_name if not check_perms or HasUserGroupPermissionAny(*req_perms)(member_name, user=cur_user): self.revoke_user_group_permission( @@ -540,10 +542,28 @@ class UserGroupModel(BaseModel): log.debug('Adding user %s to user group %s', user.username, gr.users_group_name) UserGroupModel().add_user_to_group(gr.users_group_name, user.username) + def _serialize_user_group(self, user_group): + import rhodecode.lib.helpers as h + return { + 'id': user_group.users_group_id, + # TODO: marcink figure out a way to generate the url for the + # icon + 'icon_link': '', + 'value_display': 'Group: %s (%d members)' % ( + user_group.users_group_name, len(user_group.members),), + 'value': user_group.users_group_name, + 'description': user_group.user_group_description, + 'owner': user_group.user.username, + + 'owner_icon': h.gravatar_url(user_group.user.email, 30), + 'value_display_owner': h.person(user_group.user.email), + + 'value_type': 'user_group', + 'active': user_group.users_group_active, + } + def get_user_groups(self, name_contains=None, limit=20, only_active=True, expand_groups=False): - import rhodecode.lib.helpers as h - query = self.sa.query(UserGroup) if only_active: query = query.filter(UserGroup.users_group_active == true()) @@ -560,26 +580,19 @@ class UserGroupModel(BaseModel): perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin'] user_groups = UserGroupList(user_groups, perm_set=perm_set) - _groups = [ - { - 'id': group.users_group_id, - # TODO: marcink figure out a way to generate the url for the - # icon - 'icon_link': '', - 'value_display': 'Group: %s (%d members)' % ( - group.users_group_name, len(group.members),), - 'value': group.users_group_name, - 'description': group.user_group_description, - 'owner': group.user.username, + # store same serialize method to extract data from User + from rhodecode.model.user import UserModel + serialize_user = UserModel()._serialize_user - 'owner_icon': h.gravatar_url(group.user.email, 30), - 'value_display_owner': h.person(group.user.email), - - 'value_type': 'user_group', - 'active': group.users_group_active, - } - for group in user_groups - ] + _groups = [] + for group in user_groups: + entry = self._serialize_user_group(group) + if expand_groups: + expanded_members = [] + for member in group.members: + expanded_members.append(serialize_user(member.user)) + entry['members'] = expanded_members + _groups.append(entry) return _groups @staticmethod diff --git a/rhodecode/public/js/src/rhodecode/pullrequests.js b/rhodecode/public/js/src/rhodecode/pullrequests.js --- a/rhodecode/public/js/src/rhodecode/pullrequests.js +++ b/rhodecode/public/js/src/rhodecode/pullrequests.js @@ -198,8 +198,8 @@ var initPullRequestsCodeMirror = functio /** * Reviewer autocomplete */ -var ReviewerAutoComplete = function(input_id) { - $('#'+input_id).autocomplete({ +var ReviewerAutoComplete = function(inputId) { + $(inputId).autocomplete({ serviceUrl: pyroutes.url('user_autocomplete_data'), minChars:2, maxHeight:400, @@ -207,14 +207,26 @@ var ReviewerAutoComplete = function(inpu showNoSuggestionNotice: true, tabDisabled: true, autoSelectFirst: true, + params: { user_id: templateContext.rhodecode_user.user_id, user_groups:true, user_groups_expand:true }, formatResult: autocompleteFormatResult, lookupFilter: autocompleteFilterResult, - onSelect: function(suggestion, data){ - var msg = _gettext('added manually by "{0}"'); - var reasons = [msg.format(templateContext.rhodecode_user.username)]; - addReviewMember(data.id, data.first_name, data.last_name, - data.username, data.icon_link, reasons); - $('#'+input_id).val(''); + onSelect: function(element, data) { + + var reasons = [_gettext('added manually by "{0}"').format(templateContext.rhodecode_user.username)]; + if (data.value_type == 'user_group') { + reasons.push(_gettext('member of "{0}"').format(data.value_display)); + + $.each(data.members, function(index, member_data) { + addReviewMember(member_data.id, member_data.first_name, member_data.last_name, + member_data.username, member_data.icon_link, reasons); + }) + + } else { + addReviewMember(data.id, data.first_name, data.last_name, + data.username, data.icon_link, reasons); + } + + $(inputId).val(''); } }); }; diff --git a/rhodecode/templates/debug_style/collapsable-content.html b/rhodecode/templates/debug_style/collapsable-content.html --- a/rhodecode/templates/debug_style/collapsable-content.html +++ b/rhodecode/templates/debug_style/collapsable-content.html @@ -886,7 +886,7 @@ AJAX_COMMENT_DELETE_URL = "/rhodecode-momentum/pull-request-comment/__COMMENT_ID__/delete"; $(function(){ - ReviewerAutoComplete('user'); + ReviewerAutoComplete('#user'); $('#open_edit_reviewers').on('click', function(e){ $('#open_edit_reviewers').hide(); diff --git a/rhodecode/templates/pullrequests/pullrequest.mako b/rhodecode/templates/pullrequests/pullrequest.mako --- a/rhodecode/templates/pullrequests/pullrequest.mako +++ b/rhodecode/templates/pullrequests/pullrequest.mako @@ -115,7 +115,7 @@