mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-09 10:50:24 +00:00
update inactive user (#6019)
* update inactive user * is_active del RepoAPITokens * update del_repo_api_token * add inactive_user * [user admin] add confirmation to 'set user inactive' * system admin - users * system admin - organizations - org - member * org admin - users --------- Co-authored-by: llj <lingjun.li1@gmail.com>
This commit is contained in:
@@ -8,6 +8,7 @@ const propTypes = {
|
||||
currentSelectedOption: PropTypes.object.isRequired,
|
||||
options: PropTypes.array.isRequired,
|
||||
selectOption: PropTypes.func.isRequired,
|
||||
operationBeforeSelect: PropTypes.func,
|
||||
toggleItemFreezed: PropTypes.func
|
||||
};
|
||||
|
||||
@@ -52,7 +53,11 @@ class Selector extends Component {
|
||||
|
||||
selectItem = (e, targetItem) => {
|
||||
e.stopPropagation();
|
||||
if (this.props.operationBeforeSelect) {
|
||||
this.props.operationBeforeSelect();
|
||||
} else {
|
||||
this.props.selectOption(targetItem);
|
||||
}
|
||||
this.togglePopover();
|
||||
};
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import toaster from '../../components/toast';
|
||||
import Selector from '../../components/single-selector';
|
||||
import CommonOperationConfirmationDialog from '../../components/dialog/common-operation-confirmation-dialog';
|
||||
|
||||
const propTypes = {
|
||||
user: PropTypes.object,
|
||||
@@ -84,6 +85,11 @@ class UserItem extends React.Component {
|
||||
this.props.changeStatus(this.props.user.email, isActive);
|
||||
};
|
||||
|
||||
setUserInactive = () => {
|
||||
const isActive = false;
|
||||
this.props.changeStatus(this.props.user.email, isActive);
|
||||
};
|
||||
|
||||
onDropdownToggleClick = (e) => {
|
||||
e.preventDefault();
|
||||
this.toggleOperationMenu(e);
|
||||
@@ -126,8 +132,12 @@ class UserItem extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
toggleConfirmInactiveDialog= () => {
|
||||
this.setState({isConfirmInactiveDialogOpen: !this.state.isConfirmInactiveDialogOpen});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { highlight } = this.state;
|
||||
const { highlight, isConfirmInactiveDialogOpen } = this.state;
|
||||
let { user, currentTab } = this.props;
|
||||
let href = siteRoot + 'org/useradmin/info/' + encodeURIComponent(user.email) + '/';
|
||||
let isOperationMenuShow = (user.email !== username) && this.state.showMenu;
|
||||
@@ -143,7 +153,11 @@ class UserItem extends React.Component {
|
||||
});
|
||||
const currentSelectedStatusOption = this.statusOptions.filter(item => item.isSelected)[0];
|
||||
|
||||
const itemName = '<span class="op-target">' + Utils.HTMLescape(user.name) + '</span>';
|
||||
const confirmSetUserInactiveMsg = gettext('Are you sure you want to set {user_placeholder} inactive?').replace('{user_placeholder}', itemName);
|
||||
|
||||
return (
|
||||
<>
|
||||
<tr className={this.state.highlight ? 'tr-highlight' : ''} onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}>
|
||||
<td>
|
||||
<a href={href}>{user.name}</a>
|
||||
@@ -155,6 +169,7 @@ class UserItem extends React.Component {
|
||||
options={this.statusOptions}
|
||||
selectOption={this.changeStatus}
|
||||
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||
operationBeforeSelect={user.is_active ? this.toggleConfirmInactiveDialog : undefined}
|
||||
/>
|
||||
</td>
|
||||
<td>{`${Utils.formatSize({bytes: user.quota_usage})} / ${this.getQuotaTotal(user.quota_total)}`}</td>
|
||||
@@ -184,6 +199,16 @@ class UserItem extends React.Component {
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
{isConfirmInactiveDialogOpen &&
|
||||
<CommonOperationConfirmationDialog
|
||||
title={gettext('Set user inactive')}
|
||||
message={confirmSetUserInactiveMsg}
|
||||
executeOperation={this.setUserInactive}
|
||||
confirmBtnText={gettext('Set')}
|
||||
toggleDialog={this.toggleConfirmInactiveDialog}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -158,10 +158,18 @@ class Item extends Component {
|
||||
this.setState({isResetPasswordDialogOpen: !this.state.isResetPasswordDialogOpen});
|
||||
};
|
||||
|
||||
toggleConfirmInactiveDialog= () => {
|
||||
this.setState({isConfirmInactiveDialogOpen: !this.state.isConfirmInactiveDialogOpen});
|
||||
};
|
||||
|
||||
updateStatus= (statusOption) => {
|
||||
this.props.updateStatus(this.props.item.email, statusOption.value);
|
||||
};
|
||||
|
||||
setUserInactive = () => {
|
||||
this.props.updateStatus(this.props.item.email, 'inactive');
|
||||
};
|
||||
|
||||
updateMembership= (membershipOption) => {
|
||||
this.props.updateMembership(this.props.item.email, membershipOption.value);
|
||||
};
|
||||
@@ -214,11 +222,12 @@ class Item extends Component {
|
||||
|
||||
render() {
|
||||
const { item } = this.props;
|
||||
const { highlight, isOpIconShown, isDeleteDialogOpen, isResetPasswordDialogOpen } = this.state;
|
||||
const { highlight, isOpIconShown, isDeleteDialogOpen, isResetPasswordDialogOpen, isConfirmInactiveDialogOpen } = this.state;
|
||||
|
||||
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';
|
||||
@@ -253,6 +262,7 @@ class Item extends Component {
|
||||
options={this.statusOptions}
|
||||
selectOption={this.updateStatus}
|
||||
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||
operationBeforeSelect={item.active ? this.toggleConfirmInactiveDialog : undefined}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
@@ -298,6 +308,15 @@ class Item extends Component {
|
||||
toggleDialog={this.toggleResetPasswordDialog}
|
||||
/>
|
||||
}
|
||||
{isConfirmInactiveDialogOpen &&
|
||||
<CommonOperationConfirmationDialog
|
||||
title={gettext('Set user inactive')}
|
||||
message={confirmSetUserInactiveMsg}
|
||||
executeOperation={this.setUserInactive}
|
||||
confirmBtnText={gettext('Set')}
|
||||
toggleDialog={this.toggleConfirmInactiveDialog}
|
||||
/>
|
||||
}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
@@ -200,7 +200,8 @@ class Item extends Component {
|
||||
isSetQuotaDialogOpen: false,
|
||||
isDeleteUserDialogOpen: false,
|
||||
isResetUserPasswordDialogOpen: false,
|
||||
isRevokeAdminDialogOpen: false
|
||||
isRevokeAdminDialogOpen: false,
|
||||
isConfirmInactiveDialogOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -246,6 +247,10 @@ class Item extends Component {
|
||||
this.setState({isRevokeAdminDialogOpen: !this.state.isRevokeAdminDialogOpen});
|
||||
};
|
||||
|
||||
toggleConfirmInactiveDialog= () => {
|
||||
this.setState({isConfirmInactiveDialogOpen: !this.state.isConfirmInactiveDialogOpen});
|
||||
};
|
||||
|
||||
onUserSelected = () => {
|
||||
this.props.onUserSelected(this.props.item);
|
||||
};
|
||||
@@ -258,6 +263,10 @@ 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);
|
||||
};
|
||||
|
||||
updateRole = (roleOption) => {
|
||||
this.props.updateUser(this.props.item.email, 'role', roleOption.value);
|
||||
};
|
||||
@@ -386,13 +395,15 @@ class Item extends Component {
|
||||
isSetQuotaDialogOpen,
|
||||
isDeleteUserDialogOpen,
|
||||
isResetUserPasswordDialogOpen,
|
||||
isRevokeAdminDialogOpen
|
||||
isRevokeAdminDialogOpen,
|
||||
isConfirmInactiveDialogOpen
|
||||
} = this.state;
|
||||
|
||||
const itemName = '<span class="op-target">' + Utils.HTMLescape(item.name) + '</span>';
|
||||
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';
|
||||
@@ -473,6 +484,7 @@ class Item extends Component {
|
||||
options={this.statusOptions}
|
||||
selectOption={this.updateStatus}
|
||||
toggleItemFreezed={this.props.toggleItemFreezed}
|
||||
operationBeforeSelect={item.is_active ? this.toggleConfirmInactiveDialog : undefined}
|
||||
/>
|
||||
</td>
|
||||
{isPro &&
|
||||
@@ -567,6 +579,15 @@ class Item extends Component {
|
||||
toggleDialog={this.toggleRevokeAdminDialog}
|
||||
/>
|
||||
}
|
||||
{isConfirmInactiveDialogOpen &&
|
||||
<CommonOperationConfirmationDialog
|
||||
title={gettext('Set user inactive')}
|
||||
message={confirmSetUserInactiveMsg}
|
||||
executeOperation={this.setUserInactive}
|
||||
confirmBtnText={gettext('Set')}
|
||||
toggleDialog={this.toggleConfirmInactiveDialog}
|
||||
/>
|
||||
}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
@@ -282,6 +282,13 @@ class Account(APIView):
|
||||
'is_active invalid.')
|
||||
|
||||
user.is_active = is_active
|
||||
if is_active == False:
|
||||
# del tokens and personal repo api tokens (not department)
|
||||
from seahub.utils import inactive_user
|
||||
try:
|
||||
inactive_user(email)
|
||||
except Exception as e:
|
||||
logger.error("Failed to inactive_user %s: %s." % (email, e))
|
||||
|
||||
# update password
|
||||
password = request.data.get("password", None)
|
||||
|
@@ -355,9 +355,18 @@ def update_user_info(request, user, password, is_active, is_staff, role,
|
||||
quota_total_mb, institution_name,
|
||||
upload_rate_limit, download_rate_limit):
|
||||
|
||||
email = user.username
|
||||
|
||||
# update basic user info
|
||||
if is_active is not None:
|
||||
user.is_active = is_active
|
||||
if is_active == False:
|
||||
# del tokens and personal repo api tokens (not department)
|
||||
from seahub.utils import inactive_user
|
||||
try:
|
||||
inactive_user(email)
|
||||
except Exception as e:
|
||||
logger.error("Failed to inactive_user %s: %s." % (email, e))
|
||||
|
||||
if password:
|
||||
user.set_password(password)
|
||||
@@ -368,8 +377,6 @@ def update_user_info(request, user, password, is_active, is_staff, role,
|
||||
# update user
|
||||
user.save()
|
||||
|
||||
email = user.username
|
||||
|
||||
# update additional user info
|
||||
if is_pro_version() and role:
|
||||
User.objects.update_role(email, role)
|
||||
|
@@ -442,6 +442,13 @@ class OrgAdminUser(APIView):
|
||||
|
||||
user.is_active = is_active == 'true'
|
||||
user.save()
|
||||
if not is_active == 'true':
|
||||
# del tokens and personal repo api tokens (not department)
|
||||
from seahub.utils import inactive_user
|
||||
try:
|
||||
inactive_user(email)
|
||||
except Exception as e:
|
||||
logger.error("Failed to inactive_user %s: %s." % (email, e))
|
||||
|
||||
# update quota_total
|
||||
quota_total_mb = request.data.get("quota_total", None)
|
||||
|
@@ -18,7 +18,7 @@ from urllib.parse import urlparse, urljoin
|
||||
|
||||
from constance import config
|
||||
import seaserv
|
||||
from seaserv import seafile_api
|
||||
from seaserv import seafile_api, ccnet_api
|
||||
|
||||
from django.urls import reverse
|
||||
from django.core.mail import EmailMessage
|
||||
@@ -1280,6 +1280,38 @@ def clear_token(username):
|
||||
TokenV2.objects.filter(user = username).delete()
|
||||
seafile_api.delete_repo_tokens_by_email(username)
|
||||
|
||||
|
||||
def inactive_user(username):
|
||||
# del tokens and personal repo api tokens (not department)
|
||||
from seahub.repo_api_tokens.models import RepoAPITokens
|
||||
try:
|
||||
clear_token(username)
|
||||
except Exception as e:
|
||||
logger.error("Failed to delete tokens for user %s: %s." % (username, e))
|
||||
try:
|
||||
from seahub.settings import MULTI_TENANCY
|
||||
except ImportError:
|
||||
MULTI_TENANCY = False
|
||||
try:
|
||||
org_id = -1
|
||||
if MULTI_TENANCY:
|
||||
orgs = ccnet_api.get_orgs_by_user(username)
|
||||
if orgs:
|
||||
org = orgs[0]
|
||||
org_id = org.org_id
|
||||
if org_id > 0:
|
||||
owned_repos = seafile_api.get_org_owned_repo_list(
|
||||
org_id, username, ret_corrupted=True)
|
||||
else:
|
||||
owned_repos = seafile_api.get_owned_repo_list(
|
||||
username, ret_corrupted=True)
|
||||
owned_repo_ids = [item.repo_id for item in owned_repos]
|
||||
RepoAPITokens.objects.filter(
|
||||
repo_id__in=owned_repo_ids).delete()
|
||||
except Exception as e:
|
||||
logger.error("Failed to delete repo api tokens for user %s: %s." % (username, e))
|
||||
|
||||
|
||||
def send_perm_audit_msg(etype, from_user, to, repo_id, path, perm):
|
||||
"""Send repo permission audit msg.
|
||||
|
||||
|
Reference in New Issue
Block a user