UNPKG

mattermost-redux

Version:

Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client

227 lines (226 loc) 8.87 kB
"use strict"; // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. Object.defineProperty(exports, "__esModule", { value: true }); exports.isSystemMessage = isSystemMessage; exports.isMeMessage = isMeMessage; exports.isFromWebhook = isFromWebhook; exports.isPostEphemeral = isPostEphemeral; exports.isUserAddedInChannel = isUserAddedInChannel; exports.shouldIgnorePost = shouldIgnorePost; exports.isUserActivityPost = isUserActivityPost; exports.isPostOwner = isPostOwner; exports.isEdited = isEdited; exports.canEditPost = canEditPost; exports.getLastCreateAt = getLastCreateAt; exports.shouldFilterJoinLeavePost = shouldFilterJoinLeavePost; exports.isPostPendingOrFailed = isPostPendingOrFailed; exports.comparePosts = comparePosts; exports.isPostCommentMention = isPostCommentMention; exports.fromAutoResponder = fromAutoResponder; exports.getEmbedFromMetadata = getEmbedFromMetadata; exports.isPermalink = isPermalink; exports.shouldUpdatePost = shouldUpdatePost; exports.ensureString = ensureString; exports.ensureNumber = ensureNumber; exports.secureGetFromRecord = secureGetFromRecord; const roles_1 = require("mattermost-redux/selectors/entities/roles"); const constants_1 = require("../constants"); function isSystemMessage(post) { return Boolean(post.type && post.type.startsWith(constants_1.Posts.SYSTEM_MESSAGE_PREFIX)); } function isMeMessage(post) { return Boolean(post.type && post.type === constants_1.Posts.POST_TYPES.ME); } function isFromWebhook(post) { return post.props?.from_webhook === 'true'; } function isPostEphemeral(post) { return post.type === constants_1.Posts.POST_TYPES.EPHEMERAL || post.type === constants_1.Posts.POST_TYPES.EPHEMERAL_ADD_TO_CHANNEL || post.state === constants_1.Posts.POST_DELETED; } function isUserAddedInChannel(post, userId) { const postTypeCheck = Boolean(post.type && (post.type === constants_1.Posts.POST_TYPES.ADD_TO_CHANNEL)); const userIdCheck = Boolean(post.props && post.props.addedUserId && (post.props.addedUserId === userId)); return postTypeCheck && userIdCheck; } function shouldIgnorePost(post, userId) { if (isUserAddedInChannel(post, userId)) { return false; } return constants_1.Posts.IGNORE_POST_TYPES.includes(post.type); } function isUserActivityPost(postType) { return constants_1.Posts.USER_ACTIVITY_POST_TYPES.includes(postType); } function isPostOwner(userId, post) { return userId === post.user_id; } function isEdited(post) { return post.edit_at > 0; } function canEditPost(state, config, license, teamId, channelId, userId, post) { if (!post || isSystemMessage(post)) { return false; } const isOwner = isPostOwner(userId, post); let canEdit = true; const permission = isOwner ? constants_1.Permissions.EDIT_POST : constants_1.Permissions.EDIT_OTHERS_POSTS; canEdit = (0, roles_1.haveIChannelPermission)(state, teamId, channelId, permission); if (license.IsLicensed === 'true' && config.PostEditTimeLimit !== '-1' && config.PostEditTimeLimit !== -1) { const timeLeft = (post.create_at + (config.PostEditTimeLimit * 1000)) - Date.now(); if (timeLeft <= 0) { canEdit = false; } } return canEdit; } function getLastCreateAt(postsArray) { const createAt = postsArray.map((p) => p.create_at); if (createAt.length) { return Reflect.apply(Math.max, null, createAt); } return 0; } const joinLeavePostTypes = [ constants_1.Posts.POST_TYPES.JOIN_LEAVE, constants_1.Posts.POST_TYPES.JOIN_CHANNEL, constants_1.Posts.POST_TYPES.LEAVE_CHANNEL, constants_1.Posts.POST_TYPES.ADD_REMOVE, constants_1.Posts.POST_TYPES.ADD_TO_CHANNEL, constants_1.Posts.POST_TYPES.REMOVE_FROM_CHANNEL, constants_1.Posts.POST_TYPES.JOIN_TEAM, constants_1.Posts.POST_TYPES.LEAVE_TEAM, constants_1.Posts.POST_TYPES.ADD_TO_TEAM, constants_1.Posts.POST_TYPES.REMOVE_FROM_TEAM, constants_1.Posts.POST_TYPES.COMBINED_USER_ACTIVITY, ]; /** * If the user has "Show Join/Leave Messages" disabled, this function will return true if the post should be hidden if it's of type join/leave. * The post object passed in must be not null/undefined. * @returns Returns true if a post should be hidden */ function shouldFilterJoinLeavePost(post, showJoinLeave, currentUsername) { if (showJoinLeave) { return false; } // Don't filter out non-join/leave messages if (joinLeavePostTypes.indexOf(post.type) === -1) { return false; } // Don't filter out join/leave messages about the current user return !isJoinLeavePostForUsername(post, currentUsername); } function isJoinLeavePostForUsername(post, currentUsername) { if (!post.props || !currentUsername) { return false; } if (post.user_activity_posts) { for (const childPost of post.user_activity_posts) { if (isJoinLeavePostForUsername(childPost, currentUsername)) { // If any of the contained posts are for this user, the client will // need to figure out how to render the post return true; } } } return post.props.username === currentUsername || post.props.addedUsername === currentUsername || post.props.removedUsername === currentUsername; } function isPostPendingOrFailed(post) { return post.failed || post.id === post.pending_post_id; } function comparePosts(a, b) { const aIsPendingOrFailed = isPostPendingOrFailed(a); const bIsPendingOrFailed = isPostPendingOrFailed(b); if (aIsPendingOrFailed && !bIsPendingOrFailed) { return -1; } else if (!aIsPendingOrFailed && bIsPendingOrFailed) { return 1; } if (a.create_at > b.create_at) { return -1; } else if (a.create_at < b.create_at) { return 1; } return 0; } function isPostCommentMention({ post, currentUser, threadRepliedToByCurrentUser, rootPost }) { let commentsNotifyLevel = constants_1.Preferences.COMMENTS_NEVER; let isCommentMention = false; let threadCreatedByCurrentUser = false; if (rootPost && rootPost.user_id === currentUser.id) { threadCreatedByCurrentUser = true; } if (currentUser.notify_props && currentUser.notify_props.comments) { commentsNotifyLevel = currentUser.notify_props.comments; } const notCurrentUser = post.user_id !== currentUser.id || isFromWebhook(post); if (notCurrentUser) { if (commentsNotifyLevel === constants_1.Preferences.COMMENTS_ANY && (threadCreatedByCurrentUser || threadRepliedToByCurrentUser)) { isCommentMention = true; } else if (commentsNotifyLevel === constants_1.Preferences.COMMENTS_ROOT && threadCreatedByCurrentUser) { isCommentMention = true; } } return isCommentMention; } function fromAutoResponder(post) { return Boolean(post.type && (post.type === constants_1.Posts.SYSTEM_AUTO_RESPONDER)); } function getEmbedFromMetadata(metadata) { if (!metadata || !metadata.embeds || metadata.embeds.length === 0) { return null; } return metadata.embeds[0]; } function isPermalink(post) { if (post.metadata && post.metadata.embeds) { for (const embed of post.metadata.embeds) { if (embed.type === 'permalink') { return true; } } } return false; } function shouldUpdatePost(receivedPost, storedPost) { if (!storedPost) { return true; } if (storedPost.update_at > receivedPost.update_at) { // The stored post is newer than the one we've received return false; } if (storedPost.update_at && receivedPost.update_at && storedPost.update_at === receivedPost.update_at) { // The stored post has the same update at with the one we've received if (storedPost.is_following !== receivedPost.is_following || storedPost.reply_count !== receivedPost.reply_count || storedPost.participants?.length !== receivedPost.participants?.length) { // CRT properties are not the same between posts // e.g: in the case of toggling CRT on/off return true; } if (!storedPost.metadata && receivedPost.metadata) { // Metadata is not the same between posts return true; } // The stored post is the same as the one we've received return false; } // The stored post is older than the one we've received return true; } function ensureString(v) { return typeof v === 'string' ? v : ''; } function ensureNumber(v) { return typeof v === 'number' ? v : 0; } function secureGetFromRecord(v, key) { return typeof v === 'object' && v && Object.hasOwn(v, key) ? v[key] : undefined; }