From d7bd294666cba08b6f6a8d447fbdf4cd59e66b2b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 15 Jan 2019 18:39:24 +0300 Subject: migrated some tests to normalizer, fixed some potential bug, fixed tests to use normalized naming instead of raw qvitter api objects. needs more tests tho. --- src/modules/statuses.js | 3 + src/services/api/api.service.js | 2 +- .../entity_normalizer/entity_normalizer.service.js | 212 +++++++++++++++++++++ .../status_normalizer/status_normalizer.service.js | 209 -------------------- 4 files changed, 216 insertions(+), 210 deletions(-) create mode 100644 src/services/entity_normalizer/entity_normalizer.service.js delete mode 100644 src/services/status_normalizer/status_normalizer.service.js (limited to 'src') diff --git a/src/modules/statuses.js b/src/modules/statuses.js index fde019b7..2ece12ba 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -225,6 +225,9 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us remove(timelineObject.visibleStatuses, { uri }) } }, + 'follow': (follow) => { + // NOOP, it is known status but we don't do anything about it for now + }, 'default': (unknown) => { console.log('unknown status type') console.log(unknown) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index e82f4f81..14a526ef 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -44,7 +44,7 @@ const SUGGESTIONS_URL = '/api/v1/suggestions' const MASTODON_USER_FAVORITES_TIMELINE_URL = '/api/v1/favourites' import { each, map } from 'lodash' -import { parseStatus, parseUser, parseNotification } from '../status_normalizer/status_normalizer.service.js' +import { parseStatus, parseUser, parseNotification } from '../entity_normalizer/entity_normalizer.service.js' import 'whatwg-fetch' const oldfetch = window.fetch diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js new file mode 100644 index 00000000..adc7f047 --- /dev/null +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -0,0 +1,212 @@ +const qvitterStatusType = (status) => { + if (status.is_post_verb) { + return 'status' + } + + if (status.retweeted_status) { + return 'retweet' + } + + if ((typeof status.uri === 'string' && status.uri.match(/(fave|objectType=Favourite)/)) || + (typeof status.text === 'string' && status.text.match(/favorited/))) { + return 'favorite' + } + + if (status.text.match(/deleted notice {{tag/) || status.qvitter_delete_notice) { + return 'deletion' + } + + if (status.text.match(/started following/) || status.activity_type === 'follow') { + return 'follow' + } + + return 'unknown' +} + +export const parseUser = (data) => { + const output = {} + const masto = data.hasOwnProperty('acct') + // case for users in "mentions" property for statuses in MastoAPI + const mastoShort = masto && !data.hasOwnProperty('avatar') + + output.id = data.id + + if (masto) { + output.screen_name = data.acct + + // There's nothing else to get + if (mastoShort) { + return output + } + + output.name = null // missing + output.name_html = data.display_name + + output.description = null // missing + output.description_html = data.note + + // Utilize avatar_static for gif avatars? + output.profile_image_url = data.avatar + output.profile_image_url_original = data.avatar + + // Same, utilize header_static? + output.cover_photo = data.header + + output.friends_count = data.following_count + + output.bot = data.bot + + output.statusnet_profile_url = data.url + + // Missing, trying to recover + output.is_local = !output.screen_name.includes('@') + } else { + output.screen_name = data.screen_name + + output.name = data.name + output.name_html = data.name_html + + output.description = data.description + output.description_html = data.description_html + + output.profile_image_url = data.profile_image_url + output.profile_image_url_original = data.profile_image_url_original + + output.cover_photo = data.cover_photo + + output.friends_count = data.friends_count + + output.bot = null // missing + + output.statusnet_profile_url = data.statusnet_profile_url + output.is_local = data.is_local + } + + output.created_at = new Date(data.created_at) + output.locked = data.locked + output.followers_count = data.followers_count + output.statuses_count = data.statuses_count + + return output +} + +const parseAttachment = (data) => { + // TODO A little bit messy ATM but works with both APIs + return { + ...data, + mimetype: data.mimetype || data.type + } +} + +export const parseStatus = (data) => { + const output = {} + const masto = data.hasOwnProperty('account') + + if (masto) { + output.favorited = data.favourited + output.fave_num = data.favourites_count + + output.repeated = data.reblogged + output.repeat_num = data.reblogs_count + + output.type = data.reblog ? 'retweet' : 'status' + output.nsfw = data.sensitive + + output.statusnet_html = data.content + + // Not exactly the same but works? + output.text = data.content + + output.in_reply_to_status_id = data.in_reply_to_id + output.in_reply_to_user_id = data.in_reply_to_user_id + + // Not exactly the same but works + output.statusnet_conversation_id = data.id + } else { + output.favorited = data.favorited + output.fave_num = data.fave_num + + output.repeated = data.repeated + output.repeat_num = data.repeat_num + + // catchall, temporary + // Object.assign(output, data) + + output.type = qvitterStatusType(data) + + if (data.nsfw === undefined) { + output.nsfw = isNsfw(data) + if (data.retweeted_status) { + output.nsfw = data.retweeted_status.nsfw + } + } else { + output.nsfw = data.nsfw + } + + output.statusnet_html = data.statusnet_html + output.text = data.text + + output.in_reply_to_status_id = data.in_reply_to_id + output.in_reply_to_user_id = data.in_reply_to_account_id + + output.statusnet_conversation_id = data.statusnet_conversation_id + } + + output.id = Number(data.id) + output.visibility = data.visibility + output.created_at = new Date(data.created_at) + + output.user = parseUser(masto ? data.account : data.user) + + output.attentions = ((masto ? data.mentions : data.attentions) || []) + .map(_ => ({ + id: _.id, + following: _.following // FIXME: MastoAPI doesn't have this + })) + + output.attachments = ((masto ? data.media_attachments : data.attachments) || []) + .map(parseAttachment) + + const retweetedStatus = masto ? data.reblog : data.retweeted_status + if (retweetedStatus) { + output.retweeted_status = parseStatus(retweetedStatus) + } + + return output +} + +export const parseNotification = (data) => { + const mastoDict = { + 'favourite': 'like', + 'reblog': 'repeat' + } + const masto = !data.hasOwnProperty('ntype') + const output = {} + + if (masto) { + output.type = mastoDict[data.type] || data.type + output.seen = null // missing + output.status = parseStatus(data.status) + output.action = null // missing + output.from_profile = parseUser(data.account) + } else { + const parsedNotice = parseStatus(data.notice) + output.type = data.ntype + output.seen = data.is_seen + output.status = output.type === 'like' + ? parseStatus(data.notice.favorited_status) + : parsedNotice + output.action = parsedNotice + output.from_profile = parseUser(data.from_profile) + } + + output.created_at = new Date(data.created_at) + output.id = data.id + + return output +} + +const isNsfw = (status) => { + const nsfwRegex = /#nsfw/i + return (status.tags || []).includes('nsfw') || !!status.text.match(nsfwRegex) +} diff --git a/src/services/status_normalizer/status_normalizer.service.js b/src/services/status_normalizer/status_normalizer.service.js deleted file mode 100644 index 784c7f20..00000000 --- a/src/services/status_normalizer/status_normalizer.service.js +++ /dev/null @@ -1,209 +0,0 @@ -const qvitterStatusType = (status) => { - if (status.is_post_verb) { - return 'status' - } - - if (status.retweeted_status) { - return 'retweet' - } - - if ((typeof status.uri === 'string' && status.uri.match(/(fave|objectType=Favourite)/)) || - (typeof status.text === 'string' && status.text.match(/favorited/))) { - return 'favorite' - } - - if (status.text.match(/deleted notice {{tag/) || status.qvitter_delete_notice) { - return 'deletion' - } - - if (status.text.match(/started following/) || status.activity_type === 'follow') { - return 'follow' - } - - return 'unknown' -} - -export const parseUser = (data) => { - const output = {} - const masto = data.hasOwnProperty('acct') - // case for users in "mentions" property for statuses in MastoAPI - const mastoShort = masto && !data.hasOwnProperty('avatar') - - output.id = data.id - - if (masto) { - output.screen_name = data.acct - - // There's nothing else to get - if (mastoShort) { - return output - } - - output.name = null // missing - output.name_html = data.display_name - - output.description = null // missing - output.description_html = data.note - - // Utilize avatar_static for gif avatars? - output.profile_image_url = data.avatar - output.profile_image_url_original = data.avatar - - // Same, utilize header_static? - output.cover_photo = data.header - - output.friends_count = data.following_count - - output.bot = data.bot - - output.statusnet_profile_url = data.url - - // Missing, trying to recover - output.is_local = !output.screen_name.includes('@') - } else { - output.screen_name = data.screen_name - - output.name = data.name - output.name_html = data.name_html - - output.description = data.description - output.description_html = data.description_html - - output.profile_image_url = data.profile_image_url - output.profile_image_url_original = data.profile_image_url_original - - output.cover_photo = data.cover_photo - - output.friends_count = data.friends_count - - output.bot = null // missing - - output.statusnet_profile_url = data.statusnet_profile_url - output.is_local = data.is_local - } - - output.created_at = new Date(data.created_at) - output.locked = data.locked - output.followers_count = data.followers_count - output.statuses_count = data.statuses_count - - return output -} - -const parseAttachment = (data) => { - // TODO A little bit messy ATM but works with both APIs - return { - ...data, - mimetype: data.mimetype || data.type - } -} - -export const parseStatus = (data) => { - const output = {} - const masto = data.hasOwnProperty('account') - - if (masto) { - output.favorited = data.favourited - output.fave_num = data.favourites_count - - output.repeated = data.reblogged - output.repeat_num = data.reblogs_count - - output.type = data.reblog ? 'retweet' : 'status' - output.nsfw = data.sensitive - - output.statusnet_html = data.content - - // Not exactly the same but works? - output.text = data.content - - output.in_reply_to_status_id = data.in_reply_to_id - output.in_reply_to_user_id = data.in_reply_to_user_id - - // Not exactly the same but works - output.statusnet_conversation_id = data.id - } else { - output.favorited = data.favorited - output.fave_num = data.fave_num - - output.repeated = data.repeated - output.repeat_num = data.repeat_num - - // catchall, temporary - // Object.assign(output, data) - - output.type = qvitterStatusType(data) - - if (data.nsfw === undefined) { - output.nsfw = isNsfw(data) - if (data.retweeted_status) { - output.nsfw = data.retweeted_status.nsfw - } - } - output.statusnet_html = data.statusnet_html - output.text = data.text - - output.in_reply_to_status_id = data.in_reply_to_id - output.in_reply_to_user_id = data.in_reply_to_account_id - - output.statusnet_conversation_id = data.statusnet_conversation_id - } - - output.id = Number(data.id) - output.visibility = data.visibility - output.created_at = new Date(data.created_at) - - output.user = parseUser(masto ? data.account : data.user) - - output.attentions = ((masto ? data.mentions : data.attentions) || []) - .map(_ => ({ - id: _.id, - following: _.following // FIXME: MastoAPI doesn't have this - })) - - output.attachments = ((masto ? data.media_attachments : data.attachments) || []) - .map(parseAttachment) - - const retweetedStatus = masto ? data.reblog : data.retweeted_status - if (retweetedStatus) { - output.retweeted_status = parseStatus(retweetedStatus) - } - - return output -} - -export const parseNotification = (data) => { - const mastoDict = { - 'favourite': 'like', - 'reblog': 'repeat' - } - const masto = !data.hasOwnProperty('ntype') - const output = {} - - if (masto) { - output.type = mastoDict[data.type] || data.type - output.seen = null // missing - output.status = parseStatus(data.status) - output.action = null // missing - output.from_profile = parseUser(data.account) - } else { - const parsedNotice = parseStatus(data.notice) - output.type = data.ntype - output.seen = data.is_seen - output.status = output.type === 'like' - ? parseStatus(data.notice.favorited_status) - : parsedNotice - output.action = parsedNotice - output.from_profile = parseUser(data.from_profile) - } - - output.created_at = new Date(data.created_at) - output.id = data.id - - return output -} - -const isNsfw = (status) => { - const nsfwRegex = /#nsfw/i - return (status.tags || []).includes('nsfw') || !!status.text.match(nsfwRegex) -} -- cgit v1.2.3-70-g09d2