kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Remove instance normalizer
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>environments/review-instance-v-jevtvk/deployments/4239
rodzic
3a60dee4c7
commit
59115c8dc5
|
@ -1,13 +1,13 @@
|
|||
import { __stub } from 'soapbox/api';
|
||||
import { buildGroup } from 'soapbox/jest/factory';
|
||||
import { renderHook, waitFor } from 'soapbox/jest/test-helpers';
|
||||
import { normalizeInstance } from 'soapbox/normalizers';
|
||||
import { instanceSchema } from 'soapbox/schemas';
|
||||
|
||||
import { useGroups } from './useGroups';
|
||||
|
||||
const group = buildGroup({ id: '1', display_name: 'soapbox' });
|
||||
const store = {
|
||||
instance: normalizeInstance({
|
||||
instance: instanceSchema.parse({
|
||||
version: '3.4.1 (compatible; TruthSocial 1.0.0+unreleased)',
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -2,14 +2,14 @@ import { __stub } from 'soapbox/api';
|
|||
import { Entities } from 'soapbox/entity-store/entities';
|
||||
import { buildAccount, buildGroup } from 'soapbox/jest/factory';
|
||||
import { renderHook, waitFor } from 'soapbox/jest/test-helpers';
|
||||
import { normalizeInstance } from 'soapbox/normalizers';
|
||||
import { instanceSchema } from 'soapbox/schemas';
|
||||
|
||||
import { usePendingGroups } from './usePendingGroups';
|
||||
|
||||
const id = '1';
|
||||
const group = buildGroup({ id, display_name: 'soapbox' });
|
||||
const store = {
|
||||
instance: normalizeInstance({
|
||||
instance: instanceSchema.parse({
|
||||
version: '3.4.1 (compatible; TruthSocial 1.0.0+unreleased)',
|
||||
}),
|
||||
me: '1',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
|
||||
import { fireEvent, render, screen } from 'soapbox/jest/test-helpers';
|
||||
import { normalizeInstance } from 'soapbox/normalizers';
|
||||
import { instanceSchema } from 'soapbox/schemas';
|
||||
|
||||
import LoginForm from './login-form';
|
||||
|
||||
|
@ -9,7 +9,7 @@ describe('<LoginForm />', () => {
|
|||
it('renders for Pleroma', () => {
|
||||
const mockFn = vi.fn();
|
||||
const store = {
|
||||
instance: normalizeInstance({
|
||||
instance: instanceSchema.parse({
|
||||
version: '2.7.2 (compatible; Pleroma 2.3.0)',
|
||||
}),
|
||||
};
|
||||
|
@ -22,7 +22,7 @@ describe('<LoginForm />', () => {
|
|||
it('renders for Mastodon', () => {
|
||||
const mockFn = vi.fn();
|
||||
const store = {
|
||||
instance: normalizeInstance({
|
||||
instance: instanceSchema.parse({
|
||||
version: '3.0.0',
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from 'react';
|
||||
|
||||
import { render, screen } from 'soapbox/jest/test-helpers';
|
||||
import { normalizeInstance } from 'soapbox/normalizers';
|
||||
import { instanceSchema } from 'soapbox/schemas';
|
||||
|
||||
import LoginPage from './login-page';
|
||||
|
||||
describe('<LoginPage />', () => {
|
||||
it('renders correctly on load', () => {
|
||||
const store = {
|
||||
instance: normalizeInstance({
|
||||
instance: instanceSchema.parse({
|
||||
version: '2.7.2 (compatible; Pleroma 2.3.0)',
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -3,12 +3,12 @@ import React from 'react';
|
|||
import { __stub } from 'soapbox/api';
|
||||
import { buildGroup } from 'soapbox/jest/factory';
|
||||
import { render, screen, waitFor } from 'soapbox/jest/test-helpers';
|
||||
import { normalizeInstance } from 'soapbox/normalizers';
|
||||
import { instanceSchema } from 'soapbox/schemas';
|
||||
|
||||
import Search from './search';
|
||||
|
||||
const store = {
|
||||
instance: normalizeInstance({
|
||||
instance: instanceSchema.parse({
|
||||
version: '3.4.1 (compatible; TruthSocial 1.0.0+unreleased)',
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
|
||||
import { buildAccount } from 'soapbox/jest/factory';
|
||||
import { render, screen, waitFor } from 'soapbox/jest/test-helpers';
|
||||
import { normalizeInstance } from 'soapbox/normalizers';
|
||||
import { instanceSchema } from 'soapbox/schemas';
|
||||
|
||||
import Discover from './discover';
|
||||
|
||||
|
@ -32,7 +32,7 @@ const store: any = {
|
|||
},
|
||||
}),
|
||||
},
|
||||
instance: normalizeInstance({
|
||||
instance: instanceSchema.parse({
|
||||
version: '3.4.1 (compatible; TruthSocial 1.0.0)',
|
||||
software: 'TRUTHSOCIAL',
|
||||
}),
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { __stub } from 'soapbox/api';
|
||||
import { buildAccount, buildGroup, buildGroupRelationship } from 'soapbox/jest/factory';
|
||||
import { renderHook, waitFor } from 'soapbox/jest/test-helpers';
|
||||
import { normalizeInstance } from 'soapbox/normalizers';
|
||||
import { instanceSchema } from 'soapbox/schemas';
|
||||
|
||||
import { useGroupsPath } from './useGroupsPath';
|
||||
|
||||
describe('useGroupsPath()', () => {
|
||||
test('without the groupsDiscovery feature', () => {
|
||||
const store = {
|
||||
instance: normalizeInstance({
|
||||
instance: instanceSchema.parse({
|
||||
version: '2.7.2 (compatible; Pleroma 2.3.0)',
|
||||
}),
|
||||
};
|
||||
|
@ -24,7 +24,7 @@ describe('useGroupsPath()', () => {
|
|||
beforeEach(() => {
|
||||
const userId = '1';
|
||||
store = {
|
||||
instance: normalizeInstance({
|
||||
instance: instanceSchema.parse({
|
||||
version: '3.4.1 (compatible; TruthSocial 1.0.0+unreleased)',
|
||||
}),
|
||||
me: userId,
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import alexJson from 'soapbox/__fixtures__/pleroma-account.json';
|
||||
import { normalizeInstance } from 'soapbox/normalizers';
|
||||
import { instanceSchema } from 'soapbox/schemas';
|
||||
|
||||
import { buildAccount } from './factory';
|
||||
|
||||
/** Store with registrations open. */
|
||||
const storeOpen = { instance: normalizeInstance({ registrations: true }) };
|
||||
const storeOpen = { instance: instanceSchema.parse({ registrations: true }) };
|
||||
|
||||
/** Store with registrations closed. */
|
||||
const storeClosed = { instance: normalizeInstance({ registrations: false }) };
|
||||
const storeClosed = { instance: instanceSchema.parse({ registrations: false }) };
|
||||
|
||||
/** Store with a logged-in user. */
|
||||
const storeLoggedIn = {
|
||||
|
|
|
@ -13,7 +13,6 @@ export { FilterStatusRecord, normalizeFilterStatus } from './filter-status';
|
|||
export { normalizeGroup } from './group';
|
||||
export { GroupRelationshipRecord, normalizeGroupRelationship } from './group-relationship';
|
||||
export { HistoryRecord, normalizeHistory } from './history';
|
||||
export { InstanceRecord, normalizeInstance } from './instance';
|
||||
export { ListRecord, normalizeList } from './list';
|
||||
export { LocationRecord, normalizeLocation } from './location';
|
||||
export { MentionRecord, normalizeMention } from './mention';
|
||||
|
|
|
@ -1,214 +0,0 @@
|
|||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
||||
import { normalizeInstance } from './instance';
|
||||
|
||||
describe('normalizeInstance()', () => {
|
||||
it('normalizes an empty Map', () => {
|
||||
const expected = {
|
||||
approval_required: false,
|
||||
contact_account: {},
|
||||
configuration: {
|
||||
media_attachments: {},
|
||||
chats: {
|
||||
max_characters: 5000,
|
||||
max_media_attachments: 1,
|
||||
},
|
||||
polls: {
|
||||
max_options: 4,
|
||||
max_characters_per_option: 25,
|
||||
min_expiration: 300,
|
||||
max_expiration: 2629746,
|
||||
},
|
||||
statuses: {
|
||||
max_characters: 500,
|
||||
max_media_attachments: 4,
|
||||
},
|
||||
groups: {
|
||||
max_characters_name: 50,
|
||||
max_characters_description: 160,
|
||||
},
|
||||
},
|
||||
description: '',
|
||||
description_limit: 1500,
|
||||
email: '',
|
||||
feature_quote: false,
|
||||
fedibird_capabilities: [],
|
||||
invites_enabled: false,
|
||||
languages: [],
|
||||
login_message: '',
|
||||
pleroma: {
|
||||
metadata: {
|
||||
account_activation_required: false,
|
||||
birthday_min_age: 0,
|
||||
birthday_required: false,
|
||||
features: [],
|
||||
federation: {
|
||||
enabled: true,
|
||||
exclusions: false,
|
||||
},
|
||||
},
|
||||
stats: {},
|
||||
},
|
||||
registrations: false,
|
||||
rules: [],
|
||||
short_description: '',
|
||||
stats: {
|
||||
domain_count: 0,
|
||||
status_count: 0,
|
||||
user_count: 0,
|
||||
},
|
||||
title: '',
|
||||
thumbnail: '',
|
||||
uri: '',
|
||||
urls: {},
|
||||
version: '0.0.0',
|
||||
nostr: {
|
||||
pubkey: undefined,
|
||||
relay: undefined,
|
||||
},
|
||||
};
|
||||
|
||||
const result = normalizeInstance(ImmutableMap());
|
||||
expect(result.toJS()).toEqual(expected);
|
||||
});
|
||||
|
||||
it('normalizes Pleroma instance with Mastodon configuration format', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/pleroma-instance.json');
|
||||
|
||||
const expected = {
|
||||
configuration: {
|
||||
statuses: {
|
||||
max_characters: 5000,
|
||||
max_media_attachments: Infinity,
|
||||
},
|
||||
polls: {
|
||||
max_options: 20,
|
||||
max_characters_per_option: 200,
|
||||
min_expiration: 0,
|
||||
max_expiration: 31536000,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = normalizeInstance(instance);
|
||||
expect(result.toJS()).toMatchObject(expected);
|
||||
});
|
||||
|
||||
it('normalizes Mastodon instance with retained configuration', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/mastodon-instance.json');
|
||||
|
||||
const expected = {
|
||||
configuration: {
|
||||
statuses: {
|
||||
max_characters: 500,
|
||||
max_media_attachments: 4,
|
||||
characters_reserved_per_url: 23,
|
||||
},
|
||||
media_attachments: {
|
||||
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,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = normalizeInstance(instance);
|
||||
expect(result.toJS()).toMatchObject(expected);
|
||||
});
|
||||
|
||||
it('normalizes Mastodon 3.0.0 instance with default configuration', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/mastodon-3.0.0-instance.json');
|
||||
|
||||
const expected = {
|
||||
configuration: {
|
||||
statuses: {
|
||||
max_characters: 500,
|
||||
max_media_attachments: 4,
|
||||
},
|
||||
polls: {
|
||||
max_options: 4,
|
||||
max_characters_per_option: 25,
|
||||
min_expiration: 300,
|
||||
max_expiration: 2629746,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = normalizeInstance(instance);
|
||||
expect(result.toJS()).toMatchObject(expected);
|
||||
});
|
||||
|
||||
it('normalizes Fedibird instance', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/fedibird-instance.json');
|
||||
const result = normalizeInstance(instance);
|
||||
|
||||
// Sets description_limit
|
||||
expect(result.description_limit).toEqual(1500);
|
||||
|
||||
// Preserves fedibird_capabilities
|
||||
expect(result.fedibird_capabilities).toEqual(fromJS(instance.fedibird_capabilities));
|
||||
});
|
||||
|
||||
it('normalizes Mitra instance', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/mitra-instance.json');
|
||||
const result = normalizeInstance(instance);
|
||||
|
||||
// Adds configuration and description_limit
|
||||
expect(result.get('configuration') instanceof ImmutableMap).toBe(true);
|
||||
expect(result.get('description_limit')).toBe(1500);
|
||||
});
|
||||
|
||||
it('normalizes GoToSocial instance', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/gotosocial-instance.json');
|
||||
const result = normalizeInstance(instance);
|
||||
|
||||
// Normalizes max_toot_chars
|
||||
expect(result.getIn(['configuration', 'statuses', 'max_characters'])).toEqual(5000);
|
||||
expect(result.has('max_toot_chars')).toBe(false);
|
||||
|
||||
// Adds configuration and description_limit
|
||||
expect(result.get('configuration') instanceof ImmutableMap).toBe(true);
|
||||
expect(result.get('description_limit')).toBe(1500);
|
||||
});
|
||||
|
||||
it('normalizes Friendica instance', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/friendica-instance.json');
|
||||
const result = normalizeInstance(instance);
|
||||
|
||||
// Normalizes max_toot_chars
|
||||
expect(result.getIn(['configuration', 'statuses', 'max_characters'])).toEqual(200000);
|
||||
expect(result.has('max_toot_chars')).toBe(false);
|
||||
|
||||
// Adds configuration and description_limit
|
||||
expect(result.get('configuration') instanceof ImmutableMap).toBe(true);
|
||||
expect(result.get('description_limit')).toBe(1500);
|
||||
});
|
||||
|
||||
it('normalizes a Mastodon RC version', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/mastodon-instance-rc.json');
|
||||
const result = normalizeInstance(instance);
|
||||
|
||||
expect(result.version).toEqual('3.5.0-rc1');
|
||||
});
|
||||
|
||||
it('normalizes Pixelfed instance', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/pixelfed-instance.json');
|
||||
const result = normalizeInstance(instance);
|
||||
expect(result.title).toBe('pixelfed');
|
||||
});
|
||||
|
||||
it('renames Akkoma to Pleroma', async () => {
|
||||
const instance = await import('soapbox/__fixtures__/akkoma-instance.json');
|
||||
const result = normalizeInstance(instance);
|
||||
|
||||
expect(result.version).toEqual('2.7.2 (compatible; Pleroma 2.4.50+akkoma)');
|
||||
});
|
||||
});
|
|
@ -1,164 +0,0 @@
|
|||
/**
|
||||
* Instance normalizer:
|
||||
* Converts API instances into our internal format.
|
||||
* @see {@link https://docs.joinmastodon.org/entities/instance/}
|
||||
*/
|
||||
import {
|
||||
Map as ImmutableMap,
|
||||
List as ImmutableList,
|
||||
Record as ImmutableRecord,
|
||||
fromJS,
|
||||
} from 'immutable';
|
||||
|
||||
import { parseVersion, PLEROMA } from 'soapbox/utils/features';
|
||||
import { mergeDefined } from 'soapbox/utils/normalizers';
|
||||
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>(),
|
||||
configuration: ImmutableMap<string, any>({
|
||||
media_attachments: ImmutableMap<string, any>(),
|
||||
chats: ImmutableMap<string, number>({
|
||||
max_characters: 5000,
|
||||
max_media_attachments: 1,
|
||||
}),
|
||||
polls: ImmutableMap<string, number>({
|
||||
max_options: 4,
|
||||
max_characters_per_option: 25,
|
||||
min_expiration: 300,
|
||||
max_expiration: 2629746,
|
||||
}),
|
||||
statuses: ImmutableMap<string, number>({
|
||||
max_characters: 500,
|
||||
max_media_attachments: 4,
|
||||
}),
|
||||
groups: ImmutableMap<string, number>({
|
||||
max_characters_name: 50,
|
||||
max_characters_description: 160,
|
||||
}),
|
||||
}),
|
||||
description: '',
|
||||
description_limit: 1500,
|
||||
email: '',
|
||||
feature_quote: false,
|
||||
fedibird_capabilities: ImmutableList(),
|
||||
invites_enabled: false,
|
||||
languages: ImmutableList(),
|
||||
login_message: '',
|
||||
pleroma: ImmutableMap<string, any>({
|
||||
metadata: ImmutableMap<string, any>({
|
||||
account_activation_required: false,
|
||||
birthday_min_age: 0,
|
||||
birthday_required: false,
|
||||
features: ImmutableList(),
|
||||
federation: ImmutableMap<string, any>({
|
||||
enabled: true,
|
||||
exclusions: false,
|
||||
}),
|
||||
}),
|
||||
stats: ImmutableMap(),
|
||||
}),
|
||||
registrations: false,
|
||||
rules: ImmutableList(),
|
||||
short_description: '',
|
||||
stats: ImmutableMap<string, number>({
|
||||
domain_count: 0,
|
||||
status_count: 0,
|
||||
user_count: 0,
|
||||
}),
|
||||
nostr: ImmutableMap<string, any>({
|
||||
relay: undefined as string | undefined,
|
||||
pubkey: undefined as string | undefined,
|
||||
}),
|
||||
title: '',
|
||||
thumbnail: '',
|
||||
uri: '',
|
||||
urls: ImmutableMap<string, string>(),
|
||||
version: '0.0.0',
|
||||
});
|
||||
|
||||
// Build Mastodon configuration from Pleroma instance
|
||||
const pleromaToMastodonConfig = (instance: ImmutableMap<string, any>) => {
|
||||
return ImmutableMap({
|
||||
statuses: ImmutableMap({
|
||||
max_characters: instance.get('max_toot_chars'),
|
||||
}),
|
||||
polls: ImmutableMap({
|
||||
max_options: instance.getIn(['poll_limits', 'max_options']),
|
||||
max_characters_per_option: instance.getIn(['poll_limits', 'max_option_chars']),
|
||||
min_expiration: instance.getIn(['poll_limits', 'min_expiration']),
|
||||
max_expiration: instance.getIn(['poll_limits', 'max_expiration']),
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
// Get the software's default attachment limit
|
||||
const getAttachmentLimit = (software: string | null) => software === PLEROMA ? Infinity : 4;
|
||||
|
||||
// Normalize version
|
||||
const normalizeVersion = (instance: ImmutableMap<string, any>) => {
|
||||
return instance.update('version', '0.0.0', version => {
|
||||
// Handle Mastodon release candidates
|
||||
if (new RegExp(/[0-9.]+rc[0-9]+/g).test(version)) {
|
||||
return version.split('rc').join('-rc');
|
||||
} else {
|
||||
return version;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** Rename Akkoma to Pleroma+akkoma */
|
||||
const fixAkkoma = (instance: ImmutableMap<string, any>) => {
|
||||
const version: string = instance.get('version', '');
|
||||
|
||||
if (version.includes('Akkoma')) {
|
||||
return instance.set('version', '2.7.2 (compatible; Pleroma 2.4.50+akkoma)');
|
||||
} else {
|
||||
return instance;
|
||||
}
|
||||
};
|
||||
|
||||
/** Set Takahē version to a Pleroma-like string */
|
||||
const fixTakahe = (instance: ImmutableMap<string, any>) => {
|
||||
const version: string = instance.get('version', '');
|
||||
|
||||
if (version.startsWith('takahe/')) {
|
||||
return instance.set('version', `0.0.0 (compatible; Takahe ${version.slice(7)})`);
|
||||
} else {
|
||||
return instance;
|
||||
}
|
||||
};
|
||||
|
||||
// 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 { software } = parseVersion(instance.get('version'));
|
||||
const mastodonConfig = pleromaToMastodonConfig(instance);
|
||||
|
||||
// Merge configuration
|
||||
instance.update('configuration', ImmutableMap(), configuration => (
|
||||
configuration.mergeDeepWith(mergeDefined, mastodonConfig)
|
||||
));
|
||||
|
||||
// If max attachments isn't set, check the backend software
|
||||
instance.updateIn(['configuration', 'statuses', 'max_media_attachments'], value => {
|
||||
return isNumber(value) ? value : getAttachmentLimit(software);
|
||||
});
|
||||
|
||||
// Urls can't be null, fix for Friendica
|
||||
if (instance.get('urls') === null) instance.delete('urls');
|
||||
|
||||
// Normalize version
|
||||
normalizeVersion(instance);
|
||||
fixTakahe(instance);
|
||||
fixAkkoma(instance);
|
||||
|
||||
// Merge defaults
|
||||
instance.mergeDeepWith(mergeDefined, InstanceRecord());
|
||||
}),
|
||||
);
|
||||
};
|
|
@ -12,7 +12,6 @@ import {
|
|||
FilterKeywordRecord,
|
||||
FilterStatusRecord,
|
||||
HistoryRecord,
|
||||
InstanceRecord,
|
||||
ListRecord,
|
||||
LocationRecord,
|
||||
MentionRecord,
|
||||
|
@ -41,7 +40,6 @@ type Filter = ReturnType<typeof FilterRecord>;
|
|||
type FilterKeyword = ReturnType<typeof FilterKeywordRecord>;
|
||||
type FilterStatus = ReturnType<typeof FilterStatusRecord>;
|
||||
type History = ReturnType<typeof HistoryRecord>;
|
||||
type Instance = ReturnType<typeof InstanceRecord>;
|
||||
type List = ReturnType<typeof ListRecord>;
|
||||
type Location = ReturnType<typeof LocationRecord>;
|
||||
type Mention = ReturnType<typeof MentionRecord>;
|
||||
|
@ -77,7 +75,6 @@ export {
|
|||
FilterKeyword,
|
||||
FilterStatus,
|
||||
History,
|
||||
Instance,
|
||||
List,
|
||||
Location,
|
||||
Mention,
|
||||
|
|
Ładowanie…
Reference in New Issue