From 16266f7cb43d6f9ebb328673836328f474e3ca0f Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 14 Mar 2022 18:28:13 -0500 Subject: [PATCH] reducers/instance: typescript conversion --- app/soapbox/reducers/instance.ts | 133 +++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 app/soapbox/reducers/instance.ts diff --git a/app/soapbox/reducers/instance.ts b/app/soapbox/reducers/instance.ts new file mode 100644 index 000000000..9092e685b --- /dev/null +++ b/app/soapbox/reducers/instance.ts @@ -0,0 +1,133 @@ +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; +import { AnyAction } from 'redux'; + +import { ADMIN_CONFIG_UPDATE_REQUEST, ADMIN_CONFIG_UPDATE_SUCCESS } from 'soapbox/actions/admin'; +import { PLEROMA_PRELOAD_IMPORT } from 'soapbox/actions/preload'; +import { normalizeInstance } from 'soapbox/normalizers/instance'; +import KVStore from 'soapbox/storage/kv_store'; +import { ConfigDB } from 'soapbox/utils/config_db'; + +import { + INSTANCE_REMEMBER_SUCCESS, + INSTANCE_FETCH_SUCCESS, + INSTANCE_FETCH_FAIL, + NODEINFO_FETCH_SUCCESS, +} from '../actions/instance'; + +const initialState = normalizeInstance(ImmutableMap()); + +const nodeinfoToInstance = (nodeinfo: ImmutableMap) => { + // Match Pleroma's develop branch + return normalizeInstance(ImmutableMap({ + pleroma: ImmutableMap({ + metadata: ImmutableMap({ + account_activation_required: nodeinfo.getIn(['metadata', 'accountActivationRequired']), + features: nodeinfo.getIn(['metadata', 'features']), + federation: nodeinfo.getIn(['metadata', 'federation']), + fields_limits: ImmutableMap({ + max_fields: nodeinfo.getIn(['metadata', 'fieldsLimits', 'maxFields']), + }), + }), + }), + })); +}; + +const importInstance = (_state: typeof initialState, instance: ImmutableMap) => { + return normalizeInstance(instance); +}; + +const importNodeinfo = (state: typeof initialState, nodeinfo: ImmutableMap) => { + return nodeinfoToInstance(nodeinfo).mergeDeep(state); +}; + +const preloadImport = (state: typeof initialState, action: Record, path: string) => { + const instance = action.data[path]; + return instance ? importInstance(state, ImmutableMap(fromJS(instance))) : state; +}; + +const getConfigValue = (instanceConfig: ImmutableMap, key: string) => { + const v = instanceConfig + .find(value => value.getIn(['tuple', 0]) === key); + + return v ? v.getIn(['tuple', 1]) : undefined; +}; + +const importConfigs = (state: typeof initialState, configs: ImmutableMap) => { + // FIXME: This is pretty hacked together. Need to make a cleaner map. + const config = ConfigDB.find(configs, ':pleroma', ':instance'); + const simplePolicy = ConfigDB.toSimplePolicy(configs); + + if (!config && !simplePolicy) return state; + + return state.withMutations(state => { + 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); + } + + if (simplePolicy) { + state.setIn(['pleroma', 'metadata', 'federation', 'mrf_simple'], simplePolicy); + } + }); +}; + +const handleAuthFetch = (state: typeof initialState) => { + // Authenticated fetch is enabled, so make the instance appear censored + return state.mergeWith((o, n) => o || n, { + title: '██████', + description: '████████████', + }); +}; + +const getHost = (instance: { uri: string }) => { + try { + return new URL(instance.uri).host; + } catch { + try { + return new URL(`https://${instance.uri}`).host; + } catch { + return null; + } + } +}; + +const persistInstance = (instance: { uri: string }) => { + const host = getHost(instance); + + if (host) { + KVStore.setItem(`instance:${host}`, instance).catch(console.error); + } +}; + +const handleInstanceFetchFail = (state: typeof initialState, error: Record) => { + if (error.response?.status === 401) { + return handleAuthFetch(state); + } else { + return state; + } +}; + +export default function instance(state = initialState, action: AnyAction) { + switch(action.type) { + case PLEROMA_PRELOAD_IMPORT: + return preloadImport(state, action, '/api/v1/instance'); + case INSTANCE_REMEMBER_SUCCESS: + return importInstance(state, ImmutableMap(fromJS(action.instance))); + case INSTANCE_FETCH_SUCCESS: + persistInstance(action.instance); + return importInstance(state, ImmutableMap(fromJS(action.instance))); + case INSTANCE_FETCH_FAIL: + return handleInstanceFetchFail(state, action.error); + case NODEINFO_FETCH_SUCCESS: + return importNodeinfo(state, ImmutableMap(fromJS(action.nodeinfo))); + case ADMIN_CONFIG_UPDATE_REQUEST: + case ADMIN_CONFIG_UPDATE_SUCCESS: + return importConfigs(state, ImmutableMap(fromJS(action.configs))); + default: + return state; + } +}