diff --git a/frontend/src/components/dialog/manage-members-dialog.js b/frontend/src/components/dialog/manage-members-dialog.js index 3885013b3d..0bbddd761a 100644 --- a/frontend/src/components/dialog/manage-members-dialog.js +++ b/frontend/src/components/dialog/manage-members-dialog.js @@ -1,6 +1,6 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; -import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Table } from 'reactstrap'; +import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Table, Input, Label, FormGroup } from 'reactstrap'; import { Utils } from '../../utils/utils'; import { gettext } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; @@ -31,7 +31,8 @@ class ManageMembersDialog extends React.Component { hasNextPage: false, selectedOption: null, errMessage: [], - isItemFreezed: false + isItemFreezed: false, + searchGroupMemberInputValue: '', }; } @@ -49,7 +50,7 @@ class ManageMembersDialog extends React.Component { isLoadingMore: false, page: page, hasNextPage: members.length < perPage ? false : true, - groupMembers: groupMembers.concat(members) + groupMembers: groupMembers.concat(members) }); }).catch(error => { let errMessage = Utils.getErrorMsg(error); @@ -92,6 +93,24 @@ class ManageMembersDialog extends React.Component { }); } + handleSearchGroupMemberInputChange = (e) => { + this.setState({ + searchGroupMemberInputValue: e.target.value + }); + } + + searchGroupMember = () => { + + seafileAPI.searchGroupMember(this.props.groupID, this.state.searchGroupMemberInputValue).then((res) => { + this.setState({ + groupMembers: res.data, + }); + }).catch(error => { + let errMessage = Utils.getErrorMsg(error); + toaster.danger(errMessage); + }); + } + toggleItemFreezed = (isFreezed) => { this.setState({ isItemFreezed: isFreezed @@ -112,10 +131,10 @@ class ManageMembersDialog extends React.Component { const isBottom = (clientHeight + scrollTop + 1 >= scrollHeight); if (isBottom) { // scroll to the bottom this.setState({isLoadingMore: true}, () => { - this.listGroupMembers(page + 1); - }); - } - } + this.listGroupMembers(page + 1); + }); + } + } } changeMember = (targetMember) => { @@ -143,20 +162,39 @@ class ManageMembersDialog extends React.Component { {gettext('Manage group members')} -

{gettext('Add group member')}

-
- - {this.state.selectedOption ? - : - - } -
+ +

{gettext('Add group member')}

+
+ + {this.state.selectedOption ? + : + + } +
+
+ +

{gettext('Search group member')}

+
+ + {this.state.searchGroupMemberInputValue ? + : + + } +
+
{ this.state.errMessage.length > 0 && this.state.errMessage.map((item, index = 0) => { diff --git a/frontend/src/css/manage-members-dialog.css b/frontend/src/css/manage-members-dialog.css index 265f31bdd2..8e553c1722 100644 --- a/frontend/src/css/manage-members-dialog.css +++ b/frontend/src/css/manage-members-dialog.css @@ -33,17 +33,22 @@ display: none; } -.add-members { +.add-members, +.search-members { display: flex; justify-content: space-between; } -.add-members .add-members-select { +.add-members .add-members-select, +.search-members .search-members-input { width: 385px; } -.add-members .btn { + +.add-members .btn, +.search-members .btn { width: 75px; } + .group-error { margin-top: 10px; } \ No newline at end of file diff --git a/seahub/api2/endpoints/group_members.py b/seahub/api2/endpoints/group_members.py index 725a1fe4d5..b5e0726a30 100644 --- a/seahub/api2/endpoints/group_members.py +++ b/seahub/api2/endpoints/group_members.py @@ -133,10 +133,42 @@ class GroupMembers(APIView): return Response(member_info, status=status.HTTP_201_CREATED) +class GroupSearchMember(APIView): + + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticated,) + throttle_classes = (UserRateThrottle,) + + @api_check_group + def get(self, request, group_id, format=None): + """ + Search group member by email. + """ + + q = request.GET.get('q', '') + if not q: + error_msg = 'q invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + if not is_group_member(group_id, request.user.username): + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + group_members = [] + members = ccnet_api.search_group_members(group_id, q) + for member in members: + + member_info = get_group_member_info(request, group_id, member.user_name) + + group_members.append(member_info) + + return Response(group_members) + + class GroupMember(APIView): authentication_classes = (TokenAuthentication, SessionAuthentication) permission_classes = (IsAuthenticated,) - throttle_classes = (UserRateThrottle, ) + throttle_classes = (UserRateThrottle,) @api_check_group def get(self, request, group_id, email): diff --git a/seahub/urls.py b/seahub/urls.py index 8ab11913a7..d9eeaa2f5f 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -36,7 +36,7 @@ from seahub.api2.endpoints.group_owned_libraries import GroupOwnedLibraries, \ from seahub.api2.endpoints.address_book.groups import AddressBookGroupsSubGroups from seahub.api2.endpoints.address_book.members import AddressBookGroupsSearchMember -from seahub.api2.endpoints.group_members import GroupMembers, GroupMember, \ +from seahub.api2.endpoints.group_members import GroupMembers, GroupSearchMember, GroupMember, \ GroupMembersBulk, GroupMembersImport, GroupMembersImportExample from seahub.api2.endpoints.search_group import SearchGroup from seahub.api2.endpoints.share_links import ShareLinks, ShareLink, \ @@ -307,6 +307,7 @@ urlpatterns = [ url(r'^api/v2.1/groups/(?P\d+)/group-owned-libraries/$', GroupOwnedLibraries.as_view(), name='api-v2.1-group-owned-libraries'), url(r'^api/v2.1/groups/(?P\d+)/group-owned-libraries/(?P[-0-9a-f]{36})/$', GroupOwnedLibrary.as_view(), name='api-v2.1-owned-group-library'), url(r'^api/v2.1/groups/(?P\d+)/members/$', GroupMembers.as_view(), name='api-v2.1-group-members'), + url(r'^api/v2.1/groups/(?P\d+)/search-member/$', GroupSearchMember.as_view(), name='api-v2.1-group-search-member'), url(r'^api/v2.1/groups/(?P\d+)/members/bulk/$', GroupMembersBulk.as_view(), name='api-v2.1-group-members-bulk'), url(r'^api/v2.1/groups/(?P\d+)/members/import/$', GroupMembersImport.as_view(), name='api-v2.1-group-members-import'), url(r'^api/v2.1/group-members-import-example/$', GroupMembersImportExample.as_view(), name='api-v2.1-group-members-import-example'),