Porównaj commity

...

9 Commity

Autor SHA1 Wiadomość Data
marcin mikołajczak f7fc865714 Fix tests
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-14 15:06:42 +01:00
marcin mikołajczak 200b863e0e Merge remote-tracking branch 'soapbox/develop' into instancev2 2023-02-14 14:59:32 +01:00
marcin mikołajczak 639c563107 fix
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-02-01 23:04:28 +01:00
marcin mikołajczak f11702acc7 Merge remote-tracking branch 'soapbox/develop' into instancev2
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2023-01-30 23:09:16 +01:00
marcin mikołajczak 9ee740d065 fix streaming url
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-12-29 00:21:48 +01:00
marcin mikołajczak c3141c4ae9 Merge remote-tracking branch 'soapbox/develop' into instancev2 2022-12-29 00:21:40 +01:00
marcin mikołajczak 6fb05cbff4 Merge remote-tracking branch 'soapbox/develop' into instancev2
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-12-28 00:28:03 +01:00
marcin mikołajczak ae0a68db36 Revert login_message changes
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-12-08 15:28:30 +01:00
marcin mikołajczak 6ecb870c88 support instanceV2
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2022-12-06 00:29:49 +01:00
18 zmienionych plików z 330 dodań i 82 usunięć

Wyświetl plik

@ -0,0 +1,128 @@
{
"domain": "mastodon.social",
"title": "Mastodon",
"version": "4.0.2",
"source_url": "https://github.com/mastodon/mastodon",
"description": "The original server operated by the Mastodon gGmbH non-profit",
"usage": { "users": { "active_month": 227900 } },
"thumbnail": {
"url": "https://files.mastodon.social/site_uploads/files/000/000/001/@1x/57c12f441d083cde.png",
"blurhash": "UeKUpFxuo~R%0nW;WCnhF6RjaJt757oJodS$",
"versions": {
"@1x": "https://files.mastodon.social/site_uploads/files/000/000/001/@1x/57c12f441d083cde.png",
"@2x": "https://files.mastodon.social/site_uploads/files/000/000/001/@2x/57c12f441d083cde.png"
}
},
"languages": ["en"],
"configuration": {
"urls": { "streaming": "wss://mastodon.social" },
"accounts": { "max_featured_tags": 10 },
"statuses": {
"max_characters": 500,
"max_media_attachments": 4,
"characters_reserved_per_url": 23
},
"media_attachments": {
"supported_mime_types": [
"image/jpeg",
"image/png",
"image/gif",
"image/heic",
"image/heif",
"image/webp",
"image/avif",
"video/webm",
"video/mp4",
"video/quicktime",
"video/ogg",
"audio/wave",
"audio/wav",
"audio/x-wav",
"audio/x-pn-wave",
"audio/vnd.wave",
"audio/ogg",
"audio/vorbis",
"audio/mpeg",
"audio/mp3",
"audio/webm",
"audio/flac",
"audio/aac",
"audio/m4a",
"audio/x-m4a",
"audio/mp4",
"audio/3gpp",
"video/x-ms-asf"
],
"image_size_limit": 10485760,
"image_matrix_limit": 16777216,
"video_size_limit": 41943040,
"video_frame_rate_limit": 60,
"video_matrix_limit": 2304000
},
"polls": {
"max_options": 4,
"max_characters_per_option": 50,
"min_expiration": 300,
"max_expiration": 2629746
},
"translation": { "enabled": true }
},
"registrations": {
"enabled": false,
"approval_required": false,
"message": null
},
"contact": {
"email": "staff@mastodon.social",
"account": {
"id": "1",
"username": "Gargron",
"acct": "Gargron",
"display_name": "Eugen Rochko",
"locked": false,
"bot": false,
"discoverable": true,
"group": false,
"created_at": "2016-03-16T00:00:00.000Z",
"note": "\u003cp\u003eFounder, CEO and lead developer \u003cspan class=\"h-card\"\u003e\u003ca href=\"https://mastodon.social/@Mastodon\" class=\"u-url mention\"\u003e@\u003cspan\u003eMastodon\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e, Germany.\u003c/p\u003e",
"url": "https://mastodon.social/@Gargron",
"avatar": "https://files.mastodon.social/accounts/avatars/000/000/001/original/dc4286ceb8fab734.jpg",
"avatar_static": "https://files.mastodon.social/accounts/avatars/000/000/001/original/dc4286ceb8fab734.jpg",
"header": "https://files.mastodon.social/accounts/headers/000/000/001/original/3b91c9965d00888b.jpeg",
"header_static": "https://files.mastodon.social/accounts/headers/000/000/001/original/3b91c9965d00888b.jpeg",
"followers_count": 263431,
"following_count": 327,
"statuses_count": 72827,
"last_status_at": "2022-12-03",
"noindex": false,
"emojis": [],
"fields": [
{
"name": "Patreon",
"value": "\u003ca href=\"https://www.patreon.com/mastodon\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"\u003e\u003cspan class=\"invisible\"\u003ehttps://www.\u003c/span\u003e\u003cspan class=\"\"\u003epatreon.com/mastodon\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e",
"verified_at": null
}
]
}
},
"rules": [
{
"id": "1",
"text": "Sexually explicit or violent media must be marked as sensitive when posting"
},
{
"id": "2",
"text": "No racism, sexism, homophobia, transphobia, xenophobia, or casteism"
},
{
"id": "3",
"text": "No incitement of violence or promotion of violent ideologies"
},
{ "id": "4", "text": "No harassment, dogpiling or doxxing of other users" },
{ "id": "5", "text": "No content illegal in Germany" },
{
"id": "7",
"text": "Do not share intentionally false or misleading information"
}
]
}

Wyświetl plik

@ -1,10 +1,11 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import get from 'lodash/get';
import { gte } from 'semver';
import KVStore from 'soapbox/storage/kv-store';
import { RootState } from 'soapbox/store';
import { getAuthUserUrl } from 'soapbox/utils/auth';
import { parseVersion } from 'soapbox/utils/features';
import { MASTODON, parseVersion, PLEROMA, REBASED } from 'soapbox/utils/features';
import api from '../api';
@ -27,25 +28,48 @@ export const getHost = (state: RootState) => {
export const rememberInstance = createAsyncThunk(
'instance/remember',
async(host: string) => {
return await KVStore.getItemOrError(`instance:${host}`);
const instance = await KVStore.getItemOrError(`instance:${host}`);
return { instance, host };
},
);
const supportsInstanceV2 = (instance: Record<string, any>): boolean => {
const v = parseVersion(get(instance, 'version'));
return (v.software === MASTODON && gte(v.compatVersion, '4.0.0')) ||
(v.software === PLEROMA && v.build === REBASED && gte(v.version, '2.5.0'));
};
/** We may need to fetch nodeinfo on Pleroma < 2.1 */
const needsNodeinfo = (instance: Record<string, any>): boolean => {
const v = parseVersion(get(instance, 'version'));
return v.software === 'Pleroma' && !get(instance, ['pleroma', 'metadata']);
return v.software === PLEROMA && !get(instance, ['pleroma', 'metadata']);
};
export const fetchInstance = createAsyncThunk<void, void, { state: RootState }>(
export const fetchInstance = createAsyncThunk<{ instance: Record<string, any>, host?: string | null }, string | null | undefined, { state: RootState }>(
'instance/fetch',
async(_arg, { dispatch, getState, rejectWithValue }) => {
async(host, { dispatch, getState, rejectWithValue }) => {
try {
const { data: instance } = await api(getState).get('/api/v1/instance');
if (supportsInstanceV2(instance)) {
return dispatch(fetchInstanceV2(host)) as any as { instance: Record<string, any>, host?: string | null };
}
if (needsNodeinfo(instance)) {
dispatch(fetchNodeinfo());
}
return instance;
return { instance, host };
} catch (e) {
return rejectWithValue(e);
}
},
);
export const fetchInstanceV2 = createAsyncThunk<{ instance: Record<string, any>, host?: string | null }, string | null | undefined, { state: RootState }>(
'instance/fetch',
async(host, { getState, rejectWithValue }) => {
try {
const { data: instance } = await api(getState).get('/api/v2/instance');
return { instance, host };
} catch (e) {
return rejectWithValue(e);
}
@ -57,10 +81,11 @@ export const loadInstance = createAsyncThunk<void, void, { state: RootState }>(
'instance/load',
async(_arg, { dispatch, getState }) => {
const host = getHost(getState());
await Promise.all([
dispatch(rememberInstance(host || '')),
dispatch(fetchInstance()),
]);
const rememberedInstance = await dispatch(rememberInstance(host || ''));
if (rememberedInstance.payload && supportsInstanceV2((rememberedInstance.payload as any).instance)) {
await dispatch(fetchInstanceV2(host));
} else dispatch(fetchInstance(host));
},
);

Wyświetl plik

@ -146,7 +146,7 @@ const SoapboxMount = () => {
<Route exact path='/about/:slug?' component={PublicLayout} />
<Route path='/login' component={AuthLayout} />
{(features.accountCreation && instance.registrations) && (
{(features.accountCreation && instance.registrations.get('enabled')) && (
<Route exact path='/signup' component={AuthLayout} />
)}

Wyświetl plik

@ -29,8 +29,8 @@ const generateConfig = (mode: RegistrationMode) => {
};
const modeFromInstance = (instance: Instance): RegistrationMode => {
if (instance.approval_required && instance.registrations) return 'approval';
return instance.registrations ? 'open' : 'closed';
if (instance.registrations.get('approval_required') && instance.registrations.get('enabled')) return 'approval';
return instance.registrations.get('enabled') ? 'open' : 'closed';
};
/** Allows changing the registration mode of the instance, eg "open", "closed", "approval" */

Wyświetl plik

@ -76,7 +76,7 @@ const Ad: React.FC<IAd> = ({ ad }) => {
<Card className='py-6 sm:p-5' variant='rounded'>
<Stack space={4}>
<HStack alignItems='center' space={3}>
<Avatar src={instance.thumbnail} size={42} />
<Avatar src={instance.thumbnail.get('url')} size={42} />
<Stack grow>
<HStack space={1}>

Wyświetl plik

@ -46,7 +46,7 @@ const RegistrationForm: React.FC<IRegistrationForm> = ({ inviteToken }) => {
const locale = settings.get('locale');
const needsConfirmation = !!instance.pleroma.getIn(['metadata', 'account_activation_required']);
const needsApproval = instance.approval_required;
const needsApproval = instance.registrations.get('approval_required');
const supportsEmailList = features.emailList;
const supportsAccountLookup = features.accountLookup;
const birthdayRequired = instance.pleroma.getIn(['metadata', 'birthday_required']);

Wyświetl plik

@ -13,7 +13,9 @@ interface IUploadCompose {
const UploadCompose: React.FC<IUploadCompose> = ({ composeId, id }) => {
const history = useHistory();
const dispatch = useAppDispatch();
const { description_limit: descriptionLimit } = useInstance();
const { pleroma } = useInstance();
const descriptionLimit = pleroma.getIn(['metadata', 'description_limit']) as number;
const media = useCompose(composeId).media_attachments.find(item => item.id === id)!;

Wyświetl plik

@ -31,6 +31,7 @@ describe('<FeedCarousel />', () => {
features: [],
}),
}),
configuration: ImmutableMap({}),
},
};
});

Wyświetl plik

@ -12,8 +12,10 @@ describe('<LandingPage />', () => {
const state = rootReducer(undefined, {
type: rememberInstance.fulfilled.type,
payload: {
version: '2.7.2 (compatible; Pleroma 2.3.0)',
registrations: true,
instance: {
version: '2.7.2 (compatible; Pleroma 2.3.0)',
registrations: true,
},
},
});
@ -29,8 +31,10 @@ describe('<LandingPage />', () => {
const state = rootReducer(undefined, {
type: rememberInstance.fulfilled.type,
payload: {
version: '2.7.2 (compatible; Pleroma 2.3.0)',
registrations: false,
instance: {
version: '2.7.2 (compatible; Pleroma 2.3.0)',
registrations: false,
},
},
});
@ -71,8 +75,10 @@ describe('<LandingPage />', () => {
const state = applyActions(undefined, [{
type: rememberInstance.fulfilled.type,
payload: {
version: '3.4.1 (compatible; TruthSocial 1.0.0)',
registrations: false,
instance: {
version: '3.4.1 (compatible; TruthSocial 1.0.0)',
registrations: false,
},
},
}, {
type: PEPE_FETCH_INSTANCE_SUCCESS,

Wyświetl plik

@ -93,7 +93,7 @@ const LandingPage = () => {
return renderProvider();
} else if (pepeEnabled && pepeOpen) {
return renderPepe();
} else if (features.accountCreation && instance.registrations) {
} else if (features.accountCreation && instance.registrations.get('enabled')) {
return renderOpen();
} else {
return renderClosed();
@ -113,7 +113,7 @@ const LandingPage = () => {
<Markup
size='lg'
dangerouslySetInnerHTML={{ __html: instance.short_description || instance.description }}
dangerouslySetInnerHTML={{ __html: instance.description }}
/>
</Stack>
</div>

Wyświetl plik

@ -359,7 +359,7 @@ const UI: React.FC<IUI> = ({ children }) => {
const dropdownMenuIsOpen = useAppSelector(state => state.dropdown_menu.openId !== null);
const accessToken = useAppSelector(state => getAccessToken(state));
const streamingUrl = instance.urls.get('streaming_api');
const streamingUrl = instance.configuration.getIn(['urls', 'streaming']);
const standalone = useAppSelector(isStandalone);
const handleDragEnter = (e: DragEvent) => {

Wyświetl plik

@ -13,10 +13,10 @@ export const useRegistrationStatus = () => {
return {
/** Registrations are open, either through Pepe or traditional account creation. */
isOpen: (features.accountCreation && instance.registrations) || (pepeEnabled && pepeOpen),
isOpen: (features.accountCreation && instance.registrations.get('enabled')) || (pepeEnabled && pepeOpen),
/** Whether Pepe is open. */
pepeOpen,
/** Whether Pepe is enabled. */
pepeEnabled,
};
};
};

Wyświetl plik

@ -5,8 +5,6 @@ import { normalizeInstance } from '../instance';
describe('normalizeInstance()', () => {
it('normalizes an empty Map', () => {
const expected = {
approval_required: false,
contact_account: {},
configuration: {
media_attachments: {},
chats: {
@ -22,13 +20,22 @@ describe('normalizeInstance()', () => {
max_characters: 500,
max_media_attachments: 4,
},
translation: {
enabled: false,
},
urls: {
streaming: '',
},
},
contact: {
account: {},
email: '',
},
description: '',
description_limit: 1500,
domain: '',
email: '',
feature_quote: false,
fedibird_capabilities: [],
invites_enabled: false,
languages: [],
login_message: '',
pleroma: {
@ -36,6 +43,7 @@ describe('normalizeInstance()', () => {
account_activation_required: false,
birthday_min_age: 0,
birthday_required: false,
description_limit: 1500,
features: [],
federation: {
enabled: true,
@ -44,18 +52,23 @@ describe('normalizeInstance()', () => {
},
stats: {},
},
registrations: false,
rules: [],
short_description: '',
stats: {
domain_count: 0,
status_count: 0,
user_count: 0,
registrations: {
approval_required: false,
enabled: false,
message: '',
},
rules: [],
source_url: '',
stats: {},
title: '',
thumbnail: '',
uri: '',
urls: {},
thumbnail: {
url: '',
},
usage: {
users: {
active_month: 0,
},
},
version: '0.0.0',
};
@ -142,7 +155,7 @@ describe('normalizeInstance()', () => {
const result = normalizeInstance(instance);
// Sets description_limit
expect(result.description_limit).toEqual(1500);
expect(result.pleroma.getIn(['metadata', 'description_limit'])).toEqual(1500);
// Preserves fedibird_capabilities
expect(result.fedibird_capabilities).toEqual(fromJS(instance.fedibird_capabilities));
@ -154,7 +167,7 @@ describe('normalizeInstance()', () => {
// Adds configuration and description_limit
expect(result.get('configuration') instanceof ImmutableMap).toBe(true);
expect(result.get('description_limit')).toBe(1500);
expect(result.pleroma.getIn(['metadata', 'description_limit'])).toBe(1500);
});
it('normalizes GoToSocial instance', () => {
@ -167,7 +180,7 @@ describe('normalizeInstance()', () => {
// Adds configuration and description_limit
expect(result.get('configuration') instanceof ImmutableMap).toBe(true);
expect(result.get('description_limit')).toBe(1500);
expect(result.pleroma.getIn(['metadata', 'description_limit'])).toBe(1500);
});
it('normalizes Friendica instance', () => {
@ -180,7 +193,7 @@ describe('normalizeInstance()', () => {
// Adds configuration and description_limit
expect(result.get('configuration') instanceof ImmutableMap).toBe(true);
expect(result.get('description_limit')).toBe(1500);
expect(result.pleroma.getIn(['metadata', 'description_limit'])).toBe(1500);
});
it('normalizes a Mastodon RC version', () => {

Wyświetl plik

@ -17,8 +17,10 @@ import { isNumber } from 'soapbox/utils/numbers';
// Use Mastodon defaults
// https://docs.joinmastodon.org/entities/instance/
export const InstanceRecord = ImmutableRecord({
approval_required: false,
contact_account: ImmutableMap<string, any>(),
contact: ImmutableMap<string, any>({
account: ImmutableMap<string, any>(),
email: '',
}),
configuration: ImmutableMap<string, any>({
media_attachments: ImmutableMap<string, any>(),
chats: ImmutableMap<string, number>({
@ -34,15 +36,31 @@ export const InstanceRecord = ImmutableRecord({
max_characters: 500,
max_media_attachments: 4,
}),
translation: ImmutableMap<string, any>({ enabled: false }),
urls: ImmutableMap<string, string>(),
}),
description: '',
description_limit: 1500,
domain: '',
email: '',
feature_quote: false,
fedibird_capabilities: ImmutableList(),
invites_enabled: false,
languages: ImmutableList(),
login_message: '',
registrations: ImmutableMap<string, any>({
approval_required: false,
enabled: false,
message: '',
}),
rules: ImmutableList(),
source_url: '',
stats: ImmutableMap<string, number>(),
title: '',
thumbnail: ImmutableMap<string, any>(),
usage: ImmutableMap<string, any>({
users: ImmutableMap<string, number>({
active_month: 0,
}),
}),
version: '0.0.0',
pleroma: ImmutableMap<string, any>({
metadata: ImmutableMap<string, any>({
account_activation_required: false,
@ -53,22 +71,15 @@ export const InstanceRecord = ImmutableRecord({
enabled: true,
exclusions: false,
}),
description_limit: 1500,
}),
stats: ImmutableMap(),
}),
registrations: false,
rules: ImmutableList(),
short_description: '',
stats: ImmutableMap<string, number>({
domain_count: 0,
status_count: 0,
user_count: 0,
}),
title: '',
thumbnail: '',
uri: '',
urls: ImmutableMap<string, string>(),
version: '0.0.0',
feature_quote: false,
fedibird_capabilities: ImmutableList(),
login_message: '',
});
// Build Mastodon configuration from Pleroma instance
@ -123,10 +134,40 @@ const fixTakahe = (instance: ImmutableMap<string, any>) => {
}
};
/** Convert /api/v1/instance format to v2 */
const fixInstanceV1 = (instance: ImmutableMap<string, any>) => {
instance.setIn(['configuration', 'urls', 'streaming'], instance.getIn(['urls', 'streaming_api'], ''));
instance.set('contact', ImmutableMap({
account: instance.get('contact_account'),
email: instance.get('email'),
}));
instance.set('description', instance.get('short_description') || instance.get('description'));
instance.set('registrations', ImmutableMap({
approval_required: instance.get('approval_required'),
enabled: instance.get('registrations'),
message: '',
}));
instance.set('thumbnail', ImmutableMap({
url: instance.get('thumbnail', ''),
}));
if (instance.has('pleroma')) {
instance.setIn(['pleroma', 'metadata', 'description_limit'], instance.get('description_limit'));
}
};
// Normalize instance (Pleroma, Mastodon, etc.) to Mastodon's format
export const normalizeInstance = (instance: Record<string, any>) => {
return InstanceRecord(
ImmutableMap(fromJS(instance)).withMutations((instance: ImmutableMap<string, any>) => {
const version = instance.has('domain') ? 'v2' : 'v1';
if (version === 'v1') fixInstanceV1(instance);
const { software } = parseVersion(instance.get('version'));
const mastodonConfig = pleromaToMastodonConfig(instance);

Wyświetl plik

@ -10,7 +10,6 @@ describe('instance reducer', () => {
const result = reducer(undefined, {} as any);
const expected = {
description_limit: 1500,
configuration: {
chats: {
max_characters: 500,
@ -37,7 +36,7 @@ describe('instance reducer', () => {
it('normalizes Pleroma instance with Mastodon configuration format', () => {
const action = {
type: rememberInstance.fulfilled.type,
payload: require('soapbox/__fixtures__/pleroma-instance.json'),
payload: { instance: require('soapbox/__fixtures__/pleroma-instance.json') },
};
const result = reducer(undefined, action);
@ -63,7 +62,7 @@ describe('instance reducer', () => {
it('normalizes Mastodon instance with retained configuration', () => {
const action = {
type: rememberInstance.fulfilled.type,
payload: require('soapbox/__fixtures__/mastodon-instance.json'),
payload: { instance: require('soapbox/__fixtures__/mastodon-instance.json') },
};
const result = reducer(undefined, action);
@ -97,7 +96,7 @@ describe('instance reducer', () => {
it('normalizes Mastodon 3.0.0 instance with default configuration', () => {
const action = {
type: rememberInstance.fulfilled.type,
payload: require('soapbox/__fixtures__/mastodon-3.0.0-instance.json'),
payload: { instance: require('soapbox/__fixtures__/mastodon-3.0.0-instance.json') },
};
const result = reducer(undefined, action);
@ -119,6 +118,40 @@ describe('instance reducer', () => {
expect(result.toJS()).toMatchObject(expected);
});
it('normalizes Mastodon 4.0.2 instance fetched with v2 endpoint', () => {
const action = {
type: rememberInstance.fulfilled.type,
payload: { instance: require('soapbox/__fixtures__/mastodon-instance-v2.json') },
};
const result = reducer(undefined, action);
const expected = {
configuration: {
statuses: {
max_characters: 500,
max_media_attachments: 4,
},
polls: {
max_options: 4,
max_characters_per_option: 50,
min_expiration: 300,
max_expiration: 2629746,
},
translation: {
enabled: true,
},
},
registrations: {
enabled: false,
approval_required: false,
message: null,
},
};
expect(result.toJS()).toMatchObject(expected);
});
});
describe('ADMIN_CONFIG_UPDATE_REQUEST', () => {
@ -130,13 +163,13 @@ describe('instance reducer', () => {
configs,
};
// The normalizer has `registrations: closed` by default
// The normalizer has `registrations.enabled: closed` by default
const state = reducer(undefined, {} as any);
expect(state.registrations).toBe(false);
expect(state.registrations.get('enabled')).toBe(false);
// After importing the configs, registration will be open
const result = reducer(state, action);
expect(result.registrations).toBe(true);
expect(result.registrations.get('enabled')).toBe(true);
});
});
});

Wyświetl plik

@ -65,8 +65,8 @@ const importConfigs = (state: typeof initialState, configs: ImmutableList<any>)
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.updateIn(['registrations', 'enabled'], c => typeof registrationsOpen === 'boolean' ? registrationsOpen : c);
state.updateIn(['registrations', 'approval_required'], c => typeof approvalRequired === 'boolean' ? approvalRequired : c);
}
if (simplePolicy) {
@ -95,8 +95,7 @@ const getHost = (instance: { uri: string }) => {
}
};
const persistInstance = (instance: { uri: string }) => {
const host = getHost(instance);
const persistInstance = (instance: { uri: string }, host: string | null = getHost(instance)) => {
if (host) {
KVStore.setItem(`instance:${host}`, instance).catch(console.error);
@ -116,14 +115,14 @@ export default function instance(state = initialState, action: AnyAction) {
case PLEROMA_PRELOAD_IMPORT:
return preloadImport(state, action, '/api/v1/instance');
case rememberInstance.fulfilled.type:
return importInstance(state, ImmutableMap(fromJS(action.payload)));
return importInstance(state, ImmutableMap(fromJS(action.payload.instance)));
case fetchInstance.fulfilled.type:
persistInstance(action.payload);
return importInstance(state, ImmutableMap(fromJS(action.payload)));
return importInstance(state, ImmutableMap(fromJS(action.payload.instance)));
case fetchInstance.rejected.type:
return handleInstanceFetchFail(state, action.error);
case fetchNodeinfo.fulfilled.type:
return importNodeinfo(state, ImmutableMap(fromJS(action.payload)));
return importNodeinfo(state, ImmutableMap(fromJS(action.payload.instance)));
case ADMIN_CONFIG_UPDATE_REQUEST:
case ADMIN_CONFIG_UPDATE_SUCCESS:
return importConfigs(state, ImmutableList(fromJS(action.configs)));

Wyświetl plik

@ -14,7 +14,7 @@ export function connectStream(
callbacks: (dispatch: AppDispatch, getState: () => RootState) => Record<string, any> = () => ({ onConnect() {}, onDisconnect() {}, onReceive() {} }),
) {
return (dispatch: AppDispatch, getState: () => RootState) => {
const streamingAPIBaseURL = getState().instance.urls.get('streaming_api');
const streamingAPIBaseURL = getState().instance.configuration.getIn(['urls', 'streaming']) as string;
const accessToken = getAccessToken(getState());
const { onConnect, onDisconnect, onReceive } = callbacks(dispatch, getState);
@ -40,7 +40,7 @@ export function connectStream(
// If the WebSocket fails to be created, don't crash the whole page,
// just proceed without a subscription.
try {
subscription = getStream(streamingAPIBaseURL!, accessToken, path, {
subscription = getStream(streamingAPIBaseURL, accessToken, path, {
connected() {
if (pollingRefresh) {
clearPolling();

Wyświetl plik

@ -802,7 +802,7 @@ const getInstanceFeatures = (instance: Instance) => {
* Can translate statuses.
* @see POST /api/v1/statuses/:id/translate
*/
translations: features.includes('translation'),
translations: features.includes('translation') || instance.configuration.getIn(['translation', 'enabled']),
/**
* Trending statuses.