pull-request-reviewers: added option to add reviewers by picking an user group for pull requests.

- fixes #5228
This commit is contained in:
Marcin Kuzminski 2017-04-19 17:30:07 +02:00
parent a3ed262ffd
commit 0b80fe66c9
7 changed files with 90 additions and 57 deletions

View file

@ -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}

View file

@ -65,9 +65,24 @@ class UserModel(BaseModel):
def get_user(self, user):
return self._get_user(user)
def get_users(self, name_contains=None, limit=20, only_active=True):
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):
query = self.sa.query(User)
if only_active:
query = query.filter(User.active == true())
@ -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

View file

@ -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

View file

@ -198,8 +198,8 @@ var initPullRequestsCodeMirror = function (textAreaId) {
/**
* 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(input_id) {
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('');
}
});
};

View file

@ -886,7 +886,7 @@ $(document).ready(function() {
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();

View file

@ -115,7 +115,7 @@
<input type="hidden" name="__end__" value="review_members:sequence">
<div id="add_reviewer_input" class='ac'>
<div class="reviewer_ac">
${h.text('user', class_='ac-input', placeholder=_('Add reviewer'))}
${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
<div id="reviewers_container"></div>
</div>
</div>
@ -584,7 +584,7 @@ $(function(){
loadDefaultReviewers();
% endif
ReviewerAutoComplete('user');
ReviewerAutoComplete('#user');
});
</script>

View file

@ -363,7 +363,7 @@
<div id="add_reviewer_input" class='ac' style="display: none;">
%if c.allowed_to_update:
<div class="reviewer_ac">
${h.text('user', class_='ac-input', placeholder=_('Add reviewer'))}
${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
<div id="reviewers_container"></div>
</div>
<div>
@ -617,7 +617,7 @@
$(function(){
ReviewerAutoComplete('user');
ReviewerAutoComplete('#user');
// custom code mirror
var codeMirrorInstance = initPullRequestsCodeMirror('#pr-description-input');