Admin: make awaiting approval actions work

fix/tabs-bar-issues
Alex Gleason 2020-12-29 18:22:31 -06:00
rodzic 1ad3ea4437
commit a3f208c1be
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
4 zmienionych plików z 130 dodań i 9 usunięć

Wyświetl plik

@ -12,6 +12,14 @@ export const ADMIN_USERS_FETCH_REQUEST = 'ADMIN_USERS_FETCH_REQUEST';
export const ADMIN_USERS_FETCH_SUCCESS = 'ADMIN_USERS_FETCH_SUCCESS';
export const ADMIN_USERS_FETCH_FAIL = 'ADMIN_USERS_FETCH_FAIL';
export const ADMIN_USERS_DELETE_REQUEST = 'ADMIN_USERS_DELETE_REQUEST';
export const ADMIN_USERS_DELETE_SUCCESS = 'ADMIN_USERS_DELETE_SUCCESS';
export const ADMIN_USERS_DELETE_FAIL = 'ADMIN_USERS_DELETE_FAIL';
export const ADMIN_USERS_APPROVE_REQUEST = 'ADMIN_USERS_APPROVE_REQUEST';
export const ADMIN_USERS_APPROVE_SUCCESS = 'ADMIN_USERS_APPROVE_SUCCESS';
export const ADMIN_USERS_APPROVE_FAIL = 'ADMIN_USERS_APPROVE_FAIL';
export function updateAdminConfig(params) {
return (dispatch, getState) => {
dispatch({ type: ADMIN_CONFIG_UPDATE_REQUEST });
@ -50,3 +58,29 @@ export function fetchUsers(params) {
});
};
}
export function deleteUsers(nicknames) {
return (dispatch, getState) => {
dispatch({ type: ADMIN_USERS_DELETE_REQUEST, nicknames });
return api(getState)
.delete('/api/pleroma/admin/users', { data: { nicknames } })
.then(({ data: nicknames }) => {
dispatch({ type: ADMIN_USERS_DELETE_SUCCESS, nicknames });
}).catch(error => {
dispatch({ type: ADMIN_USERS_DELETE_FAIL, error, nicknames });
});
};
}
export function approveUsers(nicknames) {
return (dispatch, getState) => {
dispatch({ type: ADMIN_USERS_APPROVE_REQUEST, nicknames });
return api(getState)
.patch('/api/pleroma/admin/users/approve', { nicknames })
.then(({ data: { users } }) => {
dispatch({ type: ADMIN_USERS_APPROVE_SUCCESS, users, nicknames });
}).catch(error => {
dispatch({ type: ADMIN_USERS_APPROVE_FAIL, error, nicknames });
});
};
}

Wyświetl plik

@ -5,16 +5,18 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Column from '../ui/components/column';
import { fetchUsers } from 'soapbox/actions/admin';
import IconButton from 'soapbox/components/icon_button';
import ScrollableList from 'soapbox/components/scrollable_list';
import { fetchUsers, deleteUsers, approveUsers } from 'soapbox/actions/admin';
const messages = defineMessages({
heading: { id: 'column.admin.awaiting_approval', defaultMessage: 'Awaiting Approval' },
});
const mapStateToProps = state => {
const userIds = state.getIn(['admin', 'awaitingApproval']);
const nicknames = state.getIn(['admin', 'awaitingApproval']);
return {
users: userIds.map(id => state.getIn(['admin', 'users', id])),
users: nicknames.toList().map(nickname => state.getIn(['admin', 'users', nickname])),
};
};
@ -27,18 +29,52 @@ class AwaitingApproval extends ImmutablePureComponent {
users: ImmutablePropTypes.list.isRequired,
};
state = {
isLoading: true,
}
componentDidMount() {
this.props.dispatch(fetchUsers({ page: 1, filters: 'local,need_approval' }));
const { dispatch } = this.props;
const params = { page: 1, filters: 'local,need_approval' };
dispatch(fetchUsers(params))
.then(() => this.setState({ isLoading: false }))
.catch(() => {});
}
handleApprove = nickname => {
const { dispatch } = this.props;
return e => {
dispatch(approveUsers([nickname]));
};
}
handleReject = nickname => {
const { dispatch } = this.props;
return e => {
dispatch(deleteUsers([nickname]));
};
}
render() {
const { intl, users } = this.props;
const { isLoading } = this.state;
return (
<Column icon='user' heading={intl.formatMessage(messages.heading)} backBtnSlim>
{users.map((user, i) => (
<div key={i}>{user.get('nickname')}</div>
))}
<ScrollableList isLoading={isLoading} showLoading={isLoading} scrollKey='awaiting-approval'>
{users.map((user, i) => (
<div className='unapproved-account' key={user.get('id')}>
<div className='unapproved-account__bio'>
<div className='unapproved-account__nickname'>@{user.get('nickname')}</div>
<blockquote className='unapproved-account__reason'>{user.get('registration_reason')}</blockquote>
</div>
<div className='unapproved-account__actions'>
<IconButton icon='check' onClick={this.handleApprove(user.get('nickname'))} />
<IconButton icon='close' onClick={this.handleReject(user.get('nickname'))} />
</div>
</div>
))}
</ScrollableList>
</Column>
);
}

Wyświetl plik

@ -1,6 +1,8 @@
import {
ADMIN_REPORTS_FETCH_SUCCESS,
ADMIN_USERS_FETCH_SUCCESS,
ADMIN_USERS_DELETE_SUCCESS,
ADMIN_USERS_APPROVE_SUCCESS,
} from '../actions/admin';
import {
Map as ImmutableMap,
@ -20,9 +22,27 @@ function importUsers(state, users) {
return state.withMutations(state => {
users.forEach(user => {
if (user.approval_pending) {
state.update('awaitingApproval', orderedSet => orderedSet.add(user.id));
state.update('awaitingApproval', orderedSet => orderedSet.add(user.nickname));
}
state.setIn(['users', user.id], fromJS(user));
state.setIn(['users', user.nickname], fromJS(user));
});
});
}
function deleteUsers(state, nicknames) {
return state.withMutations(state => {
nicknames.forEach(nickname => {
state.update('awaitingApproval', orderedSet => orderedSet.delete(nickname));
state.deleteIn(['users', nickname]);
});
});
}
function approveUsers(state, users) {
return state.withMutations(state => {
users.forEach(user => {
state.update('awaitingApproval', orderedSet => orderedSet.delete(user.nickname));
state.setIn(['users', user.nickname], fromJS(user));
});
});
}
@ -39,6 +59,10 @@ export default function admin(state = initialState, action) {
}
case ADMIN_USERS_FETCH_SUCCESS:
return importUsers(state, action.data.users);
case ADMIN_USERS_DELETE_SUCCESS:
return deleteUsers(state, action.nicknames);
case ADMIN_USERS_APPROVE_SUCCESS:
return approveUsers(state, action.users);
default:
return state;
}

Wyświetl plik

@ -67,3 +67,30 @@
border-bottom: 1px solid var(--accent-color--med);
}
}
.unapproved-account {
padding: 15px 20px;
font-size: 14px;
display: flex;
&__nickname {
font-weight: bold;
}
&__reason {
padding: 5px 0 5px 15px;
border-left: 3px solid hsla(var(--primary-text-color_hsl), 0.4);
color: var(--primary-text-color--faint);
}
&__actions {
margin-left: auto;
padding-left: 20px;
display: flex;
flex-wrap: nowrap;
}
}
.slist .item-list article:nth-child(2n-1) .unapproved-account {
background-color: hsla(var(--accent-color_hsl), 0.07);
}