##// END OF EJS Templates
pull-request-reviewers: added option to add reviewers by picking an user group for pull requests....
marcink -
r1678:7e2afc04 default
parent child Browse files
Show More
@@ -53,6 +53,7 b' class HomeView(BaseAppView):'
53 query = self.request.GET.get('query')
53 query = self.request.GET.get('query')
54 active = str2bool(self.request.GET.get('active') or True)
54 active = str2bool(self.request.GET.get('active') or True)
55 include_groups = str2bool(self.request.GET.get('user_groups'))
55 include_groups = str2bool(self.request.GET.get('user_groups'))
56 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
56
57
57 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
58 log.debug('generating user list, query:%s, active:%s, with_groups:%s',
58 query, active, include_groups)
59 query, active, include_groups)
@@ -63,7 +64,8 b' class HomeView(BaseAppView):'
63 if include_groups:
64 if include_groups:
64 # extend with user groups
65 # extend with user groups
65 _user_groups = UserGroupModel().get_user_groups(
66 _user_groups = UserGroupModel().get_user_groups(
66 name_contains=query, only_active=active)
67 name_contains=query, only_active=active,
68 expand_groups=expand_groups)
67 _users = _users + _user_groups
69 _users = _users + _user_groups
68
70
69 return {'suggestions': _users}
71 return {'suggestions': _users}
@@ -76,11 +78,14 b' class HomeView(BaseAppView):'
76 def user_group_autocomplete_data(self):
78 def user_group_autocomplete_data(self):
77 query = self.request.GET.get('query')
79 query = self.request.GET.get('query')
78 active = str2bool(self.request.GET.get('active') or True)
80 active = str2bool(self.request.GET.get('active') or True)
81 expand_groups = str2bool(self.request.GET.get('user_groups_expand'))
82
79 log.debug('generating user group list, query:%s, active:%s',
83 log.debug('generating user group list, query:%s, active:%s',
80 query, active)
84 query, active)
81
85
82 _user_groups = UserGroupModel().get_user_groups(
86 _user_groups = UserGroupModel().get_user_groups(
83 name_contains=query, only_active=active)
87 name_contains=query, only_active=active,
88 expand_groups=expand_groups)
84 _user_groups = _user_groups
89 _user_groups = _user_groups
85
90
86 return {'suggestions': _user_groups}
91 return {'suggestions': _user_groups}
@@ -65,8 +65,23 b' class UserModel(BaseModel):'
65 def get_user(self, user):
65 def get_user(self, user):
66 return self._get_user(user)
66 return self._get_user(user)
67
67
68 def _serialize_user(self, user):
69 import rhodecode.lib.helpers as h
70
71 return {
72 'id': user.user_id,
73 'first_name': user.name,
74 'last_name': user.lastname,
75 'username': user.username,
76 'email': user.email,
77 'icon_link': h.gravatar_url(user.email, 30),
78 'value_display': h.person(user),
79 'value': user.username,
80 'value_type': 'user',
81 'active': user.active,
82 }
83
68 def get_users(self, name_contains=None, limit=20, only_active=True):
84 def get_users(self, name_contains=None, limit=20, only_active=True):
69 import rhodecode.lib.helpers as h
70
85
71 query = self.sa.query(User)
86 query = self.sa.query(User)
72 if only_active:
87 if only_active:
@@ -85,19 +100,7 b' class UserModel(BaseModel):'
85 users = query.all()
100 users = query.all()
86
101
87 _users = [
102 _users = [
88 {
103 self._serialize_user(user) for user in users
89 'id': user.user_id,
90 'first_name': user.name,
91 'last_name': user.lastname,
92 'username': user.username,
93 'email': user.email,
94 'icon_link': h.gravatar_url(user.email, 30),
95 'value_display': h.person(user),
96 'value': user.username,
97 'value_type': 'user',
98 'active': user.active,
99 }
100 for user in users
101 ]
104 ]
102 return _users
105 return _users
103
106
@@ -30,12 +30,14 b' import traceback'
30 from rhodecode.lib.utils2 import safe_str, safe_unicode
30 from rhodecode.lib.utils2 import safe_str, safe_unicode
31 from rhodecode.model import BaseModel
31 from rhodecode.model import BaseModel
32 from rhodecode.model.scm import UserGroupList
32 from rhodecode.model.scm import UserGroupList
33 from rhodecode.model.db import true, func, UserGroupMember, UserGroup,\
33 from rhodecode.model.db import (
34 UserGroupRepoToPerm, Permission, UserGroupToPerm, User, UserUserGroupToPerm,\
34 true, func, User, UserGroupMember, UserGroup,
35 UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm
35 UserGroupRepoToPerm, Permission, UserGroupToPerm, UserUserGroupToPerm,
36 from rhodecode.lib.exceptions import UserGroupAssignedException,\
36 UserGroupUserGroupToPerm, UserGroupRepoGroupToPerm)
37 RepoGroupAssignmentError
37 from rhodecode.lib.exceptions import (
38 from rhodecode.lib.utils2 import get_current_rhodecode_user, action_logger_generic
38 UserGroupAssignedException, RepoGroupAssignmentError)
39 from rhodecode.lib.utils2 import (
40 get_current_rhodecode_user, action_logger_generic)
39
41
40 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
41
43
@@ -540,10 +542,28 b' class UserGroupModel(BaseModel):'
540 log.debug('Adding user %s to user group %s', user.username, gr.users_group_name)
542 log.debug('Adding user %s to user group %s', user.username, gr.users_group_name)
541 UserGroupModel().add_user_to_group(gr.users_group_name, user.username)
543 UserGroupModel().add_user_to_group(gr.users_group_name, user.username)
542
544
545 def _serialize_user_group(self, user_group):
546 import rhodecode.lib.helpers as h
547 return {
548 'id': user_group.users_group_id,
549 # TODO: marcink figure out a way to generate the url for the
550 # icon
551 'icon_link': '',
552 'value_display': 'Group: %s (%d members)' % (
553 user_group.users_group_name, len(user_group.members),),
554 'value': user_group.users_group_name,
555 'description': user_group.user_group_description,
556 'owner': user_group.user.username,
557
558 'owner_icon': h.gravatar_url(user_group.user.email, 30),
559 'value_display_owner': h.person(user_group.user.email),
560
561 'value_type': 'user_group',
562 'active': user_group.users_group_active,
563 }
564
543 def get_user_groups(self, name_contains=None, limit=20, only_active=True,
565 def get_user_groups(self, name_contains=None, limit=20, only_active=True,
544 expand_groups=False):
566 expand_groups=False):
545 import rhodecode.lib.helpers as h
546
547 query = self.sa.query(UserGroup)
567 query = self.sa.query(UserGroup)
548 if only_active:
568 if only_active:
549 query = query.filter(UserGroup.users_group_active == true())
569 query = query.filter(UserGroup.users_group_active == true())
@@ -560,26 +580,19 b' class UserGroupModel(BaseModel):'
560 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
580 perm_set = ['usergroup.read', 'usergroup.write', 'usergroup.admin']
561 user_groups = UserGroupList(user_groups, perm_set=perm_set)
581 user_groups = UserGroupList(user_groups, perm_set=perm_set)
562
582
563 _groups = [
583 # store same serialize method to extract data from User
564 {
584 from rhodecode.model.user import UserModel
565 'id': group.users_group_id,
585 serialize_user = UserModel()._serialize_user
566 # TODO: marcink figure out a way to generate the url for the
567 # icon
568 'icon_link': '',
569 'value_display': 'Group: %s (%d members)' % (
570 group.users_group_name, len(group.members),),
571 'value': group.users_group_name,
572 'description': group.user_group_description,
573 'owner': group.user.username,
574
586
575 'owner_icon': h.gravatar_url(group.user.email, 30),
587 _groups = []
576 'value_display_owner': h.person(group.user.email),
588 for group in user_groups:
577
589 entry = self._serialize_user_group(group)
578 'value_type': 'user_group',
590 if expand_groups:
579 'active': group.users_group_active,
591 expanded_members = []
580 }
592 for member in group.members:
581 for group in user_groups
593 expanded_members.append(serialize_user(member.user))
582 ]
594 entry['members'] = expanded_members
595 _groups.append(entry)
583 return _groups
596 return _groups
584
597
585 @staticmethod
598 @staticmethod
@@ -198,8 +198,8 b' var initPullRequestsCodeMirror = functio'
198 /**
198 /**
199 * Reviewer autocomplete
199 * Reviewer autocomplete
200 */
200 */
201 var ReviewerAutoComplete = function(input_id) {
201 var ReviewerAutoComplete = function(inputId) {
202 $('#'+input_id).autocomplete({
202 $(inputId).autocomplete({
203 serviceUrl: pyroutes.url('user_autocomplete_data'),
203 serviceUrl: pyroutes.url('user_autocomplete_data'),
204 minChars:2,
204 minChars:2,
205 maxHeight:400,
205 maxHeight:400,
@@ -207,14 +207,26 b' var ReviewerAutoComplete = function(inpu'
207 showNoSuggestionNotice: true,
207 showNoSuggestionNotice: true,
208 tabDisabled: true,
208 tabDisabled: true,
209 autoSelectFirst: true,
209 autoSelectFirst: true,
210 params: { user_id: templateContext.rhodecode_user.user_id, user_groups:true, user_groups_expand:true },
210 formatResult: autocompleteFormatResult,
211 formatResult: autocompleteFormatResult,
211 lookupFilter: autocompleteFilterResult,
212 lookupFilter: autocompleteFilterResult,
212 onSelect: function(suggestion, data){
213 onSelect: function(element, data) {
213 var msg = _gettext('added manually by "{0}"');
214
214 var reasons = [msg.format(templateContext.rhodecode_user.username)];
215 var reasons = [_gettext('added manually by "{0}"').format(templateContext.rhodecode_user.username)];
216 if (data.value_type == 'user_group') {
217 reasons.push(_gettext('member of "{0}"').format(data.value_display));
218
219 $.each(data.members, function(index, member_data) {
220 addReviewMember(member_data.id, member_data.first_name, member_data.last_name,
221 member_data.username, member_data.icon_link, reasons);
222 })
223
224 } else {
215 addReviewMember(data.id, data.first_name, data.last_name,
225 addReviewMember(data.id, data.first_name, data.last_name,
216 data.username, data.icon_link, reasons);
226 data.username, data.icon_link, reasons);
217 $('#'+input_id).val('');
227 }
228
229 $(inputId).val('');
218 }
230 }
219 });
231 });
220 };
232 };
@@ -886,7 +886,7 b''
886 AJAX_COMMENT_DELETE_URL = "/rhodecode-momentum/pull-request-comment/__COMMENT_ID__/delete";
886 AJAX_COMMENT_DELETE_URL = "/rhodecode-momentum/pull-request-comment/__COMMENT_ID__/delete";
887
887
888 $(function(){
888 $(function(){
889 ReviewerAutoComplete('user');
889 ReviewerAutoComplete('#user');
890
890
891 $('#open_edit_reviewers').on('click', function(e){
891 $('#open_edit_reviewers').on('click', function(e){
892 $('#open_edit_reviewers').hide();
892 $('#open_edit_reviewers').hide();
@@ -115,7 +115,7 b''
115 <input type="hidden" name="__end__" value="review_members:sequence">
115 <input type="hidden" name="__end__" value="review_members:sequence">
116 <div id="add_reviewer_input" class='ac'>
116 <div id="add_reviewer_input" class='ac'>
117 <div class="reviewer_ac">
117 <div class="reviewer_ac">
118 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer'))}
118 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
119 <div id="reviewers_container"></div>
119 <div id="reviewers_container"></div>
120 </div>
120 </div>
121 </div>
121 </div>
@@ -584,7 +584,7 b''
584 loadDefaultReviewers();
584 loadDefaultReviewers();
585 % endif
585 % endif
586
586
587 ReviewerAutoComplete('user');
587 ReviewerAutoComplete('#user');
588 });
588 });
589 </script>
589 </script>
590
590
@@ -363,7 +363,7 b''
363 <div id="add_reviewer_input" class='ac' style="display: none;">
363 <div id="add_reviewer_input" class='ac' style="display: none;">
364 %if c.allowed_to_update:
364 %if c.allowed_to_update:
365 <div class="reviewer_ac">
365 <div class="reviewer_ac">
366 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer'))}
366 ${h.text('user', class_='ac-input', placeholder=_('Add reviewer or reviewer group'))}
367 <div id="reviewers_container"></div>
367 <div id="reviewers_container"></div>
368 </div>
368 </div>
369 <div>
369 <div>
@@ -617,7 +617,7 b''
617
617
618
618
619 $(function(){
619 $(function(){
620 ReviewerAutoComplete('user');
620 ReviewerAutoComplete('#user');
621 // custom code mirror
621 // custom code mirror
622 var codeMirrorInstance = initPullRequestsCodeMirror('#pr-description-input');
622 var codeMirrorInstance = initPullRequestsCodeMirror('#pr-description-input');
623
623
General Comments 0
You need to be logged in to leave comments. Login now