From 7a18f8b9c8a46b8b1f2f01a97a3f0d707898a716 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 8 Mar 2022 23:25:30 -0600 Subject: [PATCH] Create Records for Account and Status --- app/soapbox/actions/importer/normalizer.js | 7 -- .../normalizers/__tests__/instance-test.js | 53 +++++++++---- app/soapbox/normalizers/account.js | 52 +++++++++++-- app/soapbox/normalizers/instance.js | 75 ++++++++++++++----- app/soapbox/normalizers/status.js | 6 ++ .../reducers/__tests__/instance-test.js | 22 +++--- app/soapbox/reducers/accounts.js | 20 +---- 7 files changed, 160 insertions(+), 75 deletions(-) diff --git a/app/soapbox/actions/importer/normalizer.js b/app/soapbox/actions/importer/normalizer.js index 4de148c0b..f2e82c33d 100644 --- a/app/soapbox/actions/importer/normalizer.js +++ b/app/soapbox/actions/importer/normalizer.js @@ -11,13 +11,6 @@ const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => { export function normalizeAccount(account) { account = { ...account }; - // Some backends can return null, or omit these required fields - if (!account.emojis) account.emojis = []; - if (!account.display_name) account.display_name = ''; - if (!account.note) account.note = ''; - if (!account.avatar) account.avatar = account.avatar_static || require('images/avatar-missing.png'); - if (!account.avatar_static) account.avatar_static = account.avatar; - const emojiMap = makeEmojiMap(account); const displayName = account.display_name.trim().length === 0 ? account.username : account.display_name; diff --git a/app/soapbox/normalizers/__tests__/instance-test.js b/app/soapbox/normalizers/__tests__/instance-test.js index 8f992bb84..30b7aa3d2 100644 --- a/app/soapbox/normalizers/__tests__/instance-test.js +++ b/app/soapbox/normalizers/__tests__/instance-test.js @@ -4,25 +4,48 @@ import { normalizeInstance } from '../instance'; describe('normalizeInstance()', () => { it('normalizes an empty Map', () => { - const expected = ImmutableMap({ - description_limit: 1500, - configuration: ImmutableMap({ - statuses: ImmutableMap({ - max_characters: 500, - max_media_attachments: 4, - }), - polls: ImmutableMap({ + const expected = { + approval_required: false, + contact_account: {}, + configuration: { + 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: 25, min_expiration: 300, max_expiration: 2629746, - }), - }), + }, + statuses: { + max_characters: 500, + max_media_attachments: 4, + }, + }, + description: '', + description_limit: 1500, + email: '', + fedibird_capabilities: [], + invites_enabled: false, + languages: [], + pleroma: {}, + registrations: false, + rules: [], + short_description: '', + stats: {}, + title: '', + thumbnail: '', + uri: '', + urls: {}, version: '0.0.0', - }); + }; const result = normalizeInstance(ImmutableMap()); - expect(result).toEqual(expected); + expect(result.toJS()).toEqual(expected); }); it('normalizes Pleroma instance with Mastodon configuration format', () => { @@ -104,10 +127,10 @@ describe('normalizeInstance()', () => { const result = normalizeInstance(instance); // Sets description_limit - expect(result.get('description_limit')).toEqual(1500); + expect(result.description_limit).toEqual(1500); - // But otherwise, it's the same - expect(result.delete('description_limit')).toEqual(instance); + // Preserves fedibird_capabilities + expect(result.fedibird_capabilities).toEqual(instance.get('fedibird_capabilities')); }); it('normalizes Mitra instance', () => { diff --git a/app/soapbox/normalizers/account.js b/app/soapbox/normalizers/account.js index 3b4a7dc02..a2a9289b4 100644 --- a/app/soapbox/normalizers/account.js +++ b/app/soapbox/normalizers/account.js @@ -1,7 +1,43 @@ -import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; +import { Map as ImmutableMap, List as ImmutableList, Record } from 'immutable'; import { mergeDefined } from 'soapbox/utils/normalizers'; +const AccountRecord = Record({ + acct: '', + avatar: '', + avatar_static: '', + birthday: undefined, + bot: false, + created_at: new Date(), + display_name: '', + emojis: ImmutableList(), + fields: ImmutableList(), + followers_count: 0, + following_count: 0, + fqn: '', + header: '', + header_static: '', + id: '', + last_status_at: new Date(), + location: '', + locked: false, + moved: null, + note: '', + pleroma: ImmutableMap(), + source: ImmutableMap(), + statuses_count: 0, + uri: '', + url: '', + username: '', + verified: false, + + // Internal fields + display_name_html: '', + note_emojified: '', + note_plain: '', + should_refetch: false, +}); + // https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/549 const normalizePleromaLegacyFields = account => { return account.update('pleroma', ImmutableMap(), pleroma => { @@ -49,10 +85,12 @@ const normalizeLocation = account => { }; export const normalizeAccount = account => { - return account.withMutations(account => { - normalizePleromaLegacyFields(account); - normalizeVerified(account); - normalizeBirthday(account); - normalizeLocation(account); - }); + return AccountRecord( + account.withMutations(account => { + normalizePleromaLegacyFields(account); + normalizeVerified(account); + normalizeBirthday(account); + normalizeLocation(account); + }), + ); }; diff --git a/app/soapbox/normalizers/instance.js b/app/soapbox/normalizers/instance.js index 155f6c8ae..22f90fc8d 100644 --- a/app/soapbox/normalizers/instance.js +++ b/app/soapbox/normalizers/instance.js @@ -1,16 +1,20 @@ -import { Map as ImmutableMap } from 'immutable'; +import { Map as ImmutableMap, List as ImmutableList, Record } from 'immutable'; import { parseVersion, PLEROMA } from 'soapbox/utils/features'; import { mergeDefined } from 'soapbox/utils/normalizers'; import { isNumber } from 'soapbox/utils/numbers'; // Use Mastodon defaults -const baseInstance = ImmutableMap({ - description_limit: 1500, +const InstanceRecord = Record({ + approval_required: false, + contact_account: ImmutableMap(), configuration: ImmutableMap({ - statuses: ImmutableMap({ - max_characters: 500, - max_media_attachments: 4, + media_attachments: ImmutableMap({ + image_size_limit: 10485760, + image_matrix_limit: 16777216, + video_size_limit: 41943040, + video_frame_rate_limit: 60, + video_matrix_limit: 2304000, }), polls: ImmutableMap({ max_options: 4, @@ -18,7 +22,38 @@ const baseInstance = ImmutableMap({ min_expiration: 300, max_expiration: 2629746, }), + statuses: ImmutableMap({ + max_characters: 500, + max_media_attachments: 4, + }), }), + description: '', + description_limit: 1500, + email: '', + fedibird_capabilities: ImmutableList(), + invites_enabled: false, + languages: ImmutableList(), + pleroma: ImmutableMap({ + metadata: ImmutableMap({ + account_activation_required: false, + birthday_min_age: 0, + birthday_required: false, + features: ImmutableList(), + federation: ImmutableMap({ + enabled: true, + exclusions: false, + }), + }), + stats: ImmutableMap(), + }), + registrations: false, + rules: ImmutableList(), + short_description: '', + stats: ImmutableMap(), + title: '', + thumbnail: '', + uri: '', + urls: ImmutableMap(), version: '0.0.0', }); @@ -45,19 +80,21 @@ export const normalizeInstance = instance => { const { software } = parseVersion(instance.get('version')); const mastodonConfig = pleromaToMastodonConfig(instance); - return instance.withMutations(instance => { - // Merge configuration - instance.update('configuration', ImmutableMap(), configuration => ( - configuration.mergeDeepWith(mergeDefined, mastodonConfig) - )); + return InstanceRecord( + instance.withMutations(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); - }); + // If max attachments isn't set, check the backend software + instance.updateIn(['configuration', 'statuses', 'max_media_attachments'], value => { + return isNumber(value) ? value : getAttachmentLimit(software); + }); - // Merge defaults & cleanup - instance.mergeDeepWith(mergeDefined, baseInstance); - instance.deleteAll(['max_toot_chars', 'poll_limits']); - }); + // Merge defaults & cleanup + instance.mergeDeepWith(mergeDefined, InstanceRecord()); + instance.deleteAll(['max_toot_chars', 'poll_limits']); + }), + ); }; diff --git a/app/soapbox/normalizers/status.js b/app/soapbox/normalizers/status.js index fc790d846..8087f1d85 100644 --- a/app/soapbox/normalizers/status.js +++ b/app/soapbox/normalizers/status.js @@ -33,6 +33,12 @@ const StatusRecord = Record({ uri: '', url: '', visibility: 'public', + + // Internal fields + contentHtml: '', + hidden: false, + search_index: '', + spoilerHtml: '', }); const basePollOption = ImmutableMap({ title: '', votes_count: 0 }); diff --git a/app/soapbox/reducers/__tests__/instance-test.js b/app/soapbox/reducers/__tests__/instance-test.js index 17eae2e52..dcac9e29a 100644 --- a/app/soapbox/reducers/__tests__/instance-test.js +++ b/app/soapbox/reducers/__tests__/instance-test.js @@ -1,27 +1,29 @@ -import { Map as ImmutableMap } from 'immutable'; - import { INSTANCE_REMEMBER_SUCCESS } from 'soapbox/actions/instance'; import reducer from '../instance'; describe('instance reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableMap({ + const result = reducer(undefined, {}); + + const expected = { description_limit: 1500, - configuration: ImmutableMap({ - statuses: ImmutableMap({ + configuration: { + statuses: { max_characters: 500, max_media_attachments: 4, - }), - polls: ImmutableMap({ + }, + polls: { max_options: 4, max_characters_per_option: 25, min_expiration: 300, max_expiration: 2629746, - }), - }), + }, + }, version: '0.0.0', - })); + }; + + expect(result.toJS()).toMatchObject(expected); }); describe('INSTANCE_REMEMBER_SUCCESS', () => { diff --git a/app/soapbox/reducers/accounts.js b/app/soapbox/reducers/accounts.js index c3cbcb9d6..3e573244d 100644 --- a/app/soapbox/reducers/accounts.js +++ b/app/soapbox/reducers/accounts.js @@ -40,17 +40,8 @@ import { const initialState = ImmutableMap(); -const minifyAccount = account => { - return account.deleteAll([ - 'followers_count', - 'following_count', - 'statuses_count', - 'source', - ]); -}; - const fixAccount = (state, account) => { - const normalized = minifyAccount(normalizeAccount(fromJS(account))); + const normalized = normalizeAccount(fromJS(account)); return state.set(account.id, normalized); }; @@ -125,20 +116,15 @@ const removePermission = (state, accountIds, permissionGroup) => { }); }; -const buildAccount = adminUser => fromJS({ +const buildAccount = adminUser => normalizeAccount(fromJS({ id: adminUser.get('id'), username: adminUser.get('nickname').split('@')[0], acct: adminUser.get('nickname'), display_name: adminUser.get('display_name'), display_name_html: adminUser.get('display_name'), - note: '', url: adminUser.get('url'), avatar: adminUser.get('avatar'), avatar_static: adminUser.get('avatar'), - header: '', - header_static: '', - emojis: [], - fields: [], created_at: adminUser.get('created_at'), pleroma: { is_active: adminUser.get('is_active'), @@ -153,7 +139,7 @@ const buildAccount = adminUser => fromJS({ }, }, should_refetch: true, -}); +})); const mergeAdminUser = (account, adminUser) => { return account.withMutations(account => {