diff --git a/frontend/src/components/select-editor/sysadmin-user-membership-editor.js b/frontend/src/components/select-editor/sysadmin-user-membership-editor.js
new file mode 100644
index 0000000000..7a858129dc
--- /dev/null
+++ b/frontend/src/components/select-editor/sysadmin-user-membership-editor.js
@@ -0,0 +1,41 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { gettext } from '../../utils/constants';
+import SelectEditor from './select-editor';
+
+const propTypes = {
+ isTextMode: PropTypes.bool.isRequired,
+ isEditIconShow: PropTypes.bool.isRequired,
+ statusOptions: PropTypes.array.isRequired,
+ currentStatus: PropTypes.string.isRequired,
+ onStatusChanged: PropTypes.func.isRequired
+};
+
+class SysAdminUserMembershipEditor extends React.Component {
+
+ translateStatus = (status) => {
+ switch (status) {
+ case 'is_org_staff':
+ return gettext('Admin');
+ case 'not_is_org_staff':
+ return gettext('Member');
+ }
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+SysAdminUserMembershipEditor.propTypes = propTypes;
+
+export default SysAdminUserMembershipEditor;
diff --git a/frontend/src/pages/sys-admin/orgs/org-users.js b/frontend/src/pages/sys-admin/orgs/org-users.js
index af80de93cd..b2e921a770 100644
--- a/frontend/src/pages/sys-admin/orgs/org-users.js
+++ b/frontend/src/pages/sys-admin/orgs/org-users.js
@@ -8,6 +8,7 @@ import toaster from '../../../components/toast';
import EmptyTip from '../../../components/empty-tip';
import Loading from '../../../components/loading';
import SysAdminUserStatusEditor from '../../../components/select-editor/sysadmin-user-status-editor';
+import SysAdminUserMembershipEditor from '../../../components/select-editor/sysadmin-user-membership-editor';
import SysAdminAddUserDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-add-user-dialog';
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
import OpMenu from '../../../components/dialog/op-menu';
@@ -50,9 +51,10 @@ class Content extends Component {
{gettext('Name')} |
- {gettext('Status')} |
- {gettext('Space Used')} |
- {gettext('Created At')}{' / '}{gettext('Last Login')} |
+ {gettext('Status')} |
+ {gettext('Membership')} |
+ {gettext('Space Used')} |
+ {gettext('Created At')}{' / '}{gettext('Last Login')} |
{/* Operations */} |
@@ -65,6 +67,7 @@ class Content extends Component {
onFreezedItem={this.onFreezedItem}
onUnfreezedItem={this.onUnfreezedItem}
updateStatus={this.props.updateStatus}
+ updateMembership={this.props.updateMembership}
deleteUser={this.props.deleteUser}
/>);
})}
@@ -146,6 +149,10 @@ class Item extends Component {
this.props.updateStatus(this.props.item.email, statusValue);
}
+ updateMembership= (membershipValue) => {
+ this.props.updateMembership(this.props.item.email, membershipValue);
+ }
+
deleteUser = () => {
const { item } = this.props;
this.props.deleteUser(item.org_id, item.email);
@@ -195,6 +202,15 @@ class Item extends Component {
onStatusChanged={this.updateStatus}
/>
+
+
+ |
{`${Utils.bytesToSize(item.quota_usage)} / ${item.quota_total > 0 ? Utils.bytesToSize(item.quota_total) : '--'}`} |
{moment(item.create_time).format('YYYY-MM-DD HH:mm:ss')}{' / '}{item.last_login ? moment(item.last_login).fromNow() : '--'}
@@ -311,6 +327,22 @@ class OrgUsers extends Component {
});
}
+ updateMembership = (email, membershipValue) => {
+ const isOrgStaff = membershipValue == 'is_org_staff';
+ seafileAPI.sysAdminUpdateOrgUser(this.props.orgID, email, 'is_org_staff', isOrgStaff).then(res => {
+ let newUserList = this.state.userList.map(item => {
+ if (item.email == email) {
+ item.is_org_staff = res.data.is_org_staff;
+ }
+ return item;
+ });
+ this.setState({userList: newUserList});
+ }).catch((error) => {
+ let errMessage = Utils.getErrorMsg(error);
+ toaster.danger(errMessage);
+ });
+ }
+
render() {
const { isAddUserDialogOpen, orgName } = this.state;
return (
@@ -331,6 +363,7 @@ class OrgUsers extends Component {
errorMsg={this.state.errorMsg}
items={this.state.userList}
updateStatus={this.updateStatus}
+ updateMembership={this.updateMembership}
deleteUser={this.deleteUser}
/>
diff --git a/seahub/api2/endpoints/admin/org_users.py b/seahub/api2/endpoints/admin/org_users.py
index 6c8bde1dda..03c38c77e8 100644
--- a/seahub/api2/endpoints/admin/org_users.py
+++ b/seahub/api2/endpoints/admin/org_users.py
@@ -61,6 +61,8 @@ def get_org_user_info(org_id, user_obj):
if last_login:
user_info['last_login'] = datetime_to_isoformat_timestr(last_login)
+ user_info['is_org_staff'] = True if ccnet_api.is_org_staff(org_id, email) == 1 else False
+
return user_info
def check_org_user(func):
@@ -352,6 +354,28 @@ class AdminOrgUser(APIView):
seafile_api.set_org_user_quota(org_id, email, user_quota)
+ # update is_org_staff
+ is_org_staff = request.data.get("is_org_staff", '')
+ if is_org_staff:
+
+ is_org_staff = is_org_staff.lower()
+ if is_org_staff not in ('true', 'false'):
+ error_msg = 'is_org_staff invalid.'
+ return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
+
+ if is_org_staff == 'true':
+ if ccnet_api.is_org_staff(org_id, email):
+ error_msg = '%s is already organization staff.' % email
+ return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
+
+ ccnet_api.set_org_staff(org_id, email)
+ else:
+ if not ccnet_api.is_org_staff(org_id, email):
+ error_msg = '%s is not organization staff.' % email
+ return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
+
+ ccnet_api.unset_org_staff(org_id, email)
+
user_info = get_org_user_info(org_id, user)
user_info['active'] = user.is_active
return Response(user_info)
|