Move Poll normalizer into its own module
This commit is contained in:
parent
08f219ab64
commit
6812e7bfd4
|
@ -0,0 +1,48 @@
|
|||
import { Record as ImmutableRecord, fromJS } from 'immutable';
|
||||
|
||||
import { normalizePoll } from '../poll';
|
||||
|
||||
describe('normalizePoll()', () => {
|
||||
it('adds base fields', () => {
|
||||
const poll = fromJS({ options: [{ title: 'Apples' }] });
|
||||
const result = normalizePoll(poll);
|
||||
|
||||
const expected = {
|
||||
options: [{ title: 'Apples', votes_count: 0 }],
|
||||
emojis: [],
|
||||
expired: false,
|
||||
multiple: false,
|
||||
voters_count: 0,
|
||||
votes_count: 0,
|
||||
own_votes: null,
|
||||
voted: false,
|
||||
};
|
||||
|
||||
expect(ImmutableRecord.isRecord(result)).toBe(true);
|
||||
expect(ImmutableRecord.isRecord(result.options.get(0))).toBe(true);
|
||||
expect(result.toJS()).toMatchObject(expected);
|
||||
expect(result.expires_at instanceof Date).toBe(true);
|
||||
});
|
||||
|
||||
it('normalizes a Pleroma logged-out poll', () => {
|
||||
const poll = fromJS(require('soapbox/__fixtures__/pleroma-status-with-poll.json')).get('poll');
|
||||
const result = normalizePoll(poll);
|
||||
|
||||
// Adds logged-in fields
|
||||
expect(result.voted).toBe(false);
|
||||
expect(result.own_votes).toBe(null);
|
||||
});
|
||||
|
||||
it('normalizes poll with emojis', () => {
|
||||
const poll = fromJS(require('soapbox/__fixtures__/pleroma-status-with-poll-with-emojis.json')).get('poll');
|
||||
const result = normalizePoll(poll);
|
||||
|
||||
// Emojifies poll options
|
||||
expect(result.options.get(1).title_emojified)
|
||||
.toEqual('Custom emoji <img draggable="false" class="emojione" alt=":gleason_excited:" title=":gleason_excited:" src="https://gleasonator.com/emoji/gleason_emojis/gleason_excited.png" /> ');
|
||||
|
||||
// Parses emojis as Immutable.Record's
|
||||
expect(ImmutableRecord.isRecord(result.emojis.get(0))).toBe(true);
|
||||
expect(result.emojis.get(1).shortcode).toEqual('soapbox');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* Poll normalizer:
|
||||
* Converts API polls into our internal format.
|
||||
* @see {@link https://docs.joinmastodon.org/entities/poll/}
|
||||
*/
|
||||
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 { makeEmojiMap } from 'soapbox/utils/normalizers';
|
||||
|
||||
// https://docs.joinmastodon.org/entities/poll/
|
||||
const PollRecord = ImmutableRecord({
|
||||
emojis: ImmutableList(),
|
||||
expired: false,
|
||||
expires_at: new Date(),
|
||||
id: '',
|
||||
multiple: false,
|
||||
options: ImmutableList(),
|
||||
voters_count: 0,
|
||||
votes_count: 0,
|
||||
own_votes: null,
|
||||
voted: false,
|
||||
});
|
||||
|
||||
// Sub-entity of Poll
|
||||
const PollOptionRecord = ImmutableRecord({
|
||||
title: '',
|
||||
votes_count: 0,
|
||||
|
||||
// Internal fields
|
||||
title_emojified: '',
|
||||
});
|
||||
|
||||
// Normalize emojis
|
||||
const normalizeEmojis = (entity: ImmutableMap<string, any>) => {
|
||||
return entity.update('emojis', ImmutableList(), emojis => {
|
||||
return emojis.map(normalizeEmoji);
|
||||
});
|
||||
};
|
||||
|
||||
const normalizePollOption = (option: ImmutableMap<string, any>, emojis: ImmutableList<ImmutableMap<string, string>> = ImmutableList()) => {
|
||||
const emojiMap = makeEmojiMap(emojis);
|
||||
const titleEmojified = emojify(escapeTextContentForBrowser(option.get('title')), emojiMap);
|
||||
|
||||
return PollOptionRecord(
|
||||
option.set('title_emojified', titleEmojified),
|
||||
);
|
||||
};
|
||||
|
||||
// Normalize poll options
|
||||
const normalizePollOptions = (poll: ImmutableMap<string, any>) => {
|
||||
const emojis = poll.get('emojis');
|
||||
|
||||
return poll.update('options', (options: ImmutableList<ImmutableMap<string, any>>) => {
|
||||
return options.map(option => normalizePollOption(option, emojis));
|
||||
});
|
||||
};
|
||||
|
||||
// Normalize own_votes to `null` if empty (like Mastodon)
|
||||
const normalizePollOwnVotes = (poll: ImmutableMap<string, any>) => {
|
||||
return poll.update('own_votes', ownVotes => {
|
||||
return ownVotes?.size > 0 ? ownVotes : null;
|
||||
});
|
||||
};
|
||||
|
||||
// Whether the user voted in the poll
|
||||
const normalizePollVoted = (poll: ImmutableMap<string, any>) => {
|
||||
return poll.update('voted', voted => {
|
||||
return typeof voted === 'boolean' ? voted : poll.get('own_votes')?.size > 0;
|
||||
});
|
||||
};
|
||||
|
||||
export const normalizePoll = (poll: ImmutableMap<string, any>) => {
|
||||
return PollRecord(
|
||||
poll.withMutations((poll: ImmutableMap<string, any>) => {
|
||||
normalizeEmojis(poll);
|
||||
normalizePollOptions(poll);
|
||||
normalizePollOwnVotes(poll);
|
||||
normalizePollVoted(poll);
|
||||
}),
|
||||
);
|
||||
};
|
|
@ -3,18 +3,17 @@
|
|||
* Converts API statuses into our internal format.
|
||||
* @see {@link https://docs.joinmastodon.org/entities/status/}
|
||||
*/
|
||||
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 { normalizeMention } from 'soapbox/normalizers/mention';
|
||||
import { normalizePoll } from 'soapbox/normalizers/poll';
|
||||
import { IStatus } from 'soapbox/types';
|
||||
import { mergeDefined, makeEmojiMap } from 'soapbox/utils/normalizers';
|
||||
import { mergeDefined } from 'soapbox/utils/normalizers';
|
||||
|
||||
// https://docs.joinmastodon.org/entities/status/
|
||||
const StatusRecord = ImmutableRecord({
|
||||
|
@ -73,29 +72,6 @@ const AttachmentRecord = ImmutableRecord({
|
|||
status: null,
|
||||
});
|
||||
|
||||
// https://docs.joinmastodon.org/entities/poll/
|
||||
const PollRecord = ImmutableRecord({
|
||||
emojis: ImmutableList(),
|
||||
expired: false,
|
||||
expires_at: new Date(),
|
||||
id: '',
|
||||
multiple: false,
|
||||
options: ImmutableList(),
|
||||
voters_count: 0,
|
||||
votes_count: 0,
|
||||
own_votes: null,
|
||||
voted: false,
|
||||
});
|
||||
|
||||
// Sub-entity of Poll
|
||||
const PollOptionRecord = ImmutableRecord({
|
||||
title: '',
|
||||
votes_count: 0,
|
||||
|
||||
// Internal fields
|
||||
title_emojified: '',
|
||||
});
|
||||
|
||||
// Ensure attachments have required fields
|
||||
const normalizeAttachment = (attachment: ImmutableMap<string, any>) => {
|
||||
const url = [
|
||||
|
@ -131,50 +107,6 @@ const normalizeEmojis = (entity: ImmutableMap<string, any>) => {
|
|||
});
|
||||
};
|
||||
|
||||
const normalizePollOption = (option: ImmutableMap<string, any>, emojis: ImmutableList<ImmutableMap<string, string>> = ImmutableList()) => {
|
||||
const emojiMap = makeEmojiMap(emojis);
|
||||
const titleEmojified = emojify(escapeTextContentForBrowser(option.get('title')), emojiMap);
|
||||
|
||||
return PollOptionRecord(
|
||||
option.set('title_emojified', titleEmojified),
|
||||
);
|
||||
};
|
||||
|
||||
// Normalize poll options
|
||||
const normalizePollOptions = (poll: ImmutableMap<string, any>) => {
|
||||
const emojis = poll.get('emojis');
|
||||
|
||||
return poll.update('options', (options: ImmutableList<ImmutableMap<string, any>>) => {
|
||||
return options.map(option => normalizePollOption(option, emojis));
|
||||
});
|
||||
};
|
||||
|
||||
// Normalize own_votes to `null` if empty (like Mastodon)
|
||||
const normalizePollOwnVotes = (poll: ImmutableMap<string, any>) => {
|
||||
return poll.update('own_votes', ownVotes => {
|
||||
return ownVotes?.size > 0 ? ownVotes : null;
|
||||
});
|
||||
};
|
||||
|
||||
// Whether the user voted in the poll
|
||||
const normalizePollVoted = (poll: ImmutableMap<string, any>) => {
|
||||
return poll.update('voted', voted => {
|
||||
return typeof voted === 'boolean' ? voted : poll.get('own_votes')?.size > 0;
|
||||
});
|
||||
};
|
||||
|
||||
// Normalize the actual poll
|
||||
const normalizePoll = (poll: ImmutableMap<string, any>) => {
|
||||
return PollRecord(
|
||||
poll.withMutations((poll: ImmutableMap<string, any>) => {
|
||||
normalizeEmojis(poll);
|
||||
normalizePollOptions(poll);
|
||||
normalizePollOwnVotes(poll);
|
||||
normalizePollVoted(poll);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
// Normalize the poll in the status, if applicable
|
||||
const normalizeStatusPoll = (status: ImmutableMap<string, any>) => {
|
||||
if (status.hasIn(['poll', 'options'])) {
|
||||
|
|
Loading…
Reference in New Issue