Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
25 KB
Referenced Files
None
Subscribers
None
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 1d90617fc0..f1a4d021ee 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -1,580 +1,422 @@
import { parseLinkHeader } from '@web3-storage/parse-link-header'
import escapeHtml from 'escape-html'
import { unescape as lodashUnescape } from 'lodash'
import punycode from 'punycode.js'
import { fileType } from '../file_type/file_type.service.js'
import { isStatusNotification } from '../notification_utils/notification_utils.js'
/** NOTICE! **
* Do not initialize UI-generated data here.
* It will override existing data.
*
* i.e. user.pinnedStatusIds was set to [] here
* UI code would update it with data but upon next user fetch
* it would be reverted back to []
*/
-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 = Object.hasOwn(data, 'acct')
// case for users in "mentions" property for statuses in MastoAPI
- const mastoShort = masto && !Object.hasOwn(data, 'avatar')
+ const mastoShort = !Object.hasOwn(data, 'avatar')
output.inLists = null
output.id = String(data.id)
output._original = data // used for server-side settings
- if (masto) {
- output.screen_name = data.acct
- output.fqn = data.fqn
- output.statusnet_profile_url = data.url
+ output.screen_name = data.acct
+ output.fqn = data.fqn
+ output.statusnet_profile_url = data.url
- if (Object.hasOwn(data, 'mute_expires_at')) {
- output.mute_expires_at =
- data.mute_expires_at == null ? false : data.mute_expires_at
- }
+ if (Object.hasOwn(data, 'mute_expires_at')) {
+ output.mute_expires_at =
+ data.mute_expires_at == null ? false : data.mute_expires_at
+ }
- if (Object.hasOwn(data, 'block_expires_at')) {
- output.block_expires_at =
- data.block_expires_at == null ? false : data.block_expires_at
- }
+ if (Object.hasOwn(data, 'block_expires_at')) {
+ output.block_expires_at =
+ data.block_expires_at == null ? false : data.block_expires_at
+ }
- // There's nothing else to get
- if (mastoShort) {
- return output
- }
+ // There's nothing else to get
+ if (mastoShort) {
+ return output
+ }
- output.emoji = data.emojis
- output.name = escapeHtml(data.display_name)
- output.name_html = output.name
- output.name_unescaped = data.display_name
-
- output.description = data.note
- // TODO cleanup this shit, output.description is overriden with source data
- output.description_html = data.note
-
- output.fields = data.fields
- output.fields_html = data.fields.map((field) => {
- return {
- name: escapeHtml(field.name),
- value: field.value,
- }
- })
- output.fields_text = data.fields.map((field) => {
- return {
- name: unescape(field.name.replace(/<[^>]*>/g, '')),
- value: unescape(field.value.replace(/<[^>]*>/g, '')),
- }
- })
-
- // 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.privileges = []
-
- if (data.pleroma) {
- if (data.pleroma.settings_store) {
- output.storage = data.pleroma.settings_store['pleroma-fe']
- output.user_highlight = data.pleroma.settings_store['user_highlight']
- }
- const relationship = data.pleroma.relationship
-
- output.background_image = data.pleroma.background_image
- output.favicon = data.pleroma.favicon
- output.token = data.pleroma.chat_token
-
- if (relationship) {
- output.relationship = relationship
- }
-
- output.allow_following_move = data.pleroma.allow_following_move
-
- output.hide_favorites = data.pleroma.hide_favorites
- output.hide_follows = data.pleroma.hide_follows
- output.hide_followers = data.pleroma.hide_followers
- output.hide_follows_count = data.pleroma.hide_follows_count
- output.hide_followers_count = data.pleroma.hide_followers_count
-
- output.rights = {
- moderator: data.pleroma.is_moderator,
- admin: data.pleroma.is_admin,
- }
- // TODO: Clean up in UI? This is duplication from what BE does for qvitterapi
- if (output.rights.admin) {
- output.role = 'admin'
- } else if (output.rights.moderator) {
- output.role = 'moderator'
- } else {
- output.role = 'member'
- }
-
- output.birthday = data.pleroma.birthday
-
- if (data.pleroma.privileges) {
- output.privileges = data.pleroma.privileges
- } else if (data.pleroma.is_admin) {
- output.privileges = [
- 'users_read',
- 'users_manage_invites',
- 'users_manage_activation_state',
- 'users_manage_tags',
- 'users_manage_credentials',
- 'users_delete',
- 'messages_read',
- 'messages_delete',
- 'instances_delete',
- 'reports_manage_reports',
- 'moderation_log_read',
- 'announcements_manage_announcements',
- 'emoji_manage_emoji',
- 'statistics_read',
- ]
- } else if (data.pleroma.is_moderator) {
- output.privileges = ['messages_delete', 'reports_manage_reports']
- } else {
- output.privileges = []
- }
- }
+ output.emoji = data.emojis
+ output.name = escapeHtml(data.display_name)
+ output.name_html = output.name
+ output.name_unescaped = data.display_name
+
+ output.description = data.note
+ // TODO cleanup this shit, output.description is overriden with source data
+ output.description_html = data.note
- if (data.source) {
- output.description = data.source.note
- output.default_scope = data.source.privacy
- output.fields = data.source.fields
- if (data.source.pleroma) {
- output.no_rich_text = data.source.pleroma.no_rich_text
- output.show_role = data.source.pleroma.show_role
- output.discoverable = data.source.pleroma.discoverable
- output.show_birthday = data.pleroma.show_birthday
- output.actor_type = data.source.pleroma.actor_type
- }
+ output.fields = data.fields
+ output.fields_html = data.fields.map((field) => {
+ return {
+ name: escapeHtml(field.name),
+ value: field.value,
+ }
+ })
+ output.fields_text = data.fields.map((field) => {
+ return {
+ name: unescape(field.name.replace(/<[^>]*>/g, '')),
+ value: unescape(field.value.replace(/<[^>]*>/g, '')),
}
+ })
- // TODO: handle is_local
- output.is_local = !output.screen_name.includes('@')
- } else {
- output.screen_name = data.screen_name
+ // 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.name = data.name
- output.name_html = data.name_html
+ output.friends_count = data.following_count
- output.description = data.description
- output.description_html = data.description_html
+ output.bot = data.bot
- output.profile_image_url = data.profile_image_url
- output.profile_image_url_original = data.profile_image_url_original
+ output.privileges = []
- output.cover_photo = data.cover_photo
+ if (data.pleroma) {
+ if (data.pleroma.settings_store) {
+ output.storage = data.pleroma.settings_store['pleroma-fe']
+ output.user_highlight = data.pleroma.settings_store['user_highlight']
+ }
+ const relationship = data.pleroma.relationship
- output.friends_count = data.friends_count
+ output.background_image = data.pleroma.background_image
+ output.favicon = data.pleroma.favicon
+ output.token = data.pleroma.chat_token
- // output.bot = ??? missing
+ if (relationship) {
+ output.relationship = relationship
+ }
- output.statusnet_profile_url = data.statusnet_profile_url
+ output.allow_following_move = data.pleroma.allow_following_move
- output.is_local = data.is_local
- output.role = data.role
- output.show_role = data.show_role
+ output.hide_favorites = data.pleroma.hide_favorites
+ output.hide_follows = data.pleroma.hide_follows
+ output.hide_followers = data.pleroma.hide_followers
+ output.hide_follows_count = data.pleroma.hide_follows_count
+ output.hide_followers_count = data.pleroma.hide_followers_count
- if (data.rights) {
- output.rights = {
- moderator: data.rights.delete_others_notice,
- admin: data.rights.admin,
- }
+ output.rights = {
+ moderator: data.pleroma.is_moderator,
+ admin: data.pleroma.is_admin,
}
- output.no_rich_text = data.no_rich_text
- output.default_scope = data.default_scope
- output.hide_follows = data.hide_follows
- output.hide_followers = data.hide_followers
- output.hide_follows_count = data.hide_follows_count
- output.hide_followers_count = data.hide_followers_count
- output.background_image = data.background_image
- // Websocket token
- output.token = data.token
-
- // Convert relationsip data to expected format
- output.relationship = {
- muting: data.muted,
- blocking: data.statusnet_blocking,
- followed_by: data.follows_you,
- following: data.following,
+ // TODO: Clean up in UI? This is duplication from what BE does for qvitterapi
+ if (output.rights.admin) {
+ output.role = 'admin'
+ } else if (output.rights.moderator) {
+ output.role = 'moderator'
+ } else {
+ output.role = 'member'
+ }
+
+ output.birthday = data.pleroma.birthday
+
+ if (data.pleroma.privileges) {
+ output.privileges = data.pleroma.privileges
+ } else if (data.pleroma.is_admin) {
+ output.privileges = [
+ 'users_read',
+ 'users_manage_invites',
+ 'users_manage_activation_state',
+ 'users_manage_tags',
+ 'users_manage_credentials',
+ 'users_delete',
+ 'messages_read',
+ 'messages_delete',
+ 'instances_delete',
+ 'reports_manage_reports',
+ 'moderation_log_read',
+ 'announcements_manage_announcements',
+ 'emoji_manage_emoji',
+ 'statistics_read',
+ ]
+ } else if (data.pleroma.is_moderator) {
+ output.privileges = ['messages_delete', 'reports_manage_reports']
+ } else {
+ output.privileges = []
}
}
+ if (data.source) {
+ output.description = data.source.note
+ output.default_scope = data.source.privacy
+ output.fields = data.source.fields
+ if (data.source.pleroma) {
+ output.no_rich_text = data.source.pleroma.no_rich_text
+ output.show_role = data.source.pleroma.show_role
+ output.discoverable = data.source.pleroma.discoverable
+ output.show_birthday = data.pleroma.show_birthday
+ output.actor_type = data.source.pleroma.actor_type
+ }
+ }
+
+ // TODO: handle is_local
+ output.is_local = !output.screen_name.includes('@')
+
output.created_at = new Date(data.created_at)
output.locked = data.locked
output.last_status_at = new Date(data.last_status_at)
output.followers_count = data.followers_count
output.statuses_count = data.statuses_count
if (data.pleroma) {
output.follow_request_count = data.pleroma.follow_request_count
output.tags = data.pleroma.tags
// deactivated was changed to is_active in Pleroma 2.3.0
// so check if is_active is present
output.deactivated =
typeof data.pleroma.is_active !== 'undefined'
? !data.pleroma.is_active // new backend
: data.pleroma.deactivated // old backend
output.notification_settings = data.pleroma.notification_settings
output.unread_chat_count = data.pleroma.unread_chat_count
}
output.tags = output.tags || []
output.rights = output.rights || {}
output.notification_settings = output.notification_settings || {}
// Convert punycode to unicode for UI
output.screen_name_ui = output.screen_name
if (output.screen_name && output.screen_name.includes('@')) {
const parts = output.screen_name.split('@')
const unicodeDomain = punycode.toUnicode(parts[1])
if (unicodeDomain !== parts[1]) {
// Add some identifier so users can potentially spot spoofing attempts:
// lain.com and xn--lin-6cd.com would appear identical otherwise.
output.screen_name_ui_contains_non_ascii = true
output.screen_name_ui = [parts[0], unicodeDomain].join('@')
} else {
output.screen_name_ui_contains_non_ascii = false
}
}
return output
}
export const parseAttachment = (data) => {
const output = {}
- const masto = !Object.hasOwn(data, 'oembed')
- if (masto) {
- // Not exactly same...
- output.mimetype = data.pleroma ? data.pleroma.mime_type : data.type
- output.meta = data.meta // not present in BE yet
- output.id = data.id
- } else {
- output.mimetype = data.mimetype
- // output.meta = ??? missing
- }
+ // Not exactly same...
+ output.mimetype = data.pleroma ? data.pleroma.mime_type : data.type
+ output.meta = data.meta // not present in BE yet
+ output.id = data.id
if (data.type !== 'unknown') {
// treat gifv like it is "video"
output.type = data.type === 'gifv' ? 'video' : data.type
} else {
output.type = fileType(output.mimetype)
}
output.url = data.url
output.large_thumb_url = data.preview_url
output.description = lodashUnescape(data.description)
return output
}
export const parseSource = (data) => {
const output = {}
output.text = data.text
output.spoiler_text = data.spoiler_text
output.content_type = data.content_type
return output
}
export const parseStatus = (data) => {
const output = {}
- const masto = Object.hasOwn(data, 'account')
-
- if (masto) {
- output.favorited = data.favourited
- output.fave_num = data.favourites_count
-
- output.repeated = data.reblogged
- output.repeat_num = data.reblogs_count
-
- output.bookmarked = data.bookmarked
-
- output.type = data.reblog ? 'retweet' : 'status'
- output.nsfw = data.sensitive
-
- output.raw_html = data.content
- output.emojis = data.emojis
-
- output.tags = data.tags
-
- output.edited_at = data.edited_at
-
- const { pleroma } = data
-
- if (data.pleroma) {
- output.text = pleroma.content
- ? data.pleroma.content['text/plain']
- : data.content
- output.summary = pleroma.spoiler_text
- ? data.pleroma.spoiler_text['text/plain']
- : data.spoiler_text
- output.statusnet_conversation_id = data.pleroma.conversation_id
- output.is_local = pleroma.local
- output.in_reply_to_screen_name = pleroma.in_reply_to_account_acct
- output.thread_muted = pleroma.thread_muted
- output.emoji_reactions = pleroma.emoji_reactions
- output.parent_visible =
- pleroma.parent_visible === undefined ? true : pleroma.parent_visible
- output.quote_visible = pleroma.quote_visible || true
- output.quotes_count = pleroma.quotes_count
- output.bookmark_folder_id = pleroma.bookmark_folder
- } else {
- output.text = data.content
- output.summary = data.spoiler_text
- }
- const quoteRaw = pleroma?.quote || data.quote
- const quoteData = quoteRaw ? parseStatus(quoteRaw) : undefined
- output.quote = quoteData
- output.quote_id =
- data.quote?.id ?? data.quote_id ?? quoteData?.id ?? pleroma?.quote_id
- output.quote_url = data.quote?.url ?? quoteData?.url ?? pleroma?.quote_url
+ output.favorited = data.favourited
+ output.fave_num = data.favourites_count
- output.in_reply_to_status_id = data.in_reply_to_id
- output.in_reply_to_user_id = data.in_reply_to_account_id
- output.replies_count = data.replies_count
+ output.repeated = data.reblogged
+ output.repeat_num = data.reblogs_count
- if (output.type === 'retweet') {
- output.retweeted_status = parseStatus(data.reblog)
- }
+ output.bookmarked = data.bookmarked
- output.summary_raw_html = escapeHtml(data.spoiler_text)
- output.external_url = data.uri || data.url
- output.poll = data.poll
- if (output.poll) {
- output.poll.options = (output.poll.options || []).map((field) => ({
- ...field,
- title_html: escapeHtml(field.title),
- }))
- }
- output.pinned = data.pinned
- output.muted = data.muted
- } else {
- output.favorited = data.favorited
- output.fave_num = data.fave_num
+ output.type = data.reblog ? 'retweet' : 'status'
+ output.nsfw = data.sensitive
- output.repeated = data.repeated
- output.repeat_num = data.repeat_num
+ output.raw_html = data.content
+ output.emojis = data.emojis
- // catchall, temporary
- // Object.assign(output, data)
+ output.tags = data.tags
- output.type = qvitterStatusType(data)
+ output.edited_at = data.edited_at
- if (data.nsfw === undefined) {
- output.nsfw = isNsfw(data)
- if (data.retweeted_status) {
- output.nsfw = data.retweeted_status.nsfw
- }
- } else {
- output.nsfw = data.nsfw
- }
+ const { pleroma } = data
- output.raw_html = data.statusnet_html
- output.text = data.text
+ if (data.pleroma) {
+ output.text = pleroma.content
+ ? data.pleroma.content['text/plain']
+ : data.content
+ output.summary = pleroma.spoiler_text
+ ? data.pleroma.spoiler_text['text/plain']
+ : data.spoiler_text
+ output.statusnet_conversation_id = data.pleroma.conversation_id
+ output.is_local = pleroma.local
+ output.in_reply_to_screen_name = pleroma.in_reply_to_account_acct
+ output.thread_muted = pleroma.thread_muted
+ output.emoji_reactions = pleroma.emoji_reactions
+ output.parent_visible =
+ pleroma.parent_visible === undefined ? true : pleroma.parent_visible
+ output.quote_visible = pleroma.quote_visible || true
+ output.quotes_count = pleroma.quotes_count
+ output.bookmark_folder_id = pleroma.bookmark_folder
+ } else {
+ output.text = data.content
+ output.summary = data.spoiler_text
+ }
- output.in_reply_to_status_id = data.in_reply_to_status_id
- output.in_reply_to_user_id = data.in_reply_to_user_id
- output.in_reply_to_screen_name = data.in_reply_to_screen_name
- output.statusnet_conversation_id = data.statusnet_conversation_id
+ const quoteRaw = pleroma?.quote || data.quote
+ const quoteData = quoteRaw ? parseStatus(quoteRaw) : undefined
+ output.quote = quoteData
+ output.quote_id =
+ data.quote?.id ?? data.quote_id ?? quoteData?.id ?? pleroma?.quote_id
+ output.quote_url = data.quote?.url ?? quoteData?.url ?? pleroma?.quote_url
- if (output.type === 'retweet') {
- output.retweeted_status = parseStatus(data.retweeted_status)
- }
+ output.in_reply_to_status_id = data.in_reply_to_id
+ output.in_reply_to_user_id = data.in_reply_to_account_id
+ output.replies_count = data.replies_count
- output.summary = data.summary
- output.summary_html = data.summary_html
- output.external_url = data.external_url
- output.is_local = data.is_local
+ if (output.type === 'retweet') {
+ output.retweeted_status = parseStatus(data.reblog)
}
+ output.summary_raw_html = escapeHtml(data.spoiler_text)
+ output.external_url = data.uri || data.url
+ output.poll = data.poll
+ if (output.poll) {
+ output.poll.options = (output.poll.options || []).map((field) => ({
+ ...field,
+ title_html: escapeHtml(field.title),
+ }))
+ }
+ output.pinned = data.pinned
+ output.muted = data.muted
+
output.id = String(data.id)
output.visibility = data.visibility
output.card = data.card
output.created_at = new Date(data.created_at)
// Converting to string, the right way.
output.in_reply_to_status_id = output.in_reply_to_status_id
? String(output.in_reply_to_status_id)
: null
output.in_reply_to_user_id = output.in_reply_to_user_id
? String(output.in_reply_to_user_id)
: null
- output.user = parseUser(masto ? data.account : data.user)
+ output.user = parseUser(data.account)
- output.attentions = ((masto ? data.mentions : data.attentions) || []).map(
- parseUser,
- )
+ output.attentions = (data.mentions || []).map(parseUser)
- output.attachments = (
- (masto ? data.media_attachments : data.attachments) || []
- ).map(parseAttachment)
+ output.attachments = (data.media_attachments || []).map(parseAttachment)
- const retweetedStatus = masto ? data.reblog : data.retweeted_status
+ const retweetedStatus = data.reblog
if (retweetedStatus) {
output.retweeted_status = parseStatus(retweetedStatus)
}
output.favoritedBy = []
output.rebloggedBy = []
if (Object.hasOwn(data, 'originalStatus')) {
Object.assign(output, data.originalStatus)
}
return output
}
export const parseNotification = (data) => {
const mastoDict = {
favourite: 'like',
reblog: 'repeat',
}
- const masto = !Object.hasOwn(data, 'ntype')
const output = {}
- if (masto) {
- output.type = mastoDict[data.type] || data.type
- output.seen = data.pleroma.is_seen
- // TODO: null check should be a temporary fix, I guess.
- // Investigate why backend does this.
- output.status =
- isStatusNotification(output.type) && data.status !== null
- ? parseStatus(data.status)
- : null
- output.target = output.type !== 'move' ? null : parseUser(data.target)
- output.from_profile = parseUser(data.account)
- output.emoji = data.emoji
- output.emoji_url = data.emoji_url
- if (data.report) {
- output.report = data.report
- output.report.content = data.report.content
- output.report.acct = parseUser(data.report.account)
- output.report.actor = parseUser(data.report.actor)
- output.report.statuses = data.report.statuses.map(parseStatus)
- }
- } else {
- const parsedNotice = parseStatus(data.notice)
- output.type = data.ntype
- output.seen = Boolean(data.is_seen)
- output.status =
- output.type === 'like'
- ? parseStatus(data.notice.favorited_status)
- : parsedNotice
- output.action = parsedNotice
- output.from_profile =
- output.type === 'pleroma:chat_mention'
- ? parseUser(data.account)
- : parseUser(data.from_profile)
+ output.type = mastoDict[data.type] || data.type
+ output.seen = data.pleroma.is_seen
+ // TODO: null check should be a temporary fix, I guess.
+ // Investigate why backend does this.
+ output.status =
+ isStatusNotification(output.type) && data.status !== null
+ ? parseStatus(data.status)
+ : null
+ output.target = output.type !== 'move' ? null : parseUser(data.target)
+ output.from_profile = parseUser(data.account)
+ output.emoji = data.emoji
+ output.emoji_url = data.emoji_url
+ if (data.report) {
+ output.report = data.report
+ output.report.content = data.report.content
+ output.report.acct = parseUser(data.report.account)
+ output.report.actor = parseUser(data.report.actor)
+ output.report.statuses = data.report.statuses.map(parseStatus)
}
output.created_at = new Date(data.created_at)
output.id = parseInt(data.id)
return output
}
-const isNsfw = (status) => {
- const nsfwRegex = /#nsfw/i
- return (
- (status.tags || []).includes('nsfw') ||
- !!(status.text || '').match(nsfwRegex)
- )
-}
-
export const parseLinkHeaderPagination = (linkHeader, opts = {}) => {
const flakeId = opts.flakeId
const parsedLinkHeader = parseLinkHeader(linkHeader)
if (!parsedLinkHeader) return
const maxId = parsedLinkHeader.next?.max_id
const minId = parsedLinkHeader.prev?.min_id
return {
maxId: flakeId ? maxId : parseInt(maxId, 10),
minId: flakeId ? minId : parseInt(minId, 10),
}
}
export const parseChat = (chat) => {
const output = {}
output.id = chat.id
output.account = parseUser(chat.account)
output.unread = chat.unread
output.lastMessage = parseChatMessage(chat.last_message)
output.updated_at = new Date(chat.updated_at)
return output
}
export const parseChatMessage = (message) => {
if (!message) {
return
}
if (message.isNormalized) {
return message
}
const output = message
output.id = message.id
output.created_at = new Date(message.created_at)
output.chat_id = message.chat_id
output.emojis = message.emojis
output.content = message.content
if (message.attachment) {
output.attachments = [parseAttachment(message.attachment)]
} else {
output.attachments = []
}
output.pending = !!message.pending
output.error = false
output.idempotency_key = message.idempotency_key
output.isNormalized = true
return output
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 30, 4:40 AM (23 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1799465
Default Alt Text
(25 KB)

Event Timeline