mattermost-redux
Version:
Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client
227 lines (226 loc) • 8.87 kB
JavaScript
;
// 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;
}