UNPKG

mattermost-redux

Version:

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

375 lines 17 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.combineUserActivitySystemPost = exports.comparePostTypes = exports.postTypePriority = exports.makeGenerateCombinedPost = exports.getLastPostIndex = exports.getLastPostId = exports.getFirstPostId = exports.getPostIdsForCombinedUserActivityPost = exports.isCombinedUserActivityPost = exports.getDateForDateLine = exports.isDateLine = exports.isStartOfNewMessages = exports.makeCombineUserActivityPosts = exports.makeFilterPostsAndAddSeparators = exports.makePreparePostIdsForPostList = exports.MAX_COMBINED_SYSTEM_POSTS = exports.START_OF_NEW_MESSAGES = exports.DATE_LINE = exports.COMBINED_USER_ACTIVITY = void 0; var tslib_1 = require("tslib"); // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. var reselect = tslib_1.__importStar(require("reselect")); var moment_timezone_1 = tslib_1.__importDefault(require("moment-timezone")); var constants_1 = require("../constants"); var posts_1 = require("../selectors/entities/posts"); var preferences_1 = require("../selectors/entities/preferences"); var timezone_1 = require("../selectors/entities/timezone"); var users_1 = require("../selectors/entities/users"); var helpers_1 = require("./helpers"); var post_utils_1 = require("./post_utils"); var timezone_utils_1 = require("./timezone_utils"); exports.COMBINED_USER_ACTIVITY = 'user-activity-'; exports.DATE_LINE = 'date-'; exports.START_OF_NEW_MESSAGES = 'start-of-new-messages'; exports.MAX_COMBINED_SYSTEM_POSTS = 100; function shouldShowJoinLeaveMessages(state) { // This setting is true or not set if join/leave messages are to be displayed return preferences_1.getBool(state, constants_1.Preferences.CATEGORY_ADVANCED_SETTINGS, constants_1.Preferences.ADVANCED_FILTER_JOIN_LEAVE, true); } function makePreparePostIdsForPostList() { var filterPostsAndAddSeparators = makeFilterPostsAndAddSeparators(); var combineUserActivityPosts = makeCombineUserActivityPosts(); return function (state, options) { var postIds = filterPostsAndAddSeparators(state, options); postIds = combineUserActivityPosts(state, postIds); return postIds; }; } exports.makePreparePostIdsForPostList = makePreparePostIdsForPostList; // Returns a selector that, given the state and an object containing an array of postIds and an optional // timestamp of when the channel was last read, returns a memoized array of postIds interspersed with // day indicators and an optional new message indicator. function makeFilterPostsAndAddSeparators() { var getPostsForIds = posts_1.makeGetPostsForIds(); return helpers_1.createIdsSelector(function (state, _a) { var postIds = _a.postIds; return getPostsForIds(state, postIds); }, function (state, _a) { var lastViewedAt = _a.lastViewedAt; return lastViewedAt; }, function (state, _a) { var indicateNewMessages = _a.indicateNewMessages; return indicateNewMessages; }, function (state) { return state.entities.posts.selectedPostId; }, users_1.getCurrentUser, shouldShowJoinLeaveMessages, timezone_1.isTimezoneEnabled, function (posts, lastViewedAt, indicateNewMessages, selectedPostId, currentUser, showJoinLeave, timeZoneEnabled) { if (posts.length === 0 || !currentUser) { return []; } var out = []; var lastDate; var addedNewMessagesIndicator = false; // Iterating through the posts from oldest to newest for (var i = posts.length - 1; i >= 0; i--) { var post = posts[i]; if (!post || (post.type === constants_1.Posts.POST_TYPES.EPHEMERAL_ADD_TO_CHANNEL && !selectedPostId)) { continue; } // Filter out join/leave messages if necessary if (post_utils_1.shouldFilterJoinLeavePost(post, showJoinLeave, currentUser.username)) { continue; } // Push on a date header if the last post was on a different day than the current one var postDate = new Date(post.create_at); if (timeZoneEnabled) { var currentOffset = postDate.getTimezoneOffset() * 60 * 1000; var timezone = timezone_utils_1.getUserCurrentTimezone(currentUser.timezone); if (timezone) { var zone = moment_timezone_1.default.tz.zone(timezone); if (zone) { var timezoneOffset = zone.utcOffset(post.create_at) * 60 * 1000; postDate.setTime(post.create_at + (currentOffset - timezoneOffset)); } } } if (!lastDate || lastDate.toDateString() !== postDate.toDateString()) { out.push(exports.DATE_LINE + postDate.getTime()); lastDate = postDate; } if (lastViewedAt && post.create_at > lastViewedAt && (post.user_id !== currentUser.id || post_utils_1.isFromWebhook(post)) && !addedNewMessagesIndicator && indicateNewMessages) { out.push(exports.START_OF_NEW_MESSAGES); addedNewMessagesIndicator = true; } out.push(post.id); } // Flip it back to newest to oldest return out.reverse(); }); } exports.makeFilterPostsAndAddSeparators = makeFilterPostsAndAddSeparators; function makeCombineUserActivityPosts() { return helpers_1.createIdsSelector(function (state, postIds) { return postIds; }, function (state) { return state.entities.posts.posts; }, function (postIds, posts) { var lastPostIsUserActivity = false; var combinedCount = 0; var out = []; var changed = false; for (var i = 0; i < postIds.length; i++) { var postId = postIds[i]; if (postId === exports.START_OF_NEW_MESSAGES || postId.startsWith(exports.DATE_LINE)) { // Not a post, so it won't be combined out.push(postId); lastPostIsUserActivity = false; combinedCount = 0; continue; } var post = posts[postId]; var postIsUserActivity = post_utils_1.isUserActivityPost(post.type); if (postIsUserActivity && lastPostIsUserActivity && combinedCount < exports.MAX_COMBINED_SYSTEM_POSTS) { // Add the ID to the previous combined post out[out.length - 1] += '_' + postId; combinedCount += 1; changed = true; } else if (postIsUserActivity) { // Start a new combined post, even if the "combined" post is only a single post out.push(exports.COMBINED_USER_ACTIVITY + postId); combinedCount = 1; changed = true; } else { out.push(postId); combinedCount = 0; } lastPostIsUserActivity = postIsUserActivity; } if (!changed) { // Nothing was combined, so return the original array return postIds; } return out; }); } exports.makeCombineUserActivityPosts = makeCombineUserActivityPosts; function isStartOfNewMessages(item) { return item === exports.START_OF_NEW_MESSAGES; } exports.isStartOfNewMessages = isStartOfNewMessages; function isDateLine(item) { return item.startsWith(exports.DATE_LINE); } exports.isDateLine = isDateLine; function getDateForDateLine(item) { return parseInt(item.substring(exports.DATE_LINE.length), 10); } exports.getDateForDateLine = getDateForDateLine; function isCombinedUserActivityPost(item) { return (/^user-activity-(?:[^_]+_)*[^_]+$/).test(item); } exports.isCombinedUserActivityPost = isCombinedUserActivityPost; function getPostIdsForCombinedUserActivityPost(item) { return item.substring(exports.COMBINED_USER_ACTIVITY.length).split('_'); } exports.getPostIdsForCombinedUserActivityPost = getPostIdsForCombinedUserActivityPost; function getFirstPostId(items) { for (var i = 0; i < items.length; i++) { var item = items[i]; if (isStartOfNewMessages(item) || isDateLine(item)) { // This is not a post at all continue; } if (isCombinedUserActivityPost(item)) { // This is a combined post, so find the first post ID from it var combinedIds = getPostIdsForCombinedUserActivityPost(item); return combinedIds[0]; } // This is a post ID return item; } return ''; } exports.getFirstPostId = getFirstPostId; function getLastPostId(items) { for (var i = items.length - 1; i >= 0; i--) { var item = items[i]; if (isStartOfNewMessages(item) || isDateLine(item)) { // This is not a post at all continue; } if (isCombinedUserActivityPost(item)) { // This is a combined post, so find the first post ID from it var combinedIds = getPostIdsForCombinedUserActivityPost(item); return combinedIds[combinedIds.length - 1]; } // This is a post ID return item; } return ''; } exports.getLastPostId = getLastPostId; function getLastPostIndex(postIds) { var index = 0; for (var i = postIds.length - 1; i > 0; i--) { var item = postIds[i]; if (!isStartOfNewMessages(item) && !isDateLine(item)) { index = i; break; } } return index; } exports.getLastPostIndex = getLastPostIndex; function makeGenerateCombinedPost() { var getPostsForIds = posts_1.makeGetPostsForIds(); var getPostIds = helpers_1.memoizeResult(getPostIdsForCombinedUserActivityPost); return reselect.createSelector(function (state, combinedId) { return combinedId; }, function (state, combinedId) { return getPostsForIds(state, getPostIds(combinedId)); }, function (combinedId, posts) { // All posts should be in the same channel var channelId = posts[0].channel_id; // Assume that the last post is the oldest one var createAt = posts[posts.length - 1].create_at; var messages = posts.map(function (post) { return post.message; }); return { id: combinedId, root_id: '', channel_id: channelId, create_at: createAt, delete_at: 0, message: messages.join('\n'), props: { messages: messages, user_activity: combineUserActivitySystemPost(posts), }, state: '', system_post_ids: posts.map(function (post) { return post.id; }), type: constants_1.Posts.POST_TYPES.COMBINED_USER_ACTIVITY, user_activity_posts: posts, user_id: '', metadata: {}, }; }); } exports.makeGenerateCombinedPost = makeGenerateCombinedPost; exports.postTypePriority = (_a = {}, _a[constants_1.Posts.POST_TYPES.JOIN_TEAM] = 0, _a[constants_1.Posts.POST_TYPES.ADD_TO_TEAM] = 1, _a[constants_1.Posts.POST_TYPES.LEAVE_TEAM] = 2, _a[constants_1.Posts.POST_TYPES.REMOVE_FROM_TEAM] = 3, _a[constants_1.Posts.POST_TYPES.JOIN_CHANNEL] = 4, _a[constants_1.Posts.POST_TYPES.ADD_TO_CHANNEL] = 5, _a[constants_1.Posts.POST_TYPES.LEAVE_CHANNEL] = 6, _a[constants_1.Posts.POST_TYPES.REMOVE_FROM_CHANNEL] = 7, _a[constants_1.Posts.POST_TYPES.PURPOSE_CHANGE] = 8, _a[constants_1.Posts.POST_TYPES.HEADER_CHANGE] = 9, _a[constants_1.Posts.POST_TYPES.JOIN_LEAVE] = 10, _a[constants_1.Posts.POST_TYPES.DISPLAYNAME_CHANGE] = 11, _a[constants_1.Posts.POST_TYPES.CONVERT_CHANNEL] = 12, _a[constants_1.Posts.POST_TYPES.CHANNEL_DELETED] = 13, _a[constants_1.Posts.POST_TYPES.CHANNEL_UNARCHIVED] = 14, _a[constants_1.Posts.POST_TYPES.ADD_REMOVE] = 15, _a[constants_1.Posts.POST_TYPES.EPHEMERAL] = 16, _a); function comparePostTypes(a, b) { return exports.postTypePriority[a.postType] - exports.postTypePriority[b.postType]; } exports.comparePostTypes = comparePostTypes; function extractUserActivityData(userActivities) { var messageData = []; var allUserIds = []; var allUsernames = []; Object.entries(userActivities).forEach(function (_a) { var _b = tslib_1.__read(_a, 2), postType = _b[0], values = _b[1]; if (postType === constants_1.Posts.POST_TYPES.ADD_TO_TEAM || postType === constants_1.Posts.POST_TYPES.ADD_TO_CHANNEL || postType === constants_1.Posts.POST_TYPES.REMOVE_FROM_CHANNEL) { Object.keys(values).map(function (key) { return [key, values[key]]; }).forEach(function (_a) { var _b = tslib_1.__read(_a, 2), actorId = _b[0], users = _b[1]; if (Array.isArray(users)) { throw new Error('Invalid Post activity data'); } var ids = users.ids, usernames = users.usernames; messageData.push({ postType: postType, userIds: tslib_1.__spread(usernames, ids), actorId: actorId }); if (ids.length > 0) { allUserIds.push.apply(allUserIds, tslib_1.__spread(ids)); } if (usernames.length > 0) { allUsernames.push.apply(allUsernames, tslib_1.__spread(usernames)); } allUserIds.push(actorId); }); } else { if (!Array.isArray(values)) { throw new Error('Invalid Post activity data'); } messageData.push({ postType: postType, userIds: values }); allUserIds.push.apply(allUserIds, tslib_1.__spread(values)); } }); messageData.sort(comparePostTypes); function reduceUsers(acc, curr) { if (!acc.includes(curr)) { acc.push(curr); } return acc; } return { allUserIds: allUserIds.reduce(reduceUsers, []), allUsernames: allUsernames.reduce(reduceUsers, []), messageData: messageData, }; } function combineUserActivitySystemPost(systemPosts) { if (systemPosts === void 0) { systemPosts = []; } if (systemPosts.length === 0) { return null; } var userActivities = systemPosts.reduce(function (acc, post) { var _a, _b; var postType = post.type; var userActivityProps = acc; var combinedPostType = userActivityProps[postType]; if (postType === constants_1.Posts.POST_TYPES.ADD_TO_TEAM || postType === constants_1.Posts.POST_TYPES.ADD_TO_CHANNEL || postType === constants_1.Posts.POST_TYPES.REMOVE_FROM_CHANNEL) { var userId = post.props.addedUserId || post.props.removedUserId; var username = post.props.addedUsername || post.props.removedUsername; if (combinedPostType) { if (Array.isArray(combinedPostType[post.user_id])) { throw new Error('Invalid Post activity data'); } var users = combinedPostType[post.user_id] || { ids: [], usernames: [] }; if (userId) { if (!users.ids.includes(userId)) { users.ids.push(userId); } } else if (username && !users.usernames.includes(username)) { users.usernames.push(username); } combinedPostType[post.user_id] = users; } else { var users = { ids: [], usernames: [], }; if (userId) { users.ids.push(userId); } else if (username) { users.usernames.push(username); } userActivityProps[postType] = (_a = {}, _a[post.user_id] = users, _a); } } else { var propsUserId = post.user_id; if (combinedPostType) { if (!Array.isArray(combinedPostType)) { throw new Error('Invalid Post activity data'); } if (!combinedPostType.includes(propsUserId)) { userActivityProps[postType] = tslib_1.__spread(combinedPostType, [propsUserId]); } } else { userActivityProps = tslib_1.__assign(tslib_1.__assign({}, userActivityProps), (_b = {}, _b[postType] = [propsUserId], _b)); } } return userActivityProps; }, {}); return extractUserActivityData(userActivities); } exports.combineUserActivitySystemPost = combineUserActivitySystemPost; //# sourceMappingURL=post_list.js.map