Remove instance normalizer

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak
2023-10-27 17:48:21 +02:00
parent 3a60dee4c7
commit 59115c8dc5
12 changed files with 19 additions and 401 deletions

View File

@ -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';

View File

@ -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)');
});
});

View File

@ -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());
}),
);
};