Rework admin approve/reject actions
This commit is contained in:
parent
cdc8c70078
commit
0e846784df
|
@ -39,6 +39,10 @@ const ADMIN_USERS_APPROVE_REQUEST = 'ADMIN_USERS_APPROVE_REQUEST';
|
||||||
const ADMIN_USERS_APPROVE_SUCCESS = 'ADMIN_USERS_APPROVE_SUCCESS';
|
const ADMIN_USERS_APPROVE_SUCCESS = 'ADMIN_USERS_APPROVE_SUCCESS';
|
||||||
const ADMIN_USERS_APPROVE_FAIL = 'ADMIN_USERS_APPROVE_FAIL';
|
const ADMIN_USERS_APPROVE_FAIL = 'ADMIN_USERS_APPROVE_FAIL';
|
||||||
|
|
||||||
|
const ADMIN_USERS_REJECT_REQUEST = 'ADMIN_USERS_REJECT_REQUEST';
|
||||||
|
const ADMIN_USERS_REJECT_SUCCESS = 'ADMIN_USERS_REJECT_SUCCESS';
|
||||||
|
const ADMIN_USERS_REJECT_FAIL = 'ADMIN_USERS_REJECT_FAIL';
|
||||||
|
|
||||||
const ADMIN_USERS_DEACTIVATE_REQUEST = 'ADMIN_USERS_DEACTIVATE_REQUEST';
|
const ADMIN_USERS_DEACTIVATE_REQUEST = 'ADMIN_USERS_DEACTIVATE_REQUEST';
|
||||||
const ADMIN_USERS_DEACTIVATE_SUCCESS = 'ADMIN_USERS_DEACTIVATE_SUCCESS';
|
const ADMIN_USERS_DEACTIVATE_SUCCESS = 'ADMIN_USERS_DEACTIVATE_SUCCESS';
|
||||||
const ADMIN_USERS_DEACTIVATE_FAIL = 'ADMIN_USERS_DEACTIVATE_FAIL';
|
const ADMIN_USERS_DEACTIVATE_FAIL = 'ADMIN_USERS_DEACTIVATE_FAIL';
|
||||||
|
@ -309,56 +313,80 @@ const deactivateUsers = (accountIds: string[], reportId?: string) =>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteUsers = (accountIds: string[]) =>
|
const deleteUser = (accountId: string) =>
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = accountIdsToAccts(getState(), accountIds);
|
const nicknames = accountIdsToAccts(getState(), [accountId]);
|
||||||
dispatch({ type: ADMIN_USERS_DELETE_REQUEST, accountIds });
|
dispatch({ type: ADMIN_USERS_DELETE_REQUEST, accountId });
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.delete('/api/v1/pleroma/admin/users', { data: { nicknames } })
|
.delete('/api/v1/pleroma/admin/users', { data: { nicknames } })
|
||||||
.then(({ data: nicknames }) => {
|
.then(({ data: nicknames }) => {
|
||||||
dispatch({ type: ADMIN_USERS_DELETE_SUCCESS, nicknames, accountIds });
|
dispatch({ type: ADMIN_USERS_DELETE_SUCCESS, nicknames, accountId });
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: ADMIN_USERS_DELETE_FAIL, error, accountIds });
|
dispatch({ type: ADMIN_USERS_DELETE_FAIL, error, accountId });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const approveMastodonUsers = (accountIds: string[]) =>
|
const approveMastodonUser = (accountId: string) =>
|
||||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
Promise.all(accountIds.map(accountId => {
|
|
||||||
api(getState)
|
api(getState)
|
||||||
.post(`/api/v1/admin/accounts/${accountId}/approve`)
|
.post(`/api/v1/admin/accounts/${accountId}/approve`)
|
||||||
.then(({ data: user }) => {
|
.then(({ data: user }) => {
|
||||||
dispatch({ type: ADMIN_USERS_APPROVE_SUCCESS, users: [user], accountIds: [accountId] });
|
dispatch({ type: ADMIN_USERS_APPROVE_SUCCESS, user, accountId });
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: ADMIN_USERS_APPROVE_FAIL, error, accountIds: [accountId] });
|
dispatch({ type: ADMIN_USERS_APPROVE_FAIL, error, accountId });
|
||||||
});
|
});
|
||||||
}));
|
|
||||||
|
|
||||||
const approvePleromaUsers = (accountIds: string[]) =>
|
const approvePleromaUser = (accountId: string) =>
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const nicknames = accountIdsToAccts(getState(), accountIds);
|
const nicknames = accountIdsToAccts(getState(), [accountId]);
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.patch('/api/v1/pleroma/admin/users/approve', { nicknames })
|
.patch('/api/v1/pleroma/admin/users/approve', { nicknames })
|
||||||
.then(({ data: { users } }) => {
|
.then(({ data: { users } }) => {
|
||||||
dispatch({ type: ADMIN_USERS_APPROVE_SUCCESS, users, accountIds });
|
dispatch({ type: ADMIN_USERS_APPROVE_SUCCESS, user: users[0], accountId });
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch({ type: ADMIN_USERS_APPROVE_FAIL, error, accountIds });
|
dispatch({ type: ADMIN_USERS_APPROVE_FAIL, error, accountId });
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const approveUsers = (accountIds: string[]) =>
|
const rejectMastodonUser = (accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||||
|
api(getState)
|
||||||
|
.post(`/api/v1/admin/accounts/${accountId}/reject`)
|
||||||
|
.then(({ data: user }) => {
|
||||||
|
dispatch({ type: ADMIN_USERS_REJECT_SUCCESS, user, accountId });
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch({ type: ADMIN_USERS_REJECT_FAIL, error, accountId });
|
||||||
|
});
|
||||||
|
|
||||||
|
const approveUser = (accountId: string) =>
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
const instance = state.instance;
|
const instance = state.instance;
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
dispatch({ type: ADMIN_USERS_APPROVE_REQUEST, accountIds });
|
dispatch({ type: ADMIN_USERS_APPROVE_REQUEST, accountId });
|
||||||
|
|
||||||
if (features.mastodonAdmin) {
|
if (features.mastodonAdmin) {
|
||||||
return dispatch(approveMastodonUsers(accountIds));
|
return dispatch(approveMastodonUser(accountId));
|
||||||
} else {
|
} else {
|
||||||
return dispatch(approvePleromaUsers(accountIds));
|
return dispatch(approvePleromaUser(accountId));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const rejectUser = (accountId: string) =>
|
||||||
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
|
const state = getState();
|
||||||
|
|
||||||
|
const instance = state.instance;
|
||||||
|
const features = getFeatures(instance);
|
||||||
|
|
||||||
|
dispatch({ type: ADMIN_USERS_REJECT_REQUEST, accountId });
|
||||||
|
|
||||||
|
if (features.mastodonAdmin) {
|
||||||
|
return dispatch(rejectMastodonUser(accountId));
|
||||||
|
} else {
|
||||||
|
return dispatch(deleteUser(accountId));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -562,6 +590,9 @@ export {
|
||||||
ADMIN_USERS_APPROVE_REQUEST,
|
ADMIN_USERS_APPROVE_REQUEST,
|
||||||
ADMIN_USERS_APPROVE_SUCCESS,
|
ADMIN_USERS_APPROVE_SUCCESS,
|
||||||
ADMIN_USERS_APPROVE_FAIL,
|
ADMIN_USERS_APPROVE_FAIL,
|
||||||
|
ADMIN_USERS_REJECT_REQUEST,
|
||||||
|
ADMIN_USERS_REJECT_SUCCESS,
|
||||||
|
ADMIN_USERS_REJECT_FAIL,
|
||||||
ADMIN_USERS_DEACTIVATE_REQUEST,
|
ADMIN_USERS_DEACTIVATE_REQUEST,
|
||||||
ADMIN_USERS_DEACTIVATE_SUCCESS,
|
ADMIN_USERS_DEACTIVATE_SUCCESS,
|
||||||
ADMIN_USERS_DEACTIVATE_FAIL,
|
ADMIN_USERS_DEACTIVATE_FAIL,
|
||||||
|
@ -597,8 +628,9 @@ export {
|
||||||
closeReports,
|
closeReports,
|
||||||
fetchUsers,
|
fetchUsers,
|
||||||
deactivateUsers,
|
deactivateUsers,
|
||||||
deleteUsers,
|
deleteUser,
|
||||||
approveUsers,
|
approveUser,
|
||||||
|
rejectUser,
|
||||||
deleteStatus,
|
deleteStatus,
|
||||||
toggleStatusSensitivity,
|
toggleStatusSensitivity,
|
||||||
tagUsers,
|
tagUsers,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { defineMessages, IntlShape } from 'react-intl';
|
import { defineMessages, IntlShape } from 'react-intl';
|
||||||
|
|
||||||
import { fetchAccountByUsername } from 'soapbox/actions/accounts';
|
import { fetchAccountByUsername } from 'soapbox/actions/accounts';
|
||||||
import { deactivateUsers, deleteUsers, deleteStatus, toggleStatusSensitivity } from 'soapbox/actions/admin';
|
import { deactivateUsers, deleteUser, deleteStatus, toggleStatusSensitivity } from 'soapbox/actions/admin';
|
||||||
import { openModal } from 'soapbox/actions/modals';
|
import { openModal } from 'soapbox/actions/modals';
|
||||||
import OutlineBox from 'soapbox/components/outline-box';
|
import OutlineBox from 'soapbox/components/outline-box';
|
||||||
import { Stack, Text } from 'soapbox/components/ui';
|
import { Stack, Text } from 'soapbox/components/ui';
|
||||||
|
@ -102,7 +102,7 @@ const deleteUserModal = (intl: IntlShape, accountId: string, afterConfirm = () =
|
||||||
confirm,
|
confirm,
|
||||||
checkbox,
|
checkbox,
|
||||||
onConfirm: () => {
|
onConfirm: () => {
|
||||||
dispatch(deleteUsers([accountId])).then(() => {
|
dispatch(deleteUser(accountId)).then(() => {
|
||||||
const message = intl.formatMessage(messages.userDeleted, { acct });
|
const message = intl.formatMessage(messages.userDeleted, { acct });
|
||||||
dispatch(fetchAccountByUsername(acct));
|
dispatch(fetchAccountByUsername(acct));
|
||||||
toast.success(message);
|
toast.success(message);
|
||||||
|
|
|
@ -71,6 +71,7 @@ const ProfilePopper: React.FC<IProfilePopper> = ({ condition, wrapper, children
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IAccount {
|
export interface IAccount {
|
||||||
|
acct?: string;
|
||||||
account: AccountSchema;
|
account: AccountSchema;
|
||||||
action?: React.ReactElement;
|
action?: React.ReactElement;
|
||||||
actionAlignment?: 'center' | 'top';
|
actionAlignment?: 'center' | 'top';
|
||||||
|
@ -99,6 +100,7 @@ export interface IAccount {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Account = ({
|
const Account = ({
|
||||||
|
acct,
|
||||||
account,
|
account,
|
||||||
actionType,
|
actionType,
|
||||||
action,
|
action,
|
||||||
|
@ -228,7 +230,7 @@ const Account = ({
|
||||||
|
|
||||||
<Stack space={withAccountNote || note ? 1 : 0}>
|
<Stack space={withAccountNote || note ? 1 : 0}>
|
||||||
<HStack alignItems='center' space={1}>
|
<HStack alignItems='center' space={1}>
|
||||||
<Text theme='muted' size='sm' direction='ltr' truncate>@{username}</Text>
|
<Text theme='muted' size='sm' direction='ltr' truncate>@{acct ?? username}</Text>
|
||||||
|
|
||||||
{account.pleroma?.favicon && (
|
{account.pleroma?.favicon && (
|
||||||
<InstanceFavicon account={account} disabled={!withLinkToProfile} />
|
<InstanceFavicon account={account} disabled={!withLinkToProfile} />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { approveUsers, deleteUsers } from 'soapbox/actions/admin';
|
import { approveUser, rejectUser } from 'soapbox/actions/admin';
|
||||||
import { useAccount } from 'soapbox/api/hooks';
|
import { useAccount } from 'soapbox/api/hooks';
|
||||||
import Account from 'soapbox/components/account';
|
import Account from 'soapbox/components/account';
|
||||||
import { AuthorizeRejectButtons } from 'soapbox/components/authorize-reject-buttons';
|
import { AuthorizeRejectButtons } from 'soapbox/components/authorize-reject-buttons';
|
||||||
|
@ -14,18 +14,19 @@ interface IUnapprovedAccount {
|
||||||
const UnapprovedAccount: React.FC<IUnapprovedAccount> = ({ accountId }) => {
|
const UnapprovedAccount: React.FC<IUnapprovedAccount> = ({ accountId }) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const { account } = useAccount(accountId);
|
|
||||||
const adminAccount = useAppSelector(state => state.admin.users.get(accountId));
|
const adminAccount = useAppSelector(state => state.admin.users.get(accountId));
|
||||||
|
const { account } = useAccount(adminAccount?.account || undefined);
|
||||||
|
|
||||||
if (!account) return null;
|
if (!adminAccount || !account) return null;
|
||||||
|
|
||||||
const handleApprove = () => dispatch(approveUsers([account.id]));
|
const handleApprove = () => dispatch(approveUser(adminAccount.id));
|
||||||
const handleReject = () => dispatch(deleteUsers([account.id]));
|
const handleReject = () => dispatch(rejectUser(adminAccount.id));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Account
|
<Account
|
||||||
key={account.id}
|
key={adminAccount.id}
|
||||||
account={account}
|
account={account}
|
||||||
|
acct={`${adminAccount.username}@${adminAccount.domain}`}
|
||||||
note={adminAccount?.invite_request || ''}
|
note={adminAccount?.invite_request || ''}
|
||||||
action={(
|
action={(
|
||||||
<AuthorizeRejectButtons
|
<AuthorizeRejectButtons
|
||||||
|
|
|
@ -19,6 +19,8 @@ import {
|
||||||
ADMIN_USERS_DELETE_SUCCESS,
|
ADMIN_USERS_DELETE_SUCCESS,
|
||||||
ADMIN_USERS_APPROVE_REQUEST,
|
ADMIN_USERS_APPROVE_REQUEST,
|
||||||
ADMIN_USERS_APPROVE_SUCCESS,
|
ADMIN_USERS_APPROVE_SUCCESS,
|
||||||
|
ADMIN_USERS_REJECT_REQUEST,
|
||||||
|
ADMIN_USERS_REJECT_SUCCESS,
|
||||||
} from 'soapbox/actions/admin';
|
} from 'soapbox/actions/admin';
|
||||||
import { normalizeAdminReport, normalizeAdminAccount } from 'soapbox/normalizers';
|
import { normalizeAdminReport, normalizeAdminAccount } from 'soapbox/normalizers';
|
||||||
import { normalizeId } from 'soapbox/utils/normalizers';
|
import { normalizeId } from 'soapbox/utils/normalizers';
|
||||||
|
@ -120,23 +122,19 @@ function importUsers(state: State, users: APIUser[], filters: Filter[], page: nu
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteUsers(state: State, accountIds: string[]): State {
|
function deleteUser(state: State, accountId: string): State {
|
||||||
return state.withMutations(state => {
|
return state.withMutations(state => {
|
||||||
accountIds.forEach(id => {
|
state.update('awaitingApproval', orderedSet => orderedSet.delete(accountId));
|
||||||
state.update('awaitingApproval', orderedSet => orderedSet.delete(id));
|
state.deleteIn(['users', accountId]);
|
||||||
state.deleteIn(['users', id]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function approveUsers(state: State, users: APIUser[]): State {
|
function approveUser(state: State, user: APIUser): State {
|
||||||
return state.withMutations(state => {
|
|
||||||
users.forEach(user => {
|
|
||||||
const normalizedUser = fixUser(user);
|
const normalizedUser = fixUser(user);
|
||||||
|
return state.withMutations(state => {
|
||||||
state.update('awaitingApproval', orderedSet => orderedSet.delete(user.id));
|
state.update('awaitingApproval', orderedSet => orderedSet.delete(user.id));
|
||||||
state.setIn(['users', user.id], normalizedUser);
|
state.setIn(['users', user.id], normalizedUser);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const minifyReport = (report: AdminReportRecord): ReducerAdminReport => {
|
const minifyReport = (report: AdminReportRecord): ReducerAdminReport => {
|
||||||
|
@ -207,11 +205,13 @@ export default function admin(state: State = ReducerRecord(), action: AnyAction)
|
||||||
return importUsers(state, action.users, action.filters, action.page);
|
return importUsers(state, action.users, action.filters, action.page);
|
||||||
case ADMIN_USERS_DELETE_REQUEST:
|
case ADMIN_USERS_DELETE_REQUEST:
|
||||||
case ADMIN_USERS_DELETE_SUCCESS:
|
case ADMIN_USERS_DELETE_SUCCESS:
|
||||||
return deleteUsers(state, action.accountIds);
|
case ADMIN_USERS_REJECT_REQUEST:
|
||||||
|
case ADMIN_USERS_REJECT_SUCCESS:
|
||||||
|
return deleteUser(state, action.accountId);
|
||||||
case ADMIN_USERS_APPROVE_REQUEST:
|
case ADMIN_USERS_APPROVE_REQUEST:
|
||||||
return state.update('awaitingApproval', set => set.subtract(action.accountIds));
|
return state.update('awaitingApproval', set => set.remove(action.accountId));
|
||||||
case ADMIN_USERS_APPROVE_SUCCESS:
|
case ADMIN_USERS_APPROVE_SUCCESS:
|
||||||
return approveUsers(state, action.users);
|
return approveUser(state, action.user);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue