Merge branch 'mrf-config-updates' into 'develop'

EditFederationModal: use ConfigDB directly instead of /api/v1/instance

See merge request soapbox-pub/soapbox-fe!649
This commit is contained in:
Alex Gleason 2021-07-28 22:37:09 +00:00
commit 67d68b7efb
9 changed files with 118 additions and 55 deletions

View file

@ -82,10 +82,10 @@ export function updateConfig(configs) {
dispatch({ type: ADMIN_CONFIG_UPDATE_REQUEST, configs });
return api(getState)
.post('/api/pleroma/admin/config', { configs })
.then(({ data: { configs } }) => {
dispatch({ type: ADMIN_CONFIG_UPDATE_SUCCESS, configs });
.then(({ data }) => {
dispatch({ type: ADMIN_CONFIG_UPDATE_SUCCESS, configs: data.configs, needsReboot: data.need_reboot });
}).catch(error => {
dispatch({ type: ADMIN_CONFIG_UPDATE_FAIL, error });
dispatch({ type: ADMIN_CONFIG_UPDATE_FAIL, error, configs });
});
};
}

View file

@ -1,6 +1,6 @@
import { fetchInstance } from './instance';
import { updateConfig } from './admin';
import { fetchConfig, updateConfig } from './admin';
import { Set as ImmutableSet } from 'immutable';
import ConfigDB from 'soapbox/utils/config_db';
const simplePolicyMerge = (simplePolicy, host, restrictions) => {
return simplePolicy.map((hosts, key) => {
@ -14,31 +14,15 @@ const simplePolicyMerge = (simplePolicy, host, restrictions) => {
});
};
const simplePolicyToConfig = simplePolicy => {
const value = simplePolicy.map((hosts, key) => (
{ tuple: [`:${key}`, hosts.toJS()] }
)).toList();
return [{
group: ':pleroma',
key: ':mrf_simple',
value,
}];
};
export function updateMrf(host, restrictions) {
return (dispatch, getState) => {
return dispatch(fetchInstance())
return dispatch(fetchConfig())
.then(() => {
const simplePolicy = getState().getIn(['instance', 'pleroma', 'metadata', 'federation', 'mrf_simple']);
const configs = getState().getIn(['admin', 'configs']);
const simplePolicy = ConfigDB.toSimplePolicy(configs);
const merged = simplePolicyMerge(simplePolicy, host, restrictions);
const config = simplePolicyToConfig(merged);
const config = ConfigDB.fromSimplePolicy(merged);
dispatch(updateConfig(config));
// TODO: Make this less insane
setTimeout(() => {
dispatch(fetchInstance());
}, 1000);
});
};
}

View file

@ -4,21 +4,11 @@ import { defineMessages, injectIntl } from 'react-intl';
import PropTypes from 'prop-types';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Column from '../ui/components/column';
import { createSelector } from 'reselect';
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
import RestrictedInstance from './components/restricted_instance';
import Accordion from 'soapbox/features/ui/components/accordion';
import ScrollableList from 'soapbox/components/scrollable_list';
import { federationRestrictionsDisclosed } from 'soapbox/utils/state';
const getHosts = createSelector([
state => state.getIn(['instance', 'pleroma', 'metadata', 'federation', 'mrf_simple'], ImmutableMap()),
], (simplePolicy) => {
return simplePolicy
.deleteAll(['accept', 'reject_deletes', 'report_removal'])
.reduce((acc, hosts) => acc.union(hosts), ImmutableOrderedSet())
.sort();
});
import { makeGetHosts } from 'soapbox/selectors';
const messages = defineMessages({
heading: { id: 'column.federation_restrictions', defaultMessage: 'Federation Restrictions' },
@ -28,6 +18,8 @@ const messages = defineMessages({
notDisclosed: { id: 'federation_restrictions.not_disclosed_message', defaultMessage: '{siteTitle} does not disclose federation restrictions through the API.' },
});
const getHosts = makeGetHosts();
const mapStateToProps = state => ({
siteTitle: state.getIn(['instance', 'title']),
hosts: getHosts(state),

View file

@ -6,7 +6,7 @@ import { connect } from 'react-redux';
import { defineMessages, injectIntl } from 'react-intl';
import { SimpleForm, Checkbox } from 'soapbox/features/forms';
import { makeGetRemoteInstance } from 'soapbox/selectors';
import { Map as ImmutableMap } from 'immutable';
import { Map as ImmutableMap, is } from 'immutable';
import { updateMrf } from 'soapbox/actions/mrf';
import snackbar from 'soapbox/actions/snackbar';
@ -41,11 +41,23 @@ class EditFederationModal extends ImmutablePureComponent {
data: ImmutableMap(),
}
componentDidMount() {
hydrateState = () => {
const { remoteInstance } = this.props;
this.setState({ data: remoteInstance.get('federation') });
}
componentDidMount() {
this.hydrateState();
}
componentDidUpdate(prevProps) {
const { remoteInstance } = this.props;
if (!is(prevProps.remoteInstance, remoteInstance)) {
this.hydrateState();
}
}
handleDataChange = key => {
return ({ target }) => {
const { data } = this.state;

View file

@ -9,9 +9,11 @@ import LinkFooter from 'soapbox/features/ui/components/link_footer';
import { getFeatures } from 'soapbox/utils/features';
import InstanceInfoPanel from 'soapbox/features/ui/components/instance_info_panel';
import { federationRestrictionsDisclosed } from 'soapbox/utils/state';
import { isAdmin } from 'soapbox/utils/accounts';
const mapStateToProps = state => {
const me = state.get('me');
const account = state.getIn(['accounts', me]);
const features = getFeatures(state.get('instance'));
return {
@ -19,6 +21,7 @@ const mapStateToProps = state => {
showTrendsPanel: features.trends,
showWhoToFollowPanel: features.suggestions,
disclosed: federationRestrictionsDisclosed(state),
isAdmin: isAdmin(account),
};
};
@ -26,7 +29,7 @@ export default @connect(mapStateToProps)
class RemoteInstancePage extends ImmutablePureComponent {
render() {
const { me, children, showTrendsPanel, showWhoToFollowPanel, params: { instance: host }, disclosed } = this.props;
const { me, children, showTrendsPanel, showWhoToFollowPanel, params: { instance: host }, disclosed, isAdmin } = this.props;
return (
<div className='page'>
@ -35,7 +38,7 @@ class RemoteInstancePage extends ImmutablePureComponent {
<div className='columns-area__panels__pane columns-area__panels__pane--left'>
<div className='columns-area__panels__pane__inner'>
{disclosed && <InstanceInfoPanel host={host} />}
{(disclosed || isAdmin) && <InstanceInfoPanel host={host} />}
</div>
</div>

View file

@ -1,5 +1,6 @@
import {
ADMIN_CONFIG_FETCH_SUCCESS,
ADMIN_CONFIG_UPDATE_SUCCESS,
ADMIN_REPORTS_FETCH_SUCCESS,
ADMIN_REPORTS_PATCH_REQUEST,
ADMIN_REPORTS_PATCH_SUCCESS,
@ -127,6 +128,7 @@ function handleReportDiffs(state, reports) {
export default function admin(state = initialState, action) {
switch(action.type) {
case ADMIN_CONFIG_FETCH_SUCCESS:
case ADMIN_CONFIG_UPDATE_SUCCESS:
return state.set('configs', fromJS(action.configs));
case ADMIN_REPORTS_FETCH_SUCCESS:
return importReports(state, action.reports);

View file

@ -51,15 +51,23 @@ const getConfigValue = (instanceConfig, key) => {
const importConfigs = (state, configs) => {
// FIXME: This is pretty hacked together. Need to make a cleaner map.
const config = ConfigDB.find(configs, ':pleroma', ':instance');
if (!config) return state;
const value = config.get('value', ImmutableList());
const simplePolicy = ConfigDB.toSimplePolicy(configs);
if (!config && !simplePolicy) return state;
return state.withMutations(state => {
const registrationsOpen = getConfigValue(value, ':registrations_open');
const approvalRequired = getConfigValue(value, ':account_approval_required');
if (config) {
const value = config.get('value', ImmutableList());
const registrationsOpen = getConfigValue(value, ':registrations_open');
const approvalRequired = getConfigValue(value, ':account_approval_required');
state.update('registrations', c => typeof registrationsOpen === 'boolean' ? registrationsOpen : c);
state.update('approval_required', c => typeof approvalRequired === 'boolean' ? approvalRequired : c);
state.update('registrations', c => typeof registrationsOpen === 'boolean' ? registrationsOpen : c);
state.update('approval_required', c => typeof approvalRequired === 'boolean' ? approvalRequired : c);
}
if (simplePolicy) {
state.setIn(['pleroma', 'metadata', 'federation', 'mrf_simple'], simplePolicy);
}
});
};

View file

@ -1,6 +1,11 @@
import { createSelector } from 'reselect';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import {
Map as ImmutableMap,
List as ImmutableList,
OrderedSet as ImmutableOrderedSet,
} from 'immutable';
import { getDomain } from 'soapbox/utils/accounts';
import ConfigDB from 'soapbox/utils/config_db';
const getAccountBase = (state, id) => state.getIn(['accounts', id], null);
const getAccountCounters = (state, id) => state.getIn(['accounts_counters', id], null);
@ -217,22 +222,38 @@ export const makeGetOtherAccounts = () => {
});
};
const getSimplePolicy = createSelector([
state => state.getIn(['admin', 'configs'], ImmutableMap()),
state => state.getIn(['instance', 'pleroma', 'metadata', 'federation', 'mrf_simple'], ImmutableMap()),
], (configs, instancePolicy) => {
return instancePolicy.merge(ConfigDB.toSimplePolicy(configs));
});
const getRemoteInstanceFavicon = (state, host) => (
state.get('accounts')
.find(account => getDomain(account) === host, null, ImmutableMap())
.getIn(['pleroma', 'favicon'])
);
const getSimplePolicy = (state, host) => (
state.getIn(['instance', 'pleroma', 'metadata', 'federation', 'mrf_simple'], ImmutableMap())
const getRemoteInstanceFederation = (state, host) => (
getSimplePolicy(state)
.map(hosts => hosts.includes(host))
);
export const makeGetHosts = () => {
return createSelector([getSimplePolicy], (simplePolicy) => {
return simplePolicy
.deleteAll(['accept', 'reject_deletes', 'report_removal'])
.reduce((acc, hosts) => acc.union(hosts), ImmutableOrderedSet())
.sort();
});
};
export const makeGetRemoteInstance = () => {
return createSelector([
(state, host) => host,
getRemoteInstanceFavicon,
getSimplePolicy,
getRemoteInstanceFederation,
], (host, favicon, federation) => {
return ImmutableMap({
host,

View file

@ -1,9 +1,50 @@
import {
Map as ImmutableMap,
List as ImmutableList,
Set as ImmutableSet,
fromJS,
} from 'immutable';
import { trimStart } from 'lodash';
const find = (configs, group, key) => {
return configs.find(config =>
config.isSuperset({ group, key }),
);
};
const toSimplePolicy = configs => {
const config = find(configs, ':pleroma', ':mrf_simple');
const reducer = (acc, curr) => {
const { tuple: [key, hosts] } = curr.toJS();
return acc.set(trimStart(key, ':'), ImmutableSet(hosts));
};
if (config && config.get) {
const value = config.get('value', ImmutableList());
return value.reduce(reducer, ImmutableMap());
} else {
return ImmutableMap();
}
};
const fromSimplePolicy = simplePolicy => {
const mapper = (hosts, key) => fromJS({ tuple: [`:${key}`, hosts.toJS()] });
const value = simplePolicy.map(mapper).toList();
return ImmutableList([
ImmutableMap({
group: ':pleroma',
key: ':mrf_simple',
value,
}),
]);
};
export const ConfigDB = {
find: (configs, group, key) => {
return configs.find(config =>
config.isSuperset({ group, key }),
);
},
find,
toSimplePolicy,
fromSimplePolicy,
};
export default ConfigDB;