mattermost-redux
Version:
Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client
1,241 lines • 55.1 kB
JavaScript
"use strict";
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.selectChannel = selectChannel;
exports.createChannel = createChannel;
exports.createDirectChannel = createDirectChannel;
exports.markGroupChannelOpen = markGroupChannelOpen;
exports.createGroupChannel = createGroupChannel;
exports.patchChannel = patchChannel;
exports.setMyChannelAutotranslation = setMyChannelAutotranslation;
exports.updateChannelPrivacy = updateChannelPrivacy;
exports.convertGroupMessageToPrivateChannel = convertGroupMessageToPrivateChannel;
exports.updateChannelNotifyProps = updateChannelNotifyProps;
exports.getChannelByNameAndTeamName = getChannelByNameAndTeamName;
exports.getChannel = getChannel;
exports.getChannelAndMyMember = getChannelAndMyMember;
exports.getChannelTimezones = getChannelTimezones;
exports.fetchChannelsAndMembers = fetchChannelsAndMembers;
exports.fetchAllMyChannelMembers = fetchAllMyChannelMembers;
exports.fetchAllMyTeamsChannels = fetchAllMyTeamsChannels;
exports.getChannelMembers = getChannelMembers;
exports.leaveChannel = leaveChannel;
exports.joinChannel = joinChannel;
exports.deleteChannel = deleteChannel;
exports.unarchiveChannel = unarchiveChannel;
exports.updateApproximateViewTime = updateApproximateViewTime;
exports.unsetActiveChannelOnServer = unsetActiveChannelOnServer;
exports.readMultipleChannels = readMultipleChannels;
exports.getChannels = getChannels;
exports.getArchivedChannels = getArchivedChannels;
exports.getAllChannelsWithCount = getAllChannelsWithCount;
exports.getAllChannels = getAllChannels;
exports.autocompleteChannels = autocompleteChannels;
exports.autocompleteChannelsForSearch = autocompleteChannelsForSearch;
exports.searchChannels = searchChannels;
exports.searchAllChannels = searchAllChannels;
exports.searchGroupChannels = searchGroupChannels;
exports.getChannelStats = getChannelStats;
exports.getChannelsMemberCount = getChannelsMemberCount;
exports.addChannelMember = addChannelMember;
exports.addChannelMembers = addChannelMembers;
exports.removeChannelMember = removeChannelMember;
exports.markChannelAsRead = markChannelAsRead;
exports.markMultipleChannelsAsRead = markMultipleChannelsAsRead;
exports.markChannelAsViewedOnServer = markChannelAsViewedOnServer;
exports.actionsToMarkChannelAsRead = actionsToMarkChannelAsRead;
exports.actionsToMarkChannelAsUnread = actionsToMarkChannelAsUnread;
exports.getChannelMembersByIds = getChannelMembersByIds;
exports.getChannelMember = getChannelMember;
exports.getMyChannelMember = getMyChannelMember;
exports.loadMyChannelMemberAndRole = loadMyChannelMemberAndRole;
exports.favoriteChannel = favoriteChannel;
exports.unfavoriteChannel = unfavoriteChannel;
exports.updateChannelScheme = updateChannelScheme;
exports.updateChannelMemberSchemeRoles = updateChannelMemberSchemeRoles;
exports.membersMinusGroupMembers = membersMinusGroupMembers;
exports.getChannelModerations = getChannelModerations;
exports.patchChannelModerations = patchChannelModerations;
exports.getChannelMemberCountsByGroup = getChannelMemberCountsByGroup;
exports.fetchMissingChannels = fetchMissingChannels;
exports.fetchIsRestrictedDM = fetchIsRestrictedDM;
exports.getChannelAccessControlAttributes = getChannelAccessControlAttributes;
const redux_batched_actions_1 = require("redux-batched-actions");
const action_types_1 = require("mattermost-redux/action_types");
const client_1 = require("mattermost-redux/client");
const channel_categories_1 = require("mattermost-redux/constants/channel_categories");
const channels_1 = require("mattermost-redux/constants/channels");
const channel_categories_2 = require("mattermost-redux/selectors/entities/channel_categories");
const channels_2 = require("mattermost-redux/selectors/entities/channels");
const teams_1 = require("mattermost-redux/selectors/entities/teams");
const data_loader_1 = require("mattermost-redux/utils/data_loader");
const channel_categories_3 = require("./channel_categories");
const errors_1 = require("./errors");
const helpers_1 = require("./helpers");
const posts_1 = require("./posts");
const preferences_1 = require("./preferences");
const roles_1 = require("./roles");
const users_1 = require("./users");
const constants_1 = require("../constants");
function selectChannel(channelId) {
return {
type: action_types_1.ChannelTypes.SELECT_CHANNEL,
data: channelId,
};
}
function createChannel(channel, userId) {
return async (dispatch, getState) => {
let created;
try {
created = await client_1.Client4.createChannel(channel);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({
type: action_types_1.ChannelTypes.CREATE_CHANNEL_FAILURE,
error,
});
dispatch((0, errors_1.logError)(error));
return { error };
}
const member = {
channel_id: created.id,
user_id: userId,
roles: `${constants_1.General.CHANNEL_USER_ROLE} ${constants_1.General.CHANNEL_ADMIN_ROLE}`,
last_viewed_at: 0,
msg_count: 0,
mention_count: 0,
notify_props: { desktop: 'default', mark_unread: 'all' },
last_update_at: created.create_at,
};
const actions = [];
const { channels, myMembers } = getState().entities.channels;
if (!channels[created.id]) {
actions.push({ type: action_types_1.ChannelTypes.RECEIVED_CHANNEL, data: created });
}
if (!myMembers[created.id]) {
actions.push({ type: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER, data: member });
dispatch((0, roles_1.loadRolesIfNeeded)(member.roles.split(' ')));
}
dispatch((0, redux_batched_actions_1.batchActions)([
...actions,
{
type: action_types_1.ChannelTypes.CREATE_CHANNEL_SUCCESS,
},
]));
dispatch((0, channel_categories_3.addChannelToInitialCategory)(created, true));
return { data: created };
};
}
function createDirectChannel(userId, otherUserId) {
return async (dispatch, getState) => {
dispatch({ type: action_types_1.ChannelTypes.CREATE_CHANNEL_REQUEST, data: null });
let created;
try {
created = await client_1.Client4.createDirectChannel([userId, otherUserId]);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.CREATE_CHANNEL_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
const member = {
channel_id: created.id,
user_id: userId,
roles: `${constants_1.General.CHANNEL_USER_ROLE}`,
last_viewed_at: 0,
msg_count: 0,
mention_count: 0,
notify_props: { desktop: 'default', mark_unread: 'all' },
last_update_at: created.create_at,
};
const preferences = [
{ user_id: userId, category: constants_1.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, name: otherUserId, value: 'true' },
{ user_id: userId, category: constants_1.Preferences.CATEGORY_CHANNEL_OPEN_TIME, name: created.id, value: new Date().getTime().toString() },
];
dispatch((0, preferences_1.savePreferences)(userId, preferences));
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL,
data: created,
},
{
type: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
data: member,
},
{
type: action_types_1.PreferenceTypes.RECEIVED_PREFERENCES,
data: preferences,
},
{
type: action_types_1.ChannelTypes.CREATE_CHANNEL_SUCCESS,
},
{
type: action_types_1.UserTypes.RECEIVED_PROFILES_LIST_IN_CHANNEL,
id: created.id,
data: [{ id: userId }, { id: otherUserId }],
},
]));
dispatch((0, channel_categories_3.addChannelToInitialCategory)(created));
dispatch((0, roles_1.loadRolesIfNeeded)(member.roles.split(' ')));
return { data: created };
};
}
function markGroupChannelOpen(channelId) {
return async (dispatch, getState) => {
const { currentUserId } = getState().entities.users;
const preferences = [
{ user_id: currentUserId, category: constants_1.Preferences.CATEGORY_GROUP_CHANNEL_SHOW, name: channelId, value: 'true' },
{ user_id: currentUserId, category: constants_1.Preferences.CATEGORY_CHANNEL_OPEN_TIME, name: channelId, value: new Date().getTime().toString() },
];
return dispatch((0, preferences_1.savePreferences)(currentUserId, preferences));
};
}
function createGroupChannel(userIds) {
return async (dispatch, getState) => {
dispatch({ type: action_types_1.ChannelTypes.CREATE_CHANNEL_REQUEST, data: null });
const { currentUserId } = getState().entities.users;
let created;
try {
created = await client_1.Client4.createGroupChannel(userIds);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.CREATE_CHANNEL_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
let member = {
channel_id: created.id,
user_id: currentUserId,
roles: `${constants_1.General.CHANNEL_USER_ROLE}`,
last_viewed_at: 0,
msg_count: 0,
mention_count: 0,
msg_count_root: 0,
mention_count_root: 0,
notify_props: { desktop: 'default', mark_unread: 'all' },
last_update_at: created.create_at,
};
// Check the channel previous existency: if the channel already have
// posts is because it existed before.
if (created.total_msg_count > 0) {
const storeMember = (0, channels_2.getMyChannelMember)(getState(), created.id);
if (storeMember) {
member = storeMember;
}
else {
try {
member = await client_1.Client4.getMyChannelMember(created.id);
}
catch (error) {
// Log the error and keep going with the generated membership.
dispatch((0, errors_1.logError)(error));
}
}
}
dispatch(markGroupChannelOpen(created.id));
const profilesInChannel = userIds.map((id) => ({ id }));
profilesInChannel.push({ id: currentUserId }); // currentUserId is optionally in userIds, but the reducer will get rid of a duplicate
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL,
data: created,
},
{
type: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
data: member,
},
{
type: action_types_1.ChannelTypes.CREATE_CHANNEL_SUCCESS,
},
{
type: action_types_1.UserTypes.RECEIVED_PROFILES_LIST_IN_CHANNEL,
id: created.id,
data: profilesInChannel,
},
]));
dispatch((0, channel_categories_3.addChannelToInitialCategory)(created));
dispatch((0, roles_1.loadRolesIfNeeded)((member && member.roles && member.roles.split(' ')) || []));
return { data: created };
};
}
function patchChannel(channelId, patch) {
return (0, helpers_1.bindClientFunc)({
clientFunc: client_1.Client4.patchChannel,
onSuccess: [action_types_1.ChannelTypes.RECEIVED_CHANNEL],
params: [channelId, patch],
});
}
function setMyChannelAutotranslation(channelId, enabled) {
return async (dispatch, getState) => {
const state = getState();
const myChannelMember = (0, channels_2.getMyChannelMember)(state, channelId);
if (!myChannelMember) {
return { data: false, error: 'Channel member not found' };
}
const updatedMember = {
...myChannelMember,
autotranslation_disabled: !enabled,
};
try {
await client_1.Client4.setMyChannelAutotranslation(channelId, enabled);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { data: undefined, error };
}
// We check before updating the store
const becameEnabled = (0, channels_2.hasAutotranslationBecomeEnabled)(state, updatedMember);
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
data: updatedMember,
});
// If autotranslation changed, delete posts for this channel
if (becameEnabled) {
await dispatch((0, posts_1.resetReloadPostsInChannel)(channelId));
}
return { data: true, error: undefined };
};
}
function updateChannelPrivacy(channelId, privacy) {
return (0, helpers_1.bindClientFunc)({
clientFunc: client_1.Client4.updateChannelPrivacy,
onSuccess: [action_types_1.ChannelTypes.RECEIVED_CHANNEL],
params: [channelId, privacy],
});
}
function convertGroupMessageToPrivateChannel(channelID, teamID, displayName, name) {
return async (dispatch, getState) => {
let response;
try {
response = await client_1.Client4.convertGroupMessageToPrivateChannel(channelID, teamID, displayName, name);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL,
data: response.data,
});
// move the channel from direct message category to the default "channels" category
const channelsCategory = (0, channel_categories_2.getCategoryInTeamByType)(getState(), teamID, channel_categories_1.CategoryTypes.CHANNELS);
if (!channelsCategory) {
return {};
}
return {
data: response.data,
};
};
}
function updateChannelNotifyProps(userId, channelId, props) {
return async (dispatch, getState) => {
const notifyProps = {
user_id: userId,
channel_id: channelId,
...props,
};
try {
await client_1.Client4.updateChannelNotifyProps(notifyProps);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
const member = getState().entities.channels.myMembers[channelId] || {};
const currentNotifyProps = member.notify_props || {};
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL_PROPS,
data: {
channel_id: channelId,
notifyProps: { ...currentNotifyProps, ...notifyProps },
},
});
return { data: true };
};
}
function getChannelByNameAndTeamName(teamName, channelName, includeDeleted = false) {
return async (dispatch, getState) => {
let data;
try {
data = await client_1.Client4.getChannelByNameAndTeamName(teamName, channelName, includeDeleted);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL,
data,
});
return { data };
};
}
function getChannel(channelId, asContentReviewer = false) {
return async (dispatch, getState) => {
let data;
try {
data = await client_1.Client4.getChannel(channelId, asContentReviewer);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL,
data,
});
return { data };
};
}
function getChannelAndMyMember(channelId) {
return async (dispatch, getState) => {
let channel;
let member;
try {
const channelRequest = client_1.Client4.getChannel(channelId);
const memberRequest = client_1.Client4.getMyChannelMember(channelId);
channel = await channelRequest;
member = await memberRequest;
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL,
data: channel,
},
{
type: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
data: member,
},
]));
dispatch((0, roles_1.loadRolesIfNeeded)(member.roles.split(' ')));
return { data: { channel, member } };
};
}
function getChannelTimezones(channelId) {
return async (dispatch, getState) => {
let channelTimezones;
try {
const channelTimezonesRequest = client_1.Client4.getChannelTimezones(channelId);
channelTimezones = await channelTimezonesRequest;
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
return { data: channelTimezones };
};
}
function fetchChannelsAndMembers(teamId) {
return async (dispatch, getState) => {
let channels = [];
let channelMembers = [];
try {
[channels, channelMembers] = await Promise.all([
client_1.Client4.getMyChannels(teamId),
client_1.Client4.getMyChannelMembers(teamId),
]);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error: error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNELS,
teamId,
data: channels,
},
{
type: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS,
data: channelMembers,
},
]));
const roles = new Set();
for (const member of channelMembers) {
for (const role of member.roles.split(' ')) {
roles.add(role);
}
}
if (roles.size > 0) {
dispatch((0, roles_1.loadRolesIfNeeded)(roles));
}
return { data: { channels, channelMembers } };
};
}
function fetchAllMyChannelMembers() {
return async (dispatch, getState) => {
const state = getState();
const { currentUserId } = state.entities.users;
let channelMembers = [];
try {
// The server exposes a streaming API if page is set to -1
// We don't need to paginate through the responses, and thefore pageSize doesn't matter
channelMembers = await client_1.Client4.getAllChannelsMembers(currentUserId, -1);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
const roles = new Set();
for (const member of channelMembers) {
for (const role of member.roles.split(' ')) {
roles.add(role);
}
}
if (roles.size > 0) {
dispatch((0, roles_1.loadRolesIfNeeded)(roles));
}
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBERS,
data: channelMembers,
currentUserId,
});
return { data: channelMembers };
};
}
function fetchAllMyTeamsChannels() {
return async (dispatch, getState) => {
let channels;
try {
channels = await client_1.Client4.getAllTeamsChannels();
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_CHANNELS,
data: channels,
});
return { data: channels };
};
}
function getChannelMembers(channelId, page = 0, perPage = constants_1.General.CHANNELS_CHUNK_SIZE) {
return async (dispatch, getState) => {
let channelMembers;
try {
const channelMembersRequest = client_1.Client4.getChannelMembers(channelId, page, perPage);
channelMembers = await channelMembersRequest;
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
const userIds = channelMembers.map((cm) => cm.user_id);
dispatch((0, users_1.getMissingProfilesByIds)(userIds));
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL_MEMBERS,
data: channelMembers,
});
return { data: channelMembers };
};
}
function leaveChannel(channelId) {
return async (dispatch, getState) => {
const state = getState();
const { currentUserId } = state.entities.users;
const { channels, myMembers } = state.entities.channels;
const channel = channels[channelId];
const member = myMembers[channelId];
dispatch({
type: action_types_1.ChannelTypes.LEAVE_CHANNEL,
data: {
id: channelId,
user_id: currentUserId,
team_id: channel.team_id,
type: channel.type,
},
});
(async function removeFromChannelWrapper() {
try {
await client_1.Client4.removeFromChannel(currentUserId, channelId);
}
catch {
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL,
data: channel,
},
{
type: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
data: member,
},
]));
// The category here may not be the one in which the channel was originally located,
// much less the order in which it was placed. Treating this as a transient issue
// for the user to resolve by refreshing or leaving again.
dispatch((0, channel_categories_3.addChannelToInitialCategory)(channel, false));
}
}());
return { data: true };
};
}
function joinChannel(userId, teamId, channelId, channelName) {
return async (dispatch, getState) => {
if (!channelId && !channelName) {
return { data: null };
}
let member;
let channel;
try {
if (channelId) {
member = await client_1.Client4.addToChannel(userId, channelId);
channel = await client_1.Client4.getChannel(channelId);
}
else {
channel = await client_1.Client4.getChannelByName(teamId, channelName, true);
if ((channel.type === constants_1.General.GM_CHANNEL) || (channel.type === constants_1.General.DM_CHANNEL)) {
member = await client_1.Client4.getChannelMember(channel.id, userId);
}
else {
member = await client_1.Client4.addToChannel(userId, channel.id);
}
}
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL,
data: channel,
},
{
type: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
data: member,
},
]));
dispatch((0, channel_categories_3.addChannelToInitialCategory)(channel));
if (member) {
dispatch((0, roles_1.loadRolesIfNeeded)(member.roles.split(' ')));
}
return { data: { channel, member } };
};
}
function deleteChannel(channelId) {
return async (dispatch, getState) => {
try {
await client_1.Client4.deleteChannel(channelId);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch({ type: action_types_1.ChannelTypes.DELETE_CHANNEL_SUCCESS, data: { id: channelId } });
return { data: true };
};
}
function unarchiveChannel(channelId) {
return async (dispatch, getState) => {
try {
await client_1.Client4.unarchiveChannel(channelId);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch({ type: action_types_1.ChannelTypes.UNARCHIVED_CHANNEL_SUCCESS, data: { id: channelId } });
return { data: true };
};
}
function updateApproximateViewTime(channelId) {
return async (dispatch, getState) => {
const { currentUserId } = getState().entities.users;
const { myPreferences } = getState().entities.preferences;
const viewTimePref = myPreferences[`${constants_1.Preferences.CATEGORY_CHANNEL_APPROXIMATE_VIEW_TIME}--${channelId}`];
const viewTime = viewTimePref ? parseInt(viewTimePref.value, 10) : 0;
if (viewTime < new Date().getTime() - (3 * 60 * 60 * 1000)) {
const preferences = [
{ user_id: currentUserId, category: constants_1.Preferences.CATEGORY_CHANNEL_APPROXIMATE_VIEW_TIME, name: channelId, value: new Date().getTime().toString() },
];
dispatch((0, preferences_1.savePreferences)(currentUserId, preferences));
}
return { data: true };
};
}
function unsetActiveChannelOnServer() {
return async (dispatch, getState) => {
try {
// The view channel api in the server handles the active channel
await client_1.Client4.viewMyChannel('');
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { data: false };
}
return { data: true };
};
}
function readMultipleChannels(channelIds) {
return async (dispatch, getState) => {
let response;
try {
response = await client_1.Client4.readMultipleChannels(channelIds);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch(markMultipleChannelsAsRead(response.last_viewed_at_times));
return { data: true };
};
}
function getChannels(teamId, page = 0, perPage = constants_1.General.CHANNELS_CHUNK_SIZE) {
return async (dispatch, getState) => {
dispatch({ type: action_types_1.ChannelTypes.GET_CHANNELS_REQUEST, data: null });
let channels;
try {
channels = await client_1.Client4.getChannels(teamId, page, perPage);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.GET_CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNELS,
teamId,
data: channels,
},
{
type: action_types_1.ChannelTypes.GET_CHANNELS_SUCCESS,
},
]));
return { data: channels };
};
}
function getArchivedChannels(teamId, page = 0, perPage = constants_1.General.CHANNELS_CHUNK_SIZE) {
return async (dispatch, getState) => {
let channels;
try {
channels = await client_1.Client4.getArchivedChannels(teamId, page, perPage);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
return { error };
}
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_CHANNELS,
teamId,
data: channels,
});
return { data: channels };
};
}
function getAllChannelsWithCount(page = 0, perPage = constants_1.General.CHANNELS_CHUNK_SIZE, notAssociatedToGroup = '', excludeDefaultChannels = false, includeDeleted = false, excludePolicyConstrained = false, accessControlPolicyEnforced = false, excludeAccessControlPolicyEnforced = false) {
return async (dispatch, getState) => {
dispatch({ type: action_types_1.ChannelTypes.GET_ALL_CHANNELS_REQUEST, data: null });
let payload;
try {
payload = await client_1.Client4.getAllChannels(page, perPage, notAssociatedToGroup, excludeDefaultChannels, true, includeDeleted, excludePolicyConstrained, accessControlPolicyEnforced, excludeAccessControlPolicyEnforced);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.GET_ALL_CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_ALL_CHANNELS,
data: payload.channels,
},
{
type: action_types_1.ChannelTypes.GET_ALL_CHANNELS_SUCCESS,
},
{
type: action_types_1.ChannelTypes.RECEIVED_TOTAL_CHANNEL_COUNT,
data: payload.total_count,
},
]));
return { data: payload };
};
}
function getAllChannels(page = 0, perPage = constants_1.General.CHANNELS_CHUNK_SIZE, notAssociatedToGroup = '', excludeDefaultChannels = false, excludePolicyConstrained = false, excludeAccessControlPolicyEnforced = false, accessControlPolicyEnforced = false) {
return async (dispatch, getState) => {
dispatch({ type: action_types_1.ChannelTypes.GET_ALL_CHANNELS_REQUEST, data: null });
let channels;
try {
channels = await client_1.Client4.getAllChannels(page, perPage, notAssociatedToGroup, excludeDefaultChannels, false, false, excludePolicyConstrained, accessControlPolicyEnforced, excludeAccessControlPolicyEnforced);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.GET_ALL_CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_ALL_CHANNELS,
data: channels,
},
{
type: action_types_1.ChannelTypes.GET_ALL_CHANNELS_SUCCESS,
},
]));
return { data: channels };
};
}
function autocompleteChannels(teamId, term) {
return async (dispatch, getState) => {
dispatch({ type: action_types_1.ChannelTypes.GET_CHANNELS_REQUEST, data: null });
let channels;
try {
channels = await client_1.Client4.autocompleteChannels(teamId, term);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.GET_CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNELS,
teamId,
data: channels,
},
{
type: action_types_1.ChannelTypes.GET_CHANNELS_SUCCESS,
},
]));
return { data: channels };
};
}
function autocompleteChannelsForSearch(teamId, term) {
return async (dispatch, getState) => {
dispatch({ type: action_types_1.ChannelTypes.GET_CHANNELS_REQUEST, data: null });
let channels;
try {
channels = await client_1.Client4.autocompleteChannelsForSearch(teamId, term);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.GET_CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNELS,
teamId,
data: channels,
},
{
type: action_types_1.ChannelTypes.GET_CHANNELS_SUCCESS,
},
]));
return { data: channels };
};
}
function searchChannels(teamId, term) {
return async (dispatch, getState) => {
dispatch({ type: action_types_1.ChannelTypes.GET_CHANNELS_REQUEST, data: null });
let channels;
try {
channels = await client_1.Client4.searchChannels(teamId, term);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.GET_CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNELS,
teamId,
data: channels,
},
{
type: action_types_1.ChannelTypes.GET_CHANNELS_SUCCESS,
},
]));
return { data: channels };
};
}
function searchAllChannels(term, opts = {}) {
return async (dispatch, getState) => {
dispatch({ type: action_types_1.ChannelTypes.GET_ALL_CHANNELS_REQUEST, data: null });
let response;
try {
response = await client_1.Client4.searchAllChannels(term, opts);
}
catch (error) {
if (opts.signal?.aborted) {
return { error };
}
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch({ type: action_types_1.ChannelTypes.GET_ALL_CHANNELS_FAILURE, error });
dispatch((0, errors_1.logError)(error));
return { error };
}
const channels = 'channels' in response ? response.channels : response;
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.ChannelTypes.RECEIVED_ALL_CHANNELS,
data: channels,
},
{
type: action_types_1.ChannelTypes.GET_ALL_CHANNELS_SUCCESS,
},
]));
return { data: response };
};
}
function searchGroupChannels(term) {
return (0, helpers_1.bindClientFunc)({
clientFunc: client_1.Client4.searchGroupChannels,
params: [term],
});
}
function getChannelStats(channelId, includeFileCount) {
return async (dispatch, getState) => {
let stat;
try {
stat = await client_1.Client4.getChannelStats(channelId, includeFileCount);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL_STATS,
data: stat,
});
return { data: stat };
};
}
function getChannelsMemberCount(channelIds) {
return async (dispatch, getState) => {
let channelsMemberCount;
try {
channelsMemberCount = await client_1.Client4.getChannelsMemberCount(channelIds);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch({
type: action_types_1.ChannelTypes.RECEIVED_CHANNELS_MEMBER_COUNT,
data: channelsMemberCount,
});
return { data: channelsMemberCount };
};
}
function addChannelMember(channelId, userId, postRootId = '') {
return async (dispatch, getState) => {
let member;
try {
member = await client_1.Client4.addToChannel(userId, channelId, postRootId);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
const membersInChannel = getState().entities.channels.membersInChannel[channelId];
if (!(membersInChannel && userId in membersInChannel)) {
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.UserTypes.RECEIVED_PROFILE_IN_CHANNEL,
data: { id: channelId, user_id: userId },
},
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL_MEMBER,
data: member,
},
{
type: action_types_1.ChannelTypes.ADD_CHANNEL_MEMBER_SUCCESS,
id: channelId,
},
], 'ADD_CHANNEL_MEMBER.BATCH'));
}
return { data: member };
};
}
function addChannelMembers(channelId, userIds, postRootId = '') {
const batchSize = 1000;
return async (dispatch, getState) => {
const channelMembers = [];
try {
for (let i = 0; i < userIds.length; i += batchSize) {
// eslint-disable-next-line no-await-in-loop
const cm = await client_1.Client4.addToChannels(userIds.slice(i, i + batchSize), channelId, postRootId);
channelMembers.push(...cm);
}
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
const ids = channelMembers.map((member) => ({ id: member.user_id }));
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.UserTypes.RECEIVED_PROFILES_IN_CHANNEL,
id: channelId,
data: ids,
},
{
type: action_types_1.ChannelTypes.RECEIVED_CHANNEL_MEMBERS,
data: channelMembers,
},
{
type: action_types_1.ChannelTypes.ADD_CHANNEL_MEMBER_SUCCESS,
id: channelId,
count: channelMembers.length,
},
], 'ADD_CHANNEL_MEMBERS.BATCH'));
return { data: channelMembers };
};
}
function removeChannelMember(channelId, userId) {
return async (dispatch, getState) => {
try {
await client_1.Client4.removeFromChannel(userId, channelId);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
dispatch((0, redux_batched_actions_1.batchActions)([
{
type: action_types_1.UserTypes.RECEIVED_PROFILE_NOT_IN_CHANNEL,
data: { id: channelId, user_id: userId },
},
{
type: action_types_1.ChannelTypes.REMOVE_CHANNEL_MEMBER_SUCCESS,
id: channelId,
},
], 'REMOVE_CHANNEL_MEMBER.BATCH'));
return { data: true };
};
}
function markChannelAsRead(channelId, skipUpdateViewTime = false) {
return (dispatch, getState) => {
if (skipUpdateViewTime) {
dispatch(updateApproximateViewTime(channelId));
}
dispatch(markChannelAsViewedOnServer(channelId));
const actions = actionsToMarkChannelAsRead(getState, channelId);
if (actions.length > 0) {
dispatch((0, redux_batched_actions_1.batchActions)(actions));
}
return { data: true };
};
}
function markMultipleChannelsAsRead(channelTimes) {
return (dispatch, getState) => {
const actions = [];
for (const id of Object.keys(channelTimes)) {
actions.push(...actionsToMarkChannelAsRead(getState, id, channelTimes[id]));
}
if (actions.length > 0) {
dispatch((0, redux_batched_actions_1.batchActions)(actions));
}
return { data: true };
};
}
function markChannelAsViewedOnServer(channelId) {
return async (dispatch, getState) => {
try {
await client_1.Client4.viewMyChannel(channelId);
}
catch (error) {
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
dispatch((0, errors_1.logError)(error));
return { error };
}
// const actions: AnyAction[] = [];
// for (const id of Object.keys(response.last_viewed_at_times)) {
// actions.push({
// type: ChannelTypes.RECEIVED_LAST_VIEWED_AT,
// data: {
// channel_id: channelId,
// last_viewed_at: response.last_viewed_at_times[id],
// },
// });
// }
return { data: true };
};
}
function actionsToMarkChannelAsRead(getState, channelId, viewedAt = Date.now()) {
const state = getState();
const { channels, messageCounts, myMembers } = state.entities.channels;
// Update channel member objects to set all mentions and posts as viewed
const channel = channels[channelId];
const messageCount = messageCounts[channelId];
// Update team member objects to set mentions and posts in channel as viewed
const channelMember = myMembers[channelId];
const actions = [];
if (channel && channelMember) {
actions.push({
type: action_types_1.ChannelTypes.DECREMENT_UNREAD_MSG_COUNT,
data: {
teamId: channel.team_id,
channelId,
amount: messageCount.total - channelMember.msg_count,
amountRoot: messageCount.root - channelMember.msg_count_root,
},
});
actions.push({
type: action_types_1.ChannelTypes.DECREMENT_UNREAD_MENTION_COUNT,
data: {
teamId: channel.team_id,
channelId,
amount: channelMember.mention_count,
amountRoot: channelMember.mention_count_root,
amountUrgent: channelMember.urgent_mention_count,
},
});
actions.push({
type: action_types_1.ChannelTypes.RECEIVED_LAST_VIEWED_AT,
data: {
channel_id: channelId,
last_viewed_at: viewedAt,
},
});
}
if (channel && (0, channels_2.isManuallyUnread)(getState(), channelId)) {
actions.push({
type: action_types_1.ChannelTypes.REMOVE_MANUALLY_UNREAD,
data: { channelId },
});
}
return actions;
}
function actionsToMarkChannelAsUnread(getState, teamId, channelId, mentions, fetchedChannelMember = false, isRoot = false, priority = '') {
const state = getState();
const { myMembers } = state.entities.channels;
const { currentUserId } = state.entities.users;
const actions = [{
type: action_types_1.ChannelTypes.INCREMENT_UNREAD_MSG_COUNT,
data: {
teamId,
channelId,
amount: 1,
amountRoot: isRoot ? 1 : 0,
onlyMentions: myMembers[channelId] && myMembers[channelId].notify_props &&
myMembers[channelId].notify_props.mark_unread === channels_1.MarkUnread.MENTION,
fetchedChannelMember,
},
}];
if (!fetchedChannelMember) {
actions.push({
type: action_types_1.ChannelTypes.INCREMENT_TOTAL_MSG_COUNT,
data: {
channelId,
amountRoot: isRoot ? 1 : 0,
amount: 1,
},
});
}
if (mentions && mentions.indexOf(currentUserId) !== -1) {
actions.push({
type: action_types_1.ChannelTypes.INCREMENT_UNREAD_MENTION_COUNT,
data: {
teamId,
channelId,
amountRoot: isRoot ? 1 : 0,
amount: 1,
amountUrgent: priority === 'urgent' ? 1 : 0,
fetchedChannelMember,
},
});
}
return actions;
}
function getChannelMembersByIds(channelId, userIds) {
return (0, helpers_1.bindClientFunc)({
clientFunc: client_1.Client4.getChannelMembersByIds,
onSuccess: action_types_1.ChannelTypes.RECEIVED_CHANNEL_MEMBERS,
params: [
channelId,
userIds,
],
});
}
function getChannelMember(channelId, userId) {
return (0, helpers_1.bindClientFunc)({
clientFunc: client_1.Client4.getChannelMember,
onSuccess: action_types_1.ChannelTypes.RECEIVED_CHANNEL_MEMBER,
params: [
channelId,
userId,
],
});
}
function getMyChannelMember(channelId) {
return (0, helpers_1.bindClientFunc)({
clientFunc: client_1.Client4.getMyChannelMember,
onSuccess: action_types_1.ChannelTypes.RECEIVED_MY_CHANNEL_MEMBER,
params: [
channelId,
],
});
}
function loadMyChannelMemberAndRole(channelId) {
return async (dispatch) => {
const result = await dispatch(getMyChannelMember(channelId));
const roles = result.data?.roles.split(' ');
if (roles && roles.length > 0) {
dispatch((0, roles_1.loadRolesIfNeeded)(roles));
}
return { data: true };
};
}
// favoriteChannel moves the provided channel into the current team's Favorites category.
function favoriteChannel(channelId) {
return async (dispatch, getState) => {
const state = getState();
const channel = (0, channels_2.getChannel)(state, channelId);
const category = (0, channel_categories_2.getCategoryInTeamByType)(state, channel?.team_id || (0, teams_1.getCurrentTeamId)(state), channel_categories_1.CategoryTypes.FAVORITES);
if (!category) {
return { data: false };
}
return dispatch((0, channel_categories_3.addChannelToCategory)(category.id, channelId));
};
}
// unfavoriteChannel moves the provided channel into the current team's Channels/DMs category.
function unfavoriteChannel(channelId) {
return async (dispatch, getState) => {
const state = getState();
const channel = (0, channels_2.getChannel)(state, channelId);
if (!channel) {
return { data: false };
}
const category = (0, channel_categories_2.getCategoryInTeamByType)(state, channel.team_id || (0, teams_1.getCurrentTeamId)(state), channel.type === constants_1.General.DM_CHANNEL || channel.type === constants_1.General.GM_CHANNEL ? channel_categories_1.CategoryTypes.DIRECT_MESSAGES : cha