import { isEmpty } from "@ember/utils"; import { userPath } from "discourse/lib/url"; const _additionalAttributes = []; export function includeAttributes(...attributes) { attributes.forEach(a => _additionalAttributes.push(a)); } export function transformBasicPost(post) { // Note: it can be dangerous to not use `get` in Ember code, but this is significantly // faster and has tests to confirm it works. We only call `get` when the property is a CP const postAtts = { id: post.id, hidden: post.hidden, deleted: post.get("deleted"), deleted_at: post.deleted_at, user_deleted: post.user_deleted, isDeleted: post.deleted_at || post.user_deleted, // xxxxx deletedByAvatarTemplate: null, deletedByUsername: null, primary_group_name: post.primary_group_name, primary_group_flair_url: post.primary_group_flair_url, primary_group_flair_bg_color: post.primary_group_flair_bg_color, primary_group_flair_color: post.primary_group_flair_color, wiki: post.wiki, lastWikiEdit: post.last_wiki_edit, firstPost: post.post_number === 1, post_number: post.post_number, cooked: post.cooked, via_email: post.via_email, isAutoGenerated: post.is_auto_generated, user_id: post.user_id, usernameUrl: userPath(post.username), username: post.username, avatar_template: post.avatar_template, bookmarked: post.bookmarked, bookmarkedWithReminder: post.bookmarked_with_reminder, bookmarkReminderAt: post.bookmark_reminder_at, bookmarkReminderType: post.bookmark_reminder_type, yours: post.yours, shareUrl: post.get("shareUrl"), staff: post.staff, admin: post.admin, moderator: post.moderator, new_user: post.trust_level === 0, name: post.name, user_title: post.user_title, created_at: post.created_at, updated_at: post.updated_at, canDelete: post.can_delete, showFlagDelete: false, canRecover: post.can_recover, canEdit: post.can_edit, canFlag: !isEmpty(post.get("flagsAvailable")), canReviewTopic: false, reviewableId: post.reviewable_id, reviewableScoreCount: post.reviewable_score_count, reviewableScorePendingCount: post.reviewable_score_pending_count, version: post.version, canRecoverTopic: false, canDeleteTopic: false, canViewEditHistory: post.can_view_edit_history, canWiki: post.can_wiki, showLike: false, liked: false, canToggleLike: false, likeCount: false, actionsSummary: null, read: post.read, replyToUsername: null, replyToAvatarTemplate: null, reply_to_post_number: post.reply_to_post_number, cooked_hidden: !!post.cooked_hidden, expandablePost: false, replyCount: post.reply_count, locked: post.locked, userCustomFields: post.user_custom_fields, readCount: post.readers_count }; _additionalAttributes.forEach(a => (postAtts[a] = post[a])); return postAtts; } export default function transformPost( currentUser, site, post, prevPost, nextPost ) { // Note: it can be dangerous to not use `get` in Ember code, but this is significantly // faster and has tests to confirm it works. We only call `get` when the property is a CP const postType = post.post_type; const postTypes = site.post_types; const topic = post.topic; const details = topic.get("details"); const postAtts = transformBasicPost(post); const createdBy = details.created_by || {}; postAtts.topicId = topic.id; postAtts.topicOwner = createdBy.id === post.user_id; postAtts.topicCreatedById = createdBy.id; postAtts.post_type = postType; postAtts.via_email = post.via_email; postAtts.isAutoGenerated = post.is_auto_generated; postAtts.isModeratorAction = postType === postTypes.moderator_action; postAtts.isWhisper = postType === postTypes.whisper; postAtts.isSmallAction = postType === postTypes.small_action || post.action_code === "split_topic"; postAtts.canBookmark = !!currentUser; postAtts.canManage = currentUser && currentUser.get("canManageTopic"); postAtts.canViewRawEmail = currentUser && (currentUser.id === post.user_id || currentUser.staff); postAtts.canReplyAsNewTopic = details.can_reply_as_new_topic; postAtts.canReviewTopic = !!details.can_review_topic; postAtts.isWarning = topic.is_warning; postAtts.links = post.get("internalLinks"); postAtts.replyDirectlyBelow = nextPost && nextPost.reply_to_post_number === post.post_number; postAtts.replyDirectlyAbove = prevPost && post.reply_to_post_number === prevPost.post_number; postAtts.linkCounts = post.link_counts; postAtts.actionCode = post.action_code; postAtts.actionCodeWho = post.action_code_who; postAtts.topicUrl = topic.get("url"); postAtts.isSaving = post.isSaving; if (post.notice_type) { postAtts.noticeType = post.notice_type; if (postAtts.noticeType === "custom") { postAtts.noticeMessage = post.notice_args; } else if (postAtts.noticeType === "returning_user") { postAtts.noticeTime = new Date(post.notice_args); } } const showPMMap = topic.archetype === "private_message" && post.post_number === 1; if (showPMMap) { postAtts.showPMMap = true; postAtts.allowedGroups = details.allowed_groups; postAtts.allowedUsers = details.allowed_users; postAtts.canRemoveAllowedUsers = details.can_remove_allowed_users; postAtts.canRemoveSelfId = details.can_remove_self_id; postAtts.canInvite = details.can_invite_to; } const showTopicMap = showPMMap || (post.post_number === 1 && topic.archetype === "regular" && topic.posts_count > 1); if (showTopicMap) { postAtts.showTopicMap = true; postAtts.topicCreatedAt = topic.created_at; postAtts.createdByUsername = createdBy.username; postAtts.createdByAvatarTemplate = createdBy.avatar_template; postAtts.createdByName = createdBy.name; postAtts.lastPostUrl = topic.get("lastPostUrl"); postAtts.lastPostUsername = details.last_poster.username; postAtts.lastPostAvatarTemplate = details.last_poster.avatar_template; postAtts.lastPostName = details.last_poster.name; postAtts.lastPostAt = topic.last_posted_at; postAtts.topicReplyCount = topic.get("replyCount"); postAtts.topicViews = topic.views; postAtts.topicViewsHeat = topic.get("viewsHeat"); postAtts.participantCount = topic.participant_count; postAtts.topicLikeCount = topic.like_count; postAtts.topicLinks = details.links; if (postAtts.topicLinks) { postAtts.topicLinkLength = details.links.length; } postAtts.topicPostsCount = topic.posts_count; postAtts.participants = details.participants; const postStream = topic.get("postStream"); postAtts.userFilters = postStream.userFilters; postAtts.topicSummaryEnabled = postStream.summary; postAtts.topicWordCount = topic.word_count; postAtts.hasTopicSummary = topic.has_summary; } if (postAtts.isDeleted) { postAtts.deletedByAvatarTemplate = post.get( "postDeletedBy.avatar_template" ); postAtts.deletedByUsername = post.get("postDeletedBy.username"); } const replyToUser = post.get("reply_to_user"); if (replyToUser) { postAtts.replyToUsername = replyToUser.username; postAtts.replyToAvatarTemplate = replyToUser.avatar_template; } if (post.actions_summary) { postAtts.actionsSummary = post.actions_summary .filter(a => { return a.actionType.name_key !== "like" && a.acted; }) .map(a => { const action = a.actionType.name_key; return { id: a.id, postId: post.id, action, canUndo: a.can_undo, description: I18n.t(`post.actions.by_you.${action}`) }; }); } const likeAction = post.likeAction; if (likeAction) { postAtts.liked = likeAction.acted; postAtts.canToggleLike = likeAction.get("canToggle"); postAtts.showLike = postAtts.liked || postAtts.canToggleLike; postAtts.likeCount = likeAction.count; } if (!currentUser) { postAtts.showLike = !topic.archived; } if (postAtts.post_number === 1) { postAtts.canRecoverTopic = postAtts.isDeleted && details.can_recover; postAtts.canDeleteTopic = !postAtts.isDeleted && details.can_delete; postAtts.expandablePost = topic.expandable_first_post; // Show a "Flag to delete" message if not staff and you can't // otherwise delete it. postAtts.showFlagDelete = !postAtts.canDelete && postAtts.yours && currentUser && !currentUser.staff; } else { postAtts.canRecover = postAtts.isDeleted && postAtts.canRecover; postAtts.canDelete = postAtts.canDelete && !post.deleted_at && currentUser && (currentUser.staff || !post.user_deleted); } _additionalAttributes.forEach(a => (postAtts[a] = post[a])); return postAtts; }