From 6fa973aec0e14c01127e83d33ff869754c3fb153 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 11 Mar 2022 20:48:00 -0600 Subject: [PATCH] Remove importer/normalizer.js --- app/soapbox/actions/importer/index.js | 4 +- app/soapbox/actions/importer/normalizer.js | 42 ---------- .../normalizers/__tests__/account-test.js | 14 ++++ app/soapbox/normalizers/account.ts | 84 ++++++++++++++++++- app/soapbox/normalizers/emoji.ts | 14 ++++ app/soapbox/normalizers/status.ts | 21 ++--- app/soapbox/reducers/accounts.js | 13 +-- 7 files changed, 125 insertions(+), 67 deletions(-) delete mode 100644 app/soapbox/actions/importer/normalizer.js create mode 100644 app/soapbox/normalizers/emoji.ts diff --git a/app/soapbox/actions/importer/index.js b/app/soapbox/actions/importer/index.js index 1668ad71e..ee3af3ac3 100644 --- a/app/soapbox/actions/importer/index.js +++ b/app/soapbox/actions/importer/index.js @@ -1,7 +1,5 @@ import { getSettings } from '../settings'; -import { normalizeAccount } from './normalizer'; - export const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT'; export const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT'; export const STATUS_IMPORT = 'STATUS_IMPORT'; @@ -45,7 +43,7 @@ export function importFetchedAccounts(accounts) { function processAccount(account) { if (!account.id) return; - normalAccounts.push(normalizeAccount(account)); + normalAccounts.push(account); if (account.moved) { processAccount(account.moved); diff --git a/app/soapbox/actions/importer/normalizer.js b/app/soapbox/actions/importer/normalizer.js deleted file mode 100644 index d61932957..000000000 --- a/app/soapbox/actions/importer/normalizer.js +++ /dev/null @@ -1,42 +0,0 @@ -import escapeTextContentForBrowser from 'escape-html'; - -import emojify from '../../features/emoji/emoji'; -import { unescapeHTML } from '../../utils/html'; - -const makeEmojiMap = record => record.emojis.reduce((obj, emoji) => { - obj[`:${emoji.shortcode}:`] = emoji; - return obj; -}, {}); - -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; - - account.display_name_html = emojify(escapeTextContentForBrowser(displayName), emojiMap); - account.note_emojified = emojify(account.note, emojiMap); - account.note_plain = unescapeHTML(account.note); - - if (account.fields) { - account.fields = account.fields.map(pair => ({ - ...pair, - name_emojified: emojify(escapeTextContentForBrowser(pair.name)), - value_emojified: emojify(pair.value, emojiMap), - value_plain: unescapeHTML(pair.value), - })); - } - - if (account.moved) { - account.moved = account.moved.id; - } - - return account; -} diff --git a/app/soapbox/normalizers/__tests__/account-test.js b/app/soapbox/normalizers/__tests__/account-test.js index 5199e3492..cf64fe18e 100644 --- a/app/soapbox/normalizers/__tests__/account-test.js +++ b/app/soapbox/normalizers/__tests__/account-test.js @@ -3,6 +3,20 @@ import { fromJS } from 'immutable'; import { normalizeAccount } from '../account'; describe('normalizeAccount()', () => { + it('normalizes a mention', () => { + const mention = fromJS({ + acct: 'NEETzsche@iddqd.social', + id: '9v5bw7hEGBPc9nrpzc', + url: 'https://iddqd.social/users/NEETzsche', + username: 'NEETzsche', + }); + + const result = normalizeAccount(mention); + expect(result.emojis).toEqual(fromJS([])); + expect(result.display_name).toEqual('NEETzsche'); + expect(result.verified).toBe(false); + }); + it('normalizes Fedibird birthday', () => { const account = fromJS(require('soapbox/__fixtures__/fedibird-account.json')); const result = normalizeAccount(account); diff --git a/app/soapbox/normalizers/account.ts b/app/soapbox/normalizers/account.ts index d6e81033b..04d3a8b52 100644 --- a/app/soapbox/normalizers/account.ts +++ b/app/soapbox/normalizers/account.ts @@ -1,12 +1,17 @@ +import escapeTextContentForBrowser from 'escape-html'; import { Map as ImmutableMap, List as ImmutableList, Record as ImmutableRecord, } from 'immutable'; +import emojify from 'soapbox/features/emoji/emoji'; +import { normalizeEmoji } from 'soapbox/normalizers/emoji'; import { IAccount } from 'soapbox/types'; -import { mergeDefined } from 'soapbox/utils/normalizers'; +import { unescapeHTML } from 'soapbox/utils/html'; +import { mergeDefined, makeEmojiMap } from 'soapbox/utils/normalizers'; +// https://docs.joinmastodon.org/entities/account/ const AccountRecord = ImmutableRecord({ acct: '', avatar: '', @@ -45,6 +50,18 @@ const AccountRecord = ImmutableRecord({ should_refetch: false, }); +// https://docs.joinmastodon.org/entities/field/ +const FieldRecord = ImmutableRecord({ + name: '', + value: '', + verified_at: null, + + // Internal fields + name_emojified: '', + value_emojified: '', + value_plain: '', +}); + // https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/549 const normalizePleromaLegacyFields = (account: ImmutableMap) => { return account.update('pleroma', ImmutableMap(), (pleroma: ImmutableMap) => { @@ -61,6 +78,29 @@ const normalizePleromaLegacyFields = (account: ImmutableMap) => { }); }; +// Add avatar, if missing +const normalizeAvatar = (account: ImmutableMap) => { + const avatar = account.get('avatar'); + const avatarStatic = account.get('avatar_static'); + const missing = require('images/avatar-missing.png'); + + return account.withMutations(account => { + account.set('avatar', avatar || avatarStatic || missing); + account.set('avatar_static', avatarStatic || avatar || missing); + }); +}; + +// Normalize custom fields +const normalizeFields = (account: ImmutableMap) => { + return account.update('fields', ImmutableList(), fields => fields.map(FieldRecord)); +}; + +// Normalize emojis +const normalizeEmojis = (entity: ImmutableMap) => { + const emojis = entity.get('emojis', ImmutableList()).map(normalizeEmoji); + return entity.set('emojis', emojis); +}; + // Normalize Pleroma/Fedibird birthday const normalizeBirthday = (account: ImmutableMap) => { const birthday = [ @@ -99,19 +139,55 @@ const normalizeLocation = (account: ImmutableMap) => { // Set username from acct, if applicable const fixUsername = (account: ImmutableMap) => { - return account.update('username', username => ( - username || (account.get('acct') || '').split('@')[0] - )); + const acct = account.get('acct') || ''; + const username = account.get('username') || ''; + return account.set('username', username || acct.split('@')[0]); +}; + +// Set display name from username, if applicable +const fixDisplayName = (account: ImmutableMap) => { + const displayName = account.get('display_name') || ''; + return account.set('display_name', displayName.trim().length === 0 ? account.get('username') : displayName); +}; + +// Emojification, etc +const addInternalFields = (account: ImmutableMap) => { + const emojiMap = makeEmojiMap(account.get('emojis')); + + return account.withMutations((account: ImmutableMap) => { + // Emojify account properties + account.merge({ + display_name_html: emojify(escapeTextContentForBrowser(account.get('display_name')), emojiMap), + note_emojified: emojify(account.get('note', ''), emojiMap), + note_plain: unescapeHTML(account.get('note', '')), + }); + + // Emojify fields + account.update('fields', ImmutableList(), fields => { + return fields.map((field: ImmutableMap) => { + return field.merge({ + name_emojified: emojify(escapeTextContentForBrowser(field.get('name')), emojiMap), + value_emojified: emojify(field.get('value'), emojiMap), + value_plain: unescapeHTML(field.get('value')), + }); + }); + }); + }); }; export const normalizeAccount = (account: ImmutableMap): IAccount => { return AccountRecord( account.withMutations(account => { normalizePleromaLegacyFields(account); + normalizeEmojis(account); + normalizeAvatar(account); + normalizeFields(account); normalizeVerified(account); normalizeBirthday(account); normalizeLocation(account); fixUsername(account); + fixDisplayName(account); + addInternalFields(account); }), ); }; diff --git a/app/soapbox/normalizers/emoji.ts b/app/soapbox/normalizers/emoji.ts new file mode 100644 index 000000000..4a5bb4941 --- /dev/null +++ b/app/soapbox/normalizers/emoji.ts @@ -0,0 +1,14 @@ +import { Record as ImmutableRecord, Map as ImmutableMap } from 'immutable'; + +// https://docs.joinmastodon.org/entities/emoji/ +const EmojiRecord = ImmutableRecord({ + category: '', + shortcode: '', + static_url: '', + url: '', + visible_in_picker: true, +}); + +export const normalizeEmoji = (emoji: ImmutableMap) => { + return EmojiRecord(emoji); +}; diff --git a/app/soapbox/normalizers/status.ts b/app/soapbox/normalizers/status.ts index 0ae90579a..a1af2f4dc 100644 --- a/app/soapbox/normalizers/status.ts +++ b/app/soapbox/normalizers/status.ts @@ -7,6 +7,7 @@ import { import emojify from 'soapbox/features/emoji/emoji'; import { normalizeAccount } from 'soapbox/normalizers/account'; +import { normalizeEmoji } from 'soapbox/normalizers/emoji'; import { IStatus } from 'soapbox/types'; import { mergeDefined, makeEmojiMap } from 'soapbox/utils/normalizers'; @@ -93,15 +94,6 @@ const PollOptionRecord = ImmutableRecord({ title_emojified: '', }); -// https://docs.joinmastodon.org/entities/emoji/ -const EmojiRecord = ImmutableRecord({ - category: '', - shortcode: '', - static_url: '', - url: '', - visible_in_picker: true, -}); - // Ensure attachments have required fields // https://docs.joinmastodon.org/entities/attachment/ const normalizeAttachment = (attachment: ImmutableMap) => { @@ -131,15 +123,18 @@ const normalizeMention = (mention: ImmutableMap) => { }; const normalizeMentions = (status: ImmutableMap) => { - return status.update('mentions', ImmutableList(), mentions => { - return mentions.map(normalizeMention); - }); + let mentions; + + mentions = status.get('mentions', ImmutableList()); + mentions = mentions.map(normalizeMention); + + return status.set('mentions', mentions); }; // Normalize emojis const normalizeEmojis = (entity: ImmutableMap) => { return entity.update('emojis', ImmutableList(), emojis => { - return emojis.map(EmojiRecord); + return emojis.map(normalizeEmoji); }); }; diff --git a/app/soapbox/reducers/accounts.js b/app/soapbox/reducers/accounts.js index 3e573244d..c601ed928 100644 --- a/app/soapbox/reducers/accounts.js +++ b/app/soapbox/reducers/accounts.js @@ -28,7 +28,6 @@ import { ADMIN_USERS_UNSUGGEST_FAIL, } from 'soapbox/actions/admin'; import { CHATS_FETCH_SUCCESS, CHATS_EXPAND_SUCCESS, CHAT_FETCH_SUCCESS } from 'soapbox/actions/chats'; -import { normalizeAccount as normalizeAccount2 } from 'soapbox/actions/importer/normalizer'; import { STREAMING_CHAT_UPDATE } from 'soapbox/actions/streaming'; import { normalizeAccount } from 'soapbox/normalizers/account'; @@ -40,8 +39,14 @@ import { const initialState = ImmutableMap(); +const minifyAccount = account => { + return account.mergeWith((o, n) => n || o, { + moved: account.getIn(['moved', 'id']), + }); +}; + const fixAccount = (state, account) => { - const normalized = normalizeAccount(fromJS(account)); + const normalized = minifyAccount(normalizeAccount(fromJS(account))); return state.set(account.id, normalized); }; @@ -53,9 +58,7 @@ const normalizeAccounts = (state, accounts) => { return state; }; -const importAccountFromChat = (state, chat) => - // TODO: Fix this monstrosity - fixAccount(state, normalizeAccount2(chat.account)); +const importAccountFromChat = (state, chat) => fixAccount(state, chat.account); const importAccountsFromChats = (state, chats) => state.withMutations(mutable =>