mirror of
https://github.com/haiwen/seahub.git
synced 2025-05-11 01:17:02 +00:00
Add deactivation option (#7626)
* sql delete share relation * update rpc remove share * update * use sql remove share * code optimize * code optimize * update selector --------- Co-authored-by: 孙永强 <11704063+s-yongqiang@user.noreply.gitee.com> Co-authored-by: r350178982 <32759763+r350178982@users.noreply.github.com>
This commit is contained in:
parent
38c6ea36ae
commit
f24516e88a
frontend/src
components
pages/sys-admin
utils
seahub
@ -0,0 +1,80 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button, Modal, ModalBody, ModalFooter, Form, FormGroup, Input, Label } from 'reactstrap';
|
||||
import { gettext } from '../../../utils/constants';
|
||||
import SeahubModalHeader from '@/components/common/seahub-modal-header';
|
||||
|
||||
const propTypes = {
|
||||
toggleDialog: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
class SysAdminUserDeactivateDialog extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
keepSharing: true
|
||||
};
|
||||
}
|
||||
|
||||
handleOptionChange = (e) => {
|
||||
this.setState({ keepSharing: e.target.value === 'true' });
|
||||
};
|
||||
|
||||
submit = () => {
|
||||
this.props.onSubmit(this.state.keepSharing);
|
||||
this.props.toggleDialog();
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Modal isOpen={true} toggle={this.props.toggleDialog}>
|
||||
<SeahubModalHeader toggle={this.props.toggleDialog}>
|
||||
{gettext('Set user inactive')}
|
||||
</SeahubModalHeader>
|
||||
<ModalBody>
|
||||
<Form>
|
||||
<FormGroup tag="fieldset">
|
||||
<p>{gettext('Do you want to keep the sharing relationships?')}</p>
|
||||
<FormGroup check>
|
||||
<Label check>
|
||||
<Input
|
||||
type="radio"
|
||||
name="keepSharing"
|
||||
value="true"
|
||||
checked={this.state.keepSharing === true}
|
||||
onChange={this.handleOptionChange}
|
||||
className="mr-2"
|
||||
/>
|
||||
{gettext('Keep sharing')}
|
||||
</Label>
|
||||
</FormGroup>
|
||||
<FormGroup check>
|
||||
<Label check>
|
||||
<Input
|
||||
type="radio"
|
||||
name="keepSharing"
|
||||
value="false"
|
||||
checked={this.state.keepSharing === false}
|
||||
onChange={this.handleOptionChange}
|
||||
className="mr-2"
|
||||
/>
|
||||
{gettext('Do not keep sharing')}
|
||||
</Label>
|
||||
</FormGroup>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</Button>
|
||||
<Button color="primary" onClick={this.submit}>{gettext('Submit')}</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SysAdminUserDeactivateDialog.propTypes = propTypes;
|
||||
|
||||
export default SysAdminUserDeactivateDialog;
|
@ -56,7 +56,7 @@ class Selector extends Component {
|
||||
selectItem = (e, targetItem) => {
|
||||
e.stopPropagation();
|
||||
if (this.props.operationBeforeSelect) {
|
||||
this.props.operationBeforeSelect();
|
||||
this.props.operationBeforeSelect(targetItem);
|
||||
} else {
|
||||
this.props.selectOption(targetItem);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import OpMenu from '../../../components/dialog/op-menu';
|
||||
import MainPanelTopbar from '../main-panel-topbar';
|
||||
import UserLink from '../user-link';
|
||||
import OrgNav from './org-nav';
|
||||
import SysAdminUserDeactivateDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-user-deactivate-dialog';
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
@ -160,7 +161,10 @@ class Item extends Component {
|
||||
this.setState({ isResetPasswordDialogOpen: !this.state.isResetPasswordDialogOpen });
|
||||
};
|
||||
|
||||
toggleConfirmInactiveDialog = () => {
|
||||
toggleConfirmInactiveDialog = (targetItem) => {
|
||||
if (targetItem?.value === 'active') {
|
||||
return;
|
||||
}
|
||||
this.setState({ isConfirmInactiveDialogOpen: !this.state.isConfirmInactiveDialogOpen });
|
||||
};
|
||||
|
||||
@ -168,8 +172,8 @@ class Item extends Component {
|
||||
this.props.updateStatus(this.props.item.email, statusOption.value);
|
||||
};
|
||||
|
||||
setUserInactive = () => {
|
||||
this.props.updateStatus(this.props.item.email, 'inactive');
|
||||
setUserInactive = (keepSharing) => {
|
||||
this.props.updateStatus(this.props.item.email, 'inactive', { keepSharing: keepSharing });
|
||||
};
|
||||
|
||||
updateMembership = (membershipOption) => {
|
||||
@ -229,7 +233,6 @@ class Item extends Component {
|
||||
const itemName = '<span class="op-target">' + Utils.HTMLescape(item.name) + '</span>';
|
||||
let deleteDialogMsg = gettext('Are you sure you want to delete {placeholder} ?').replace('{placeholder}', itemName);
|
||||
let resetPasswordDialogMsg = gettext('Are you sure you want to reset the password of {placeholder} ?').replace('{placeholder}', itemName);
|
||||
const confirmSetUserInactiveMsg = gettext('Are you sure you want to set {user_placeholder} inactive?').replace('{user_placeholder}', itemName);
|
||||
|
||||
// for 'user status'
|
||||
const curStatus = item.active ? 'active' : 'inactive';
|
||||
@ -311,13 +314,10 @@ class Item extends Component {
|
||||
/>
|
||||
}
|
||||
{isConfirmInactiveDialogOpen &&
|
||||
<CommonOperationConfirmationDialog
|
||||
title={gettext('Set user inactive')}
|
||||
message={confirmSetUserInactiveMsg}
|
||||
executeOperation={this.setUserInactive}
|
||||
confirmBtnText={gettext('Set')}
|
||||
toggleDialog={this.toggleConfirmInactiveDialog}
|
||||
/>
|
||||
<SysAdminUserDeactivateDialog
|
||||
toggleDialog={this.toggleConfirmInactiveDialog}
|
||||
onSubmit={this.setUserInactive}
|
||||
/>
|
||||
}
|
||||
</Fragment>
|
||||
);
|
||||
@ -396,9 +396,9 @@ class OrgUsers extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
updateStatus = (email, statusValue) => {
|
||||
updateStatus = (email, statusValue, options = {}) => {
|
||||
const isActive = statusValue == 'active';
|
||||
systemAdminAPI.sysAdminUpdateOrgUser(this.props.orgID, email, 'active', isActive).then(res => {
|
||||
systemAdminAPI.sysAdminUpdateOrgUser(this.props.orgID, email, 'active', isActive, options).then(res => {
|
||||
let newUserList = this.state.userList.map(item => {
|
||||
if (item.email == email) {
|
||||
item.active = res.data.active;
|
||||
|
@ -204,8 +204,8 @@ class SearchUsers extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
updateUser = (email, key, value) => {
|
||||
systemAdminAPI.sysAdminUpdateUser(email, key, value).then(res => {
|
||||
updateUser = (email, key, value, options) => {
|
||||
systemAdminAPI.sysAdminUpdateUser(email, key, value, options).then(res => {
|
||||
let newUserList = this.state.userList.map(item => {
|
||||
if (item.email == email) {
|
||||
item[key] = res.data[key];
|
||||
|
@ -15,6 +15,7 @@ import OpMenu from '../../../components/dialog/op-menu';
|
||||
import SysAdminUserSetQuotaDialog from '../../../components/dialog/sysadmin-dialog/set-quota';
|
||||
import CommonOperationConfirmationDialog from '../../../components/dialog/common-operation-confirmation-dialog';
|
||||
import UserLink from '../user-link';
|
||||
import SysAdminUserDeactivateDialog from '../../../components/dialog/sysadmin-dialog/sysadmin-user-deactivate-dialog';
|
||||
|
||||
const { availableRoles, availableAdminRoles, institutions } = window.sysadmin.pageOptions;
|
||||
dayjs.extend(relativeTime);
|
||||
@ -206,7 +207,7 @@ class Item extends Component {
|
||||
isDeleteUserDialogOpen: false,
|
||||
isResetUserPasswordDialogOpen: false,
|
||||
isRevokeAdminDialogOpen: false,
|
||||
isConfirmInactiveDialogOpen: false
|
||||
isConfirmInactiveDialogOpen: false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -252,7 +253,10 @@ class Item extends Component {
|
||||
this.setState({ isRevokeAdminDialogOpen: !this.state.isRevokeAdminDialogOpen });
|
||||
};
|
||||
|
||||
toggleConfirmInactiveDialog = () => {
|
||||
toggleConfirmInactiveDialog = (targetItem) => {
|
||||
if (targetItem?.value === 'active') {
|
||||
return;
|
||||
}
|
||||
this.setState({ isConfirmInactiveDialogOpen: !this.state.isConfirmInactiveDialogOpen });
|
||||
};
|
||||
|
||||
@ -268,10 +272,14 @@ class Item extends Component {
|
||||
this.props.updateUser(this.props.item.email, 'is_active', isActive);
|
||||
};
|
||||
|
||||
setUserInactive = () => {
|
||||
this.props.updateUser(this.props.item.email, 'is_active', false);
|
||||
setUserInactive = (keepSharing) => {
|
||||
this.props.updateUser(this.props.item.email, 'is_active', false, {
|
||||
keep_sharing: keepSharing
|
||||
});
|
||||
this.toggleConfirmInactiveDialog();
|
||||
};
|
||||
|
||||
|
||||
updateRole = (roleOption) => {
|
||||
this.props.updateUser(this.props.item.email, 'role', roleOption.value);
|
||||
};
|
||||
@ -408,7 +416,6 @@ class Item extends Component {
|
||||
const deleteDialogMsg = gettext('Are you sure you want to delete {placeholder} ?').replace('{placeholder}', itemName);
|
||||
const resetPasswordDialogMsg = gettext('Are you sure you want to reset the password of {placeholder} ?').replace('{placeholder}', itemName);
|
||||
const revokeAdminDialogMsg = gettext('Are you sure you want to revoke the admin permission of {placeholder} ?').replace('{placeholder}', itemName);
|
||||
const confirmSetUserInactiveMsg = gettext('Are you sure you want to set {user_placeholder} inactive?').replace('{user_placeholder}', itemName);
|
||||
|
||||
// for 'user status'
|
||||
const curStatus = item.is_active ? 'active' : 'inactive';
|
||||
@ -585,12 +592,9 @@ class Item extends Component {
|
||||
/>
|
||||
}
|
||||
{isConfirmInactiveDialogOpen &&
|
||||
<CommonOperationConfirmationDialog
|
||||
title={gettext('Set user inactive')}
|
||||
message={confirmSetUserInactiveMsg}
|
||||
executeOperation={this.setUserInactive}
|
||||
confirmBtnText={gettext('Set')}
|
||||
<SysAdminUserDeactivateDialog
|
||||
toggleDialog={this.toggleConfirmInactiveDialog}
|
||||
onSubmit={this.setUserInactive}
|
||||
/>
|
||||
}
|
||||
</Fragment>
|
||||
|
@ -360,8 +360,8 @@ class Users extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
updateUser = (email, key, value) => {
|
||||
systemAdminAPI.sysAdminUpdateUser(email, key, value).then(res => {
|
||||
updateUser = (email, key, value, options = {}) => {
|
||||
systemAdminAPI.sysAdminUpdateUser(email, key, value, options).then(res => {
|
||||
let newUserList = this.state.userList.map(item => {
|
||||
if (item.email == email) {
|
||||
item[key] = res.data[key];
|
||||
|
@ -642,12 +642,15 @@ class SystemAdminAPI {
|
||||
return this._sendPostRequest(url, formData);
|
||||
}
|
||||
|
||||
sysAdminUpdateOrgUser(orgID, email, attribute, value) {
|
||||
sysAdminUpdateOrgUser(orgID, email, attribute, value, options = {}) {
|
||||
const url = this.server + '/api/v2.1/admin/organizations/' + orgID + '/users/' + encodeURIComponent(email) + '/';
|
||||
let formData = new FormData();
|
||||
switch (attribute) {
|
||||
case 'active':
|
||||
formData.append('active', value);
|
||||
if (options.keepSharing !== undefined) {
|
||||
formData.append('keep_sharing', options.keepSharing);
|
||||
}
|
||||
break;
|
||||
case 'is_org_staff':
|
||||
formData.append('is_org_staff', value);
|
||||
@ -957,7 +960,7 @@ class SystemAdminAPI {
|
||||
return this._sendPostRequest(url, formData);
|
||||
}
|
||||
|
||||
sysAdminUpdateUser(email, attribute, value) {
|
||||
sysAdminUpdateUser(email, attribute, value, options = {}) {
|
||||
const url = this.server + '/api/v2.1/admin/users/' + encodeURIComponent(email) + '/';
|
||||
let formData = new FormData();
|
||||
switch (attribute) {
|
||||
@ -966,6 +969,9 @@ class SystemAdminAPI {
|
||||
break;
|
||||
case 'is_active':
|
||||
formData.append('is_active', value);
|
||||
if (options.keep_sharing !== undefined) {
|
||||
formData.append('keep_sharing', options.keep_sharing);
|
||||
}
|
||||
break;
|
||||
case 'is_staff':
|
||||
formData.append('is_staff', value);
|
||||
|
@ -31,6 +31,8 @@ from seahub.api2.permissions import IsProVersion
|
||||
from seahub.api2.endpoints.utils import is_org_user
|
||||
from seahub.utils.timeutils import timestamp_to_isoformat_timestr, \
|
||||
datetime_to_isoformat_timestr
|
||||
from seahub.utils.db_api import SeafileDB
|
||||
from seahub.share.models import ExtraSharePermission
|
||||
|
||||
try:
|
||||
from seahub.settings import ORG_MEMBER_QUOTA_ENABLED
|
||||
@ -303,6 +305,20 @@ class AdminOrgUser(APIView):
|
||||
else:
|
||||
user.is_active = False
|
||||
|
||||
keep_sharing = request.data.get("keep_sharing", None)
|
||||
username = request.user.username
|
||||
if keep_sharing and keep_sharing == 'false':
|
||||
seafile_db = SeafileDB()
|
||||
orgs = ccnet_api.get_orgs_by_user(email)
|
||||
if orgs:
|
||||
org_id = orgs[0].org_id
|
||||
seafile_db.delete_received_share_by_user(email, org_id)
|
||||
seafile_db.delete_share_by_user(email, org_id)
|
||||
else:
|
||||
seafile_db.delete_received_share_by_user(email)
|
||||
seafile_db.delete_share_by_user(email)
|
||||
ExtraSharePermission.objects.filter(share_to=username).delete()
|
||||
|
||||
try:
|
||||
# update user status
|
||||
result_code = user.save()
|
||||
|
@ -66,7 +66,7 @@ from seahub.auth.utils import get_virtual_id_by_email
|
||||
from seahub.auth.models import SocialAuthUser
|
||||
|
||||
from seahub.options.models import UserOptions
|
||||
from seahub.share.models import FileShare, UploadLinkShare
|
||||
from seahub.share.models import FileShare, UploadLinkShare, ExtraSharePermission
|
||||
from seahub.utils.ldap import ENABLE_LDAP, LDAP_FILTER, ENABLE_SASL, SASL_MECHANISM, ENABLE_SSO_USER_CHANGE_PASSWORD, \
|
||||
LDAP_PROVIDER, LDAP_SERVER_URL, LDAP_BASE_DN, LDAP_ADMIN_DN, LDAP_ADMIN_PASSWORD, LDAP_LOGIN_ATTR, LDAP_USER_OBJECT_CLASS, \
|
||||
ENABLE_MULTI_LDAP, MULTI_LDAP_1_SERVER_URL, MULTI_LDAP_1_BASE_DN, MULTI_LDAP_1_ADMIN_DN, \
|
||||
@ -1262,7 +1262,20 @@ class AdminUser(APIView):
|
||||
|
||||
is_active = request.data.get("is_active", None)
|
||||
if is_active:
|
||||
|
||||
keep_sharing = request.data.get("keep_sharing", None)
|
||||
username = request.user.username
|
||||
|
||||
if keep_sharing and keep_sharing == 'false':
|
||||
seafile_db = SeafileDB()
|
||||
orgs = ccnet_api.get_orgs_by_user(email)
|
||||
if orgs:
|
||||
org_id = orgs[0].org_id
|
||||
seafile_db.delete_received_share_by_user(email, org_id)
|
||||
seafile_db.delete_share_by_user(email, org_id)
|
||||
else:
|
||||
seafile_db.delete_received_share_by_user(email)
|
||||
seafile_db.delete_share_by_user(email)
|
||||
ExtraSharePermission.objects.filter(share_to=username).delete()
|
||||
try:
|
||||
is_active = to_python_boolean(is_active)
|
||||
except ValueError:
|
||||
|
@ -618,3 +618,38 @@ class SeafileDB:
|
||||
wiki_info = WikiInfo(**params)
|
||||
wikis.append(wiki_info)
|
||||
return wikis
|
||||
|
||||
def delete_received_share_by_user(self, username, org_id=''):
|
||||
# Delete the share content shared to <username>
|
||||
if org_id:
|
||||
delete_share_sql = f"""
|
||||
DELETE FROM `{self.db_name}`.`OrgSharedRepo` WHERE to_email=%s AND org_id=%s
|
||||
"""
|
||||
else:
|
||||
delete_share_sql = f"""
|
||||
DELETE FROM `{self.db_name}`.`SharedRepo` WHERE to_email=%s
|
||||
"""
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(delete_share_sql, [username, org_id] if org_id else [username])
|
||||
|
||||
def delete_share_by_user(self, username, org_id=''):
|
||||
# Delete the share content shared from <username>
|
||||
if org_id:
|
||||
delete_share_sql = f"""
|
||||
DELETE FROM `{self.db_name}`.`OrgSharedRepo` WHERE from_email=%s AND org_id=%s
|
||||
"""
|
||||
delete_group_share_sql = f"""
|
||||
DELETE FROM `{self.db_name}`.`OrgGroupRepo` WHERE owner=%s AND org_id=%s
|
||||
"""
|
||||
else:
|
||||
delete_share_sql = f"""
|
||||
DELETE FROM `{self.db_name}`.`SharedRepo` WHERE from_email=%s
|
||||
"""
|
||||
delete_group_share_sql = f"""
|
||||
DELETE FROM `{self.db_name}`.`RepoGroup` WHERE user_name=%s
|
||||
"""
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(delete_share_sql, [username, org_id] if org_id else [username])
|
||||
cursor.execute(delete_group_share_sql, [username, org_id] if org_id else [username])
|
||||
|
Loading…
Reference in New Issue
Block a user