mattermost-redux 11.5.0 → 11.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/action_types/content_flagging.d.ts +3 -0
- package/lib/action_types/content_flagging.js +3 -0
- package/lib/action_types/files.d.ts +1 -0
- package/lib/action_types/files.js +1 -0
- package/lib/actions/content_flagging.d.ts +14 -0
- package/lib/actions/content_flagging.js +119 -0
- package/lib/actions/limits.js +2 -1
- package/lib/actions/posts.js +14 -0
- package/lib/actions/search.js +14 -2
- package/lib/actions/shared_channels.d.ts +1 -1
- package/lib/actions/shared_channels.js +2 -2
- package/lib/actions/users.d.ts +3 -1
- package/lib/actions/users.js +19 -0
- package/lib/constants/general.d.ts +2 -0
- package/lib/constants/general.js +2 -0
- package/lib/constants/stats.d.ts +1 -0
- package/lib/constants/stats.js +1 -0
- package/lib/reducers/entities/admin.js +3 -0
- package/lib/reducers/entities/content_flagging.d.ts +18 -0
- package/lib/reducers/entities/content_flagging.js +51 -0
- package/lib/reducers/entities/files.d.ts +3 -0
- package/lib/reducers/entities/files.js +19 -0
- package/lib/reducers/entities/index.d.ts +30 -0
- package/lib/reducers/index.d.ts +30 -0
- package/lib/selectors/entities/access_control.d.ts +0 -1
- package/lib/selectors/entities/access_control.js +0 -6
- package/lib/selectors/entities/agents.d.ts +1 -0
- package/lib/selectors/entities/agents.js +6 -1
- package/lib/selectors/entities/content_flagging.d.ts +4 -0
- package/lib/selectors/entities/content_flagging.js +28 -1
- package/lib/selectors/entities/files.d.ts +2 -0
- package/lib/selectors/entities/files.js +9 -0
- package/lib/store/initial_state.js +1 -0
- package/lib/utils/data_loader.d.ts +4 -0
- package/lib/utils/data_loader.js +22 -4
- package/lib/utils/emoji_utils.d.ts +2 -2
- package/lib/utils/emoji_utils.js +6 -10
- package/lib/utils/integration_utils.js +58 -2
- package/lib/utils/user_utils.js +2 -0
- package/package.json +3 -3
|
@@ -3,5 +3,8 @@ declare const _default: {
|
|
|
3
3
|
RECEIVED_POST_CONTENT_FLAGGING_FIELDS: "RECEIVED_POST_CONTENT_FLAGGING_FIELDS";
|
|
4
4
|
RECEIVED_POST_CONTENT_FLAGGING_VALUES: "RECEIVED_POST_CONTENT_FLAGGING_VALUES";
|
|
5
5
|
CONTENT_FLAGGING_REPORT_VALUE_UPDATED: "CONTENT_FLAGGING_REPORT_VALUE_UPDATED";
|
|
6
|
+
RECEIVED_FLAGGED_POST: "RECEIVED_FLAGGED_POST";
|
|
7
|
+
RECEIVED_CONTENT_FLAGGING_CHANNEL: "RECEIVED_CONTENT_FLAGGING_CHANNEL";
|
|
8
|
+
RECEIVED_CONTENT_FLAGGING_TEAM: "RECEIVED_CONTENT_FLAGGING_TEAM";
|
|
6
9
|
};
|
|
7
10
|
export default _default;
|
|
@@ -11,4 +11,7 @@ exports.default = (0, key_mirror_1.default)({
|
|
|
11
11
|
RECEIVED_POST_CONTENT_FLAGGING_FIELDS: null,
|
|
12
12
|
RECEIVED_POST_CONTENT_FLAGGING_VALUES: null,
|
|
13
13
|
CONTENT_FLAGGING_REPORT_VALUE_UPDATED: null,
|
|
14
|
+
RECEIVED_FLAGGED_POST: null,
|
|
15
|
+
RECEIVED_CONTENT_FLAGGING_CHANNEL: null,
|
|
16
|
+
RECEIVED_CONTENT_FLAGGING_TEAM: null,
|
|
14
17
|
});
|
|
@@ -1,10 +1,24 @@
|
|
|
1
|
+
import type { Channel } from '@mattermost/types/channels';
|
|
1
2
|
import type { ContentFlaggingConfig } from '@mattermost/types/content_flagging';
|
|
3
|
+
import type { Post } from '@mattermost/types/posts';
|
|
2
4
|
import type { NameMappedPropertyFields, PropertyValue } from '@mattermost/types/properties';
|
|
5
|
+
import type { Team } from '@mattermost/types/teams';
|
|
3
6
|
import type { ActionFuncAsync } from 'mattermost-redux/types/actions';
|
|
7
|
+
export type ContentFlaggingChannelRequestIdentifier = {
|
|
8
|
+
channelId?: string;
|
|
9
|
+
flaggedPostId?: string;
|
|
10
|
+
};
|
|
11
|
+
export type ContentFlaggingTeamRequestIdentifier = {
|
|
12
|
+
teamId?: string;
|
|
13
|
+
flaggedPostId?: string;
|
|
14
|
+
};
|
|
4
15
|
export declare function getTeamContentFlaggingStatus(teamId: string): ActionFuncAsync<{
|
|
5
16
|
enabled: boolean;
|
|
6
17
|
}>;
|
|
7
18
|
export declare function getContentFlaggingConfig(teamId?: string): ActionFuncAsync<ContentFlaggingConfig>;
|
|
8
19
|
export declare function getPostContentFlaggingFields(): ActionFuncAsync<NameMappedPropertyFields>;
|
|
9
20
|
export declare function loadPostContentFlaggingFields(): ActionFuncAsync<NameMappedPropertyFields>;
|
|
21
|
+
export declare function loadFlaggedPost(flaggedPostId: string): ActionFuncAsync<Post>;
|
|
22
|
+
export declare function loadContentFlaggingChannel(identifier: ContentFlaggingChannelRequestIdentifier): ActionFuncAsync<Channel>;
|
|
23
|
+
export declare function loadContentFlaggingTeam(identifier: ContentFlaggingTeamRequestIdentifier): ActionFuncAsync<Team>;
|
|
10
24
|
export declare function getPostContentFlaggingValues(postId: string): ActionFuncAsync<Array<PropertyValue<unknown>>>;
|
|
@@ -6,12 +6,21 @@ exports.getTeamContentFlaggingStatus = getTeamContentFlaggingStatus;
|
|
|
6
6
|
exports.getContentFlaggingConfig = getContentFlaggingConfig;
|
|
7
7
|
exports.getPostContentFlaggingFields = getPostContentFlaggingFields;
|
|
8
8
|
exports.loadPostContentFlaggingFields = loadPostContentFlaggingFields;
|
|
9
|
+
exports.loadFlaggedPost = loadFlaggedPost;
|
|
10
|
+
exports.loadContentFlaggingChannel = loadContentFlaggingChannel;
|
|
11
|
+
exports.loadContentFlaggingTeam = loadContentFlaggingTeam;
|
|
9
12
|
exports.getPostContentFlaggingValues = getPostContentFlaggingValues;
|
|
10
13
|
const action_types_1 = require("mattermost-redux/action_types");
|
|
11
14
|
const errors_1 = require("mattermost-redux/actions/errors");
|
|
12
15
|
const helpers_1 = require("mattermost-redux/actions/helpers");
|
|
13
16
|
const client_1 = require("mattermost-redux/client");
|
|
14
17
|
const data_loader_1 = require("mattermost-redux/utils/data_loader");
|
|
18
|
+
function channelComparator(a, b) {
|
|
19
|
+
return a.channelId === b.channelId;
|
|
20
|
+
}
|
|
21
|
+
function teamComparator(a, b) {
|
|
22
|
+
return a.teamId === b.teamId;
|
|
23
|
+
}
|
|
15
24
|
function getTeamContentFlaggingStatus(teamId) {
|
|
16
25
|
return async (dispatch, getState) => {
|
|
17
26
|
let response;
|
|
@@ -84,6 +93,116 @@ function loadPostContentFlaggingFields() {
|
|
|
84
93
|
return {};
|
|
85
94
|
};
|
|
86
95
|
}
|
|
96
|
+
function getFlaggedPost(flaggedPostId) {
|
|
97
|
+
return async (dispatch, getState) => {
|
|
98
|
+
let data;
|
|
99
|
+
try {
|
|
100
|
+
data = await client_1.Client4.getFlaggedPost(flaggedPostId);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
|
|
104
|
+
dispatch((0, errors_1.logError)(error));
|
|
105
|
+
return { error };
|
|
106
|
+
}
|
|
107
|
+
dispatch({
|
|
108
|
+
type: action_types_1.ContentFlaggingTypes.RECEIVED_FLAGGED_POST,
|
|
109
|
+
data,
|
|
110
|
+
});
|
|
111
|
+
return { data };
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function loadFlaggedPost(flaggedPostId) {
|
|
115
|
+
return async (dispatch, getState, { loaders }) => {
|
|
116
|
+
if (!loaders.flaggedPostLoader) {
|
|
117
|
+
loaders.flaggedPostLoader = new data_loader_1.DelayedDataLoader({
|
|
118
|
+
fetchBatch: ([postId]) => dispatch(getFlaggedPost(postId)),
|
|
119
|
+
maxBatchSize: 1,
|
|
120
|
+
wait: 200,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const loader = loaders.flaggedPostLoader;
|
|
124
|
+
loader.queue([flaggedPostId]);
|
|
125
|
+
return {};
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function getContentFlaggingChannel(channelId, flaggedPostId) {
|
|
129
|
+
return async (dispatch, getState) => {
|
|
130
|
+
let data;
|
|
131
|
+
try {
|
|
132
|
+
data = await client_1.Client4.getChannel(channelId, true, flaggedPostId);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
|
|
136
|
+
dispatch((0, errors_1.logError)(error));
|
|
137
|
+
return { error };
|
|
138
|
+
}
|
|
139
|
+
dispatch({
|
|
140
|
+
type: action_types_1.ContentFlaggingTypes.RECEIVED_CONTENT_FLAGGING_CHANNEL,
|
|
141
|
+
data,
|
|
142
|
+
});
|
|
143
|
+
return { data };
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function loadContentFlaggingChannel(identifier) {
|
|
147
|
+
return async (dispatch, getState, { loaders }) => {
|
|
148
|
+
if (!loaders.contentFlaggingChannelLoader) {
|
|
149
|
+
loaders.contentFlaggingChannelLoader =
|
|
150
|
+
new data_loader_1.DelayedDataLoader({
|
|
151
|
+
fetchBatch: ([{ flaggedPostId, channelId }]) => {
|
|
152
|
+
if (channelId && flaggedPostId) {
|
|
153
|
+
return dispatch(getContentFlaggingChannel(channelId, flaggedPostId));
|
|
154
|
+
}
|
|
155
|
+
return Promise.resolve(null);
|
|
156
|
+
},
|
|
157
|
+
maxBatchSize: 1,
|
|
158
|
+
wait: 200,
|
|
159
|
+
comparator: channelComparator,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
const loader = loaders.contentFlaggingChannelLoader;
|
|
163
|
+
loader.queue([identifier]);
|
|
164
|
+
return {};
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function getContentFlaggingTeam(teamId, flaggedPostId) {
|
|
168
|
+
return async (dispatch, getState) => {
|
|
169
|
+
let data;
|
|
170
|
+
try {
|
|
171
|
+
data = await client_1.Client4.getTeam(teamId, true, flaggedPostId);
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
|
|
175
|
+
dispatch((0, errors_1.logError)(error));
|
|
176
|
+
return { error };
|
|
177
|
+
}
|
|
178
|
+
dispatch({
|
|
179
|
+
type: action_types_1.ContentFlaggingTypes.RECEIVED_CONTENT_FLAGGING_TEAM,
|
|
180
|
+
data,
|
|
181
|
+
});
|
|
182
|
+
return { data };
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function loadContentFlaggingTeam(identifier) {
|
|
186
|
+
return async (dispatch, getState, { loaders }) => {
|
|
187
|
+
if (!loaders.contentFlaggingTeamLoader) {
|
|
188
|
+
loaders.contentFlaggingTeamLoader =
|
|
189
|
+
new data_loader_1.DelayedDataLoader({
|
|
190
|
+
fetchBatch: ([{ flaggedPostId, teamId }]) => {
|
|
191
|
+
if (teamId && flaggedPostId) {
|
|
192
|
+
return dispatch(getContentFlaggingTeam(teamId, flaggedPostId));
|
|
193
|
+
}
|
|
194
|
+
return Promise.resolve(null);
|
|
195
|
+
},
|
|
196
|
+
maxBatchSize: 1,
|
|
197
|
+
wait: 200,
|
|
198
|
+
comparator: teamComparator,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
const loader = loaders.contentFlaggingTeamLoader;
|
|
202
|
+
loader.queue([identifier]);
|
|
203
|
+
return {};
|
|
204
|
+
};
|
|
205
|
+
}
|
|
87
206
|
function getPostContentFlaggingValues(postId) {
|
|
88
207
|
return async (dispatch, getState) => {
|
|
89
208
|
let response;
|
package/lib/actions/limits.js
CHANGED
|
@@ -23,9 +23,10 @@ function getServerLimits() {
|
|
|
23
23
|
activeUserCount: response?.data?.activeUserCount ?? 0,
|
|
24
24
|
maxUsersLimit: response?.data?.maxUsersLimit ?? 0,
|
|
25
25
|
maxUsersHardLimit: response?.data?.maxUsersHardLimit ?? 0,
|
|
26
|
-
// Post history limit fields from server response
|
|
27
26
|
lastAccessiblePostTime: response?.data?.lastAccessiblePostTime ?? 0,
|
|
28
27
|
postHistoryLimit: response?.data?.postHistoryLimit ?? 0,
|
|
28
|
+
singleChannelGuestCount: response?.data?.singleChannelGuestCount ?? 0,
|
|
29
|
+
singleChannelGuestLimit: response?.data?.singleChannelGuestLimit ?? 0,
|
|
29
30
|
};
|
|
30
31
|
dispatch({ type: action_types_1.LimitsTypes.RECEIVED_APP_LIMITS, data });
|
|
31
32
|
return { data };
|
package/lib/actions/posts.js
CHANGED
|
@@ -235,6 +235,20 @@ function createPost(post, files = [], afterSubmit) {
|
|
|
235
235
|
update_at: timestamp,
|
|
236
236
|
reply_count: 0,
|
|
237
237
|
};
|
|
238
|
+
// Add current_team_id for DM/GM posts to enable proper channel mention resolution
|
|
239
|
+
// This prevents cross-team information disclosure and makes mention resolution deterministic
|
|
240
|
+
const channel = state.entities.channels.channels[post.channel_id];
|
|
241
|
+
const currentTeamId = state.entities.teams.currentTeamId;
|
|
242
|
+
if (channel && !channel.team_id && currentTeamId) {
|
|
243
|
+
// DM/GM channel - add current team context
|
|
244
|
+
newPost = {
|
|
245
|
+
...newPost,
|
|
246
|
+
props: {
|
|
247
|
+
...newPost.props,
|
|
248
|
+
current_team_id: currentTeamId,
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
}
|
|
238
252
|
if (post.root_id) {
|
|
239
253
|
newPost.reply_count = PostSelectors.getPostRepliesCount(state, post.root_id) + 1;
|
|
240
254
|
}
|
package/lib/actions/search.js
CHANGED
|
@@ -29,7 +29,13 @@ function getMissingChannelsFromPosts(posts) {
|
|
|
29
29
|
const promises = [];
|
|
30
30
|
Object.values(posts).forEach((post) => {
|
|
31
31
|
const id = post.channel_id;
|
|
32
|
-
if (!channels[id]
|
|
32
|
+
if (!channels[id]) {
|
|
33
|
+
// Fetch channel data independently so a 403 on the membership request (e.g. for public channels
|
|
34
|
+
// the user hasn't joined) doesn't prevent the channel from being loaded.
|
|
35
|
+
promises.push(dispatch((0, channels_1.getChannel)(id)));
|
|
36
|
+
}
|
|
37
|
+
if (!myMembers[id]) {
|
|
38
|
+
// Best-effort: will 403 for non-member public channels, which is fine.
|
|
33
39
|
promises.push(dispatch((0, channels_1.getChannelAndMyMember)(id)));
|
|
34
40
|
}
|
|
35
41
|
if (!membersInChannel[id]) {
|
|
@@ -45,7 +51,13 @@ function getMissingChannelsFromFiles(files) {
|
|
|
45
51
|
const promises = [];
|
|
46
52
|
Object.values(files).forEach((file) => {
|
|
47
53
|
const id = file.channel_id;
|
|
48
|
-
if (!channels[id]
|
|
54
|
+
if (!channels[id]) {
|
|
55
|
+
// Fetch channel data independently so a 403 on the membership request (e.g. for public channels
|
|
56
|
+
// the user hasn't joined) doesn't prevent the channel from being loaded.
|
|
57
|
+
promises.push(dispatch((0, channels_1.getChannel)(id)));
|
|
58
|
+
}
|
|
59
|
+
if (!myMembers[id]) {
|
|
60
|
+
// Best-effort: will 403 for non-member public channels, which is fine.
|
|
49
61
|
promises.push(dispatch((0, channels_1.getChannelAndMyMember)(id)));
|
|
50
62
|
}
|
|
51
63
|
if (!membersInChannel[id]) {
|
|
@@ -15,4 +15,4 @@ export declare function receivedRemoteClusterInfo(remoteId: string, remoteInfo:
|
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
17
|
export declare function fetchChannelRemotes(channelId: string, forceRefresh?: boolean): ActionFuncAsync<RemoteClusterInfo[]>;
|
|
18
|
-
export declare function fetchRemoteClusterInfo(remoteId: string, forceRefresh?: boolean): ActionFuncAsync<RemoteClusterInfo>;
|
|
18
|
+
export declare function fetchRemoteClusterInfo(remoteId: string, includeDeleted?: boolean, forceRefresh?: boolean): ActionFuncAsync<RemoteClusterInfo>;
|
|
@@ -55,7 +55,7 @@ function fetchChannelRemotes(channelId, forceRefresh = false) {
|
|
|
55
55
|
return { data };
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
|
-
function fetchRemoteClusterInfo(remoteId, forceRefresh = false) {
|
|
58
|
+
function fetchRemoteClusterInfo(remoteId, includeDeleted, forceRefresh = false) {
|
|
59
59
|
return async (dispatch, getState) => {
|
|
60
60
|
// Check if we already have the remote info cached
|
|
61
61
|
const state = getState();
|
|
@@ -65,7 +65,7 @@ function fetchRemoteClusterInfo(remoteId, forceRefresh = false) {
|
|
|
65
65
|
}
|
|
66
66
|
let data;
|
|
67
67
|
try {
|
|
68
|
-
data = await client_1.Client4.getRemoteClusterInfo(remoteId);
|
|
68
|
+
data = await client_1.Client4.getRemoteClusterInfo(remoteId, includeDeleted);
|
|
69
69
|
}
|
|
70
70
|
catch (error) {
|
|
71
71
|
(0, helpers_1.forceLogoutIfNecessary)(error, dispatch, getState);
|
package/lib/actions/users.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AnyAction } from 'redux';
|
|
2
2
|
import type { UserAutocomplete } from '@mattermost/types/autocomplete';
|
|
3
3
|
import type { Channel } from '@mattermost/types/channels';
|
|
4
|
-
import type { UserProfile, UserStatus, GetFilteredUsersStatsOpts, UsersStats, UserCustomStatus, UserAccessToken } from '@mattermost/types/users';
|
|
4
|
+
import type { UserProfile, UserStatus, GetFilteredUsersStatsOpts, UsersStats, UserCustomStatus, UserAccessToken, UserAuthUpdate } from '@mattermost/types/users';
|
|
5
5
|
import type { ActionFuncAsync } from 'mattermost-redux/types/actions';
|
|
6
6
|
export declare const maxUserIdsPerProfilesRequest = 100;
|
|
7
7
|
export declare const maxUserIdsPerStatusesRequest = 200;
|
|
@@ -60,6 +60,7 @@ export declare function searchProfiles(term: string, options?: any): ActionFuncA
|
|
|
60
60
|
export declare function updateMe(user: Partial<UserProfile>): ActionFuncAsync<UserProfile>;
|
|
61
61
|
export declare function saveCustomProfileAttribute(userID: string, attributeID: string, attributeValue: string | string[]): ActionFuncAsync<Record<string, string | string[]>>;
|
|
62
62
|
export declare function patchUser(user: UserProfile): ActionFuncAsync<UserProfile>;
|
|
63
|
+
export declare function updateUserAuth(userId: string, userAuth: UserAuthUpdate): ActionFuncAsync<UserAuthUpdate>;
|
|
63
64
|
export declare function updateUserRoles(userId: string, roles: string): ActionFuncAsync;
|
|
64
65
|
export declare function updateUserMfa(userId: string, activate: boolean, code?: string): ActionFuncAsync;
|
|
65
66
|
export declare function updateUserPassword(userId: string, currentPassword: string, newPassword: string): ActionFuncAsync;
|
|
@@ -104,6 +105,7 @@ declare const _default: {
|
|
|
104
105
|
getUserAudits: typeof getUserAudits;
|
|
105
106
|
searchProfiles: typeof searchProfiles;
|
|
106
107
|
updateMe: typeof updateMe;
|
|
108
|
+
updateUserAuth: typeof updateUserAuth;
|
|
107
109
|
updateUserRoles: typeof updateUserRoles;
|
|
108
110
|
updateUserMfa: typeof updateUserMfa;
|
|
109
111
|
updateUserPassword: typeof updateUserPassword;
|
package/lib/actions/users.js
CHANGED
|
@@ -48,6 +48,7 @@ exports.searchProfiles = searchProfiles;
|
|
|
48
48
|
exports.updateMe = updateMe;
|
|
49
49
|
exports.saveCustomProfileAttribute = saveCustomProfileAttribute;
|
|
50
50
|
exports.patchUser = patchUser;
|
|
51
|
+
exports.updateUserAuth = updateUserAuth;
|
|
51
52
|
exports.updateUserRoles = updateUserRoles;
|
|
52
53
|
exports.updateUserMfa = updateUserMfa;
|
|
53
54
|
exports.updateUserPassword = updateUserPassword;
|
|
@@ -945,6 +946,23 @@ function patchUser(user) {
|
|
|
945
946
|
return { data };
|
|
946
947
|
};
|
|
947
948
|
}
|
|
949
|
+
function updateUserAuth(userId, userAuth) {
|
|
950
|
+
return async (dispatch, getState) => {
|
|
951
|
+
let data;
|
|
952
|
+
try {
|
|
953
|
+
data = await client_1.Client4.updateUserAuth(userId, userAuth);
|
|
954
|
+
}
|
|
955
|
+
catch (error) {
|
|
956
|
+
dispatch((0, errors_1.logError)(error));
|
|
957
|
+
return { error };
|
|
958
|
+
}
|
|
959
|
+
const profile = getState().entities.users.profiles[userId];
|
|
960
|
+
if (profile) {
|
|
961
|
+
dispatch({ type: action_types_1.UserTypes.RECEIVED_PROFILE, data: { ...profile, auth_data: data.auth_data, auth_service: data.auth_service } });
|
|
962
|
+
}
|
|
963
|
+
return { data };
|
|
964
|
+
};
|
|
965
|
+
}
|
|
948
966
|
function updateUserRoles(userId, roles) {
|
|
949
967
|
return async (dispatch, getState) => {
|
|
950
968
|
try {
|
|
@@ -1309,6 +1327,7 @@ exports.default = {
|
|
|
1309
1327
|
getUserAudits,
|
|
1310
1328
|
searchProfiles,
|
|
1311
1329
|
updateMe,
|
|
1330
|
+
updateUserAuth,
|
|
1312
1331
|
updateUserRoles,
|
|
1313
1332
|
updateUserMfa,
|
|
1314
1333
|
updateUserPassword,
|
|
@@ -32,6 +32,8 @@ declare const _default: {
|
|
|
32
32
|
SYSTEM_USER_MANAGER_ROLE: string;
|
|
33
33
|
SYSTEM_READ_ONLY_ADMIN_ROLE: string;
|
|
34
34
|
SYSTEM_MANAGER_ROLE: string;
|
|
35
|
+
SHARED_CHANNEL_MANAGER_ROLE: string;
|
|
36
|
+
SECURE_CONNECTION_MANAGER_ROLE: string;
|
|
35
37
|
SYSTEM_USER_ACCESS_TOKEN_ROLE: string;
|
|
36
38
|
SYSTEM_POST_ALL_ROLE: string;
|
|
37
39
|
SYSTEM_POST_ALL_PUBLIC_ROLE: string;
|
package/lib/constants/general.js
CHANGED
|
@@ -36,6 +36,8 @@ exports.default = {
|
|
|
36
36
|
SYSTEM_USER_MANAGER_ROLE: 'system_user_manager',
|
|
37
37
|
SYSTEM_READ_ONLY_ADMIN_ROLE: 'system_read_only_admin',
|
|
38
38
|
SYSTEM_MANAGER_ROLE: 'system_manager',
|
|
39
|
+
SHARED_CHANNEL_MANAGER_ROLE: 'shared_channel_manager',
|
|
40
|
+
SECURE_CONNECTION_MANAGER_ROLE: 'secure_connection_manager',
|
|
39
41
|
SYSTEM_USER_ACCESS_TOKEN_ROLE: 'system_user_access_token',
|
|
40
42
|
SYSTEM_POST_ALL_ROLE: 'system_post_all',
|
|
41
43
|
SYSTEM_POST_ALL_PUBLIC_ROLE: 'system_post_all_public',
|
package/lib/constants/stats.d.ts
CHANGED
package/lib/constants/stats.js
CHANGED
|
@@ -209,6 +209,9 @@ function convertAnalyticsRowsToStats(data, name) {
|
|
|
209
209
|
case 'total_file_size':
|
|
210
210
|
key = constants_1.Stats.TOTAL_FILE_SIZE;
|
|
211
211
|
break;
|
|
212
|
+
case 'single_channel_guest_count':
|
|
213
|
+
key = constants_1.Stats.SINGLE_CHANNEL_GUESTS;
|
|
214
|
+
break;
|
|
212
215
|
}
|
|
213
216
|
if (key) {
|
|
214
217
|
stats[key] = row.value;
|
|
@@ -6,11 +6,29 @@ declare const _default: import("redux").Reducer<{
|
|
|
6
6
|
postValues: {
|
|
7
7
|
[key: string]: PropertyValue<unknown>[];
|
|
8
8
|
};
|
|
9
|
+
flaggedPosts: {
|
|
10
|
+
[key: string]: import("@mattermost/types/posts").Post;
|
|
11
|
+
};
|
|
12
|
+
channels: {
|
|
13
|
+
[key: string]: import("@mattermost/types/channels").Channel;
|
|
14
|
+
};
|
|
15
|
+
teams: {
|
|
16
|
+
[key: string]: import("@mattermost/types/teams").Team;
|
|
17
|
+
};
|
|
9
18
|
}, import("redux").AnyAction, Partial<{
|
|
10
19
|
settings: ContentFlaggingConfig | undefined;
|
|
11
20
|
fields: NameMappedPropertyFields | undefined;
|
|
12
21
|
postValues: {
|
|
13
22
|
[key: string]: PropertyValue<unknown>[];
|
|
14
23
|
} | undefined;
|
|
24
|
+
flaggedPosts: {
|
|
25
|
+
[key: string]: import("@mattermost/types/posts").Post;
|
|
26
|
+
} | undefined;
|
|
27
|
+
channels: {
|
|
28
|
+
[key: string]: import("@mattermost/types/channels").Channel;
|
|
29
|
+
} | undefined;
|
|
30
|
+
teams: {
|
|
31
|
+
[key: string]: import("@mattermost/types/teams").Team;
|
|
32
|
+
} | undefined;
|
|
15
33
|
}>>;
|
|
16
34
|
export default _default;
|
|
@@ -12,6 +12,8 @@ function settings(state = {}, action) {
|
|
|
12
12
|
...action.data,
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
+
case action_types_1.UserTypes.LOGOUT_SUCCESS:
|
|
16
|
+
return {};
|
|
15
17
|
default:
|
|
16
18
|
return state;
|
|
17
19
|
}
|
|
@@ -24,6 +26,8 @@ function fields(state = {}, action) {
|
|
|
24
26
|
...action.data,
|
|
25
27
|
};
|
|
26
28
|
}
|
|
29
|
+
case action_types_1.UserTypes.LOGOUT_SUCCESS:
|
|
30
|
+
return {};
|
|
27
31
|
default:
|
|
28
32
|
return state;
|
|
29
33
|
}
|
|
@@ -52,6 +56,50 @@ function postValues(state = {}, action) {
|
|
|
52
56
|
[postId]: Object.values(valuesByFieldId),
|
|
53
57
|
};
|
|
54
58
|
}
|
|
59
|
+
case action_types_1.UserTypes.LOGOUT_SUCCESS:
|
|
60
|
+
return {};
|
|
61
|
+
default:
|
|
62
|
+
return state;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function flaggedPosts(state = {}, action) {
|
|
66
|
+
switch (action.type) {
|
|
67
|
+
case action_types_1.ContentFlaggingTypes.RECEIVED_FLAGGED_POST: {
|
|
68
|
+
return {
|
|
69
|
+
...state,
|
|
70
|
+
[action.data.id]: action.data,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
case action_types_1.UserTypes.LOGOUT_SUCCESS:
|
|
74
|
+
return {};
|
|
75
|
+
default:
|
|
76
|
+
return state;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function channels(state = {}, action) {
|
|
80
|
+
switch (action.type) {
|
|
81
|
+
case action_types_1.ContentFlaggingTypes.RECEIVED_CONTENT_FLAGGING_CHANNEL: {
|
|
82
|
+
return {
|
|
83
|
+
...state,
|
|
84
|
+
[action.data.id]: action.data,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
case action_types_1.UserTypes.LOGOUT_SUCCESS:
|
|
88
|
+
return {};
|
|
89
|
+
default:
|
|
90
|
+
return state;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function teams(state = {}, action) {
|
|
94
|
+
switch (action.type) {
|
|
95
|
+
case action_types_1.ContentFlaggingTypes.RECEIVED_CONTENT_FLAGGING_TEAM: {
|
|
96
|
+
return {
|
|
97
|
+
...state,
|
|
98
|
+
[action.data.id]: action.data,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
case action_types_1.UserTypes.LOGOUT_SUCCESS:
|
|
102
|
+
return {};
|
|
55
103
|
default:
|
|
56
104
|
return state;
|
|
57
105
|
}
|
|
@@ -60,4 +108,7 @@ exports.default = (0, redux_1.combineReducers)({
|
|
|
60
108
|
settings,
|
|
61
109
|
fields,
|
|
62
110
|
postValues,
|
|
111
|
+
flaggedPosts,
|
|
112
|
+
channels,
|
|
113
|
+
teams,
|
|
63
114
|
});
|
|
@@ -3,11 +3,13 @@ import type { MMReduxAction } from 'mattermost-redux/action_types';
|
|
|
3
3
|
export declare function files(state: Record<string, FileInfo> | undefined, action: MMReduxAction): any;
|
|
4
4
|
export declare function filesFromSearch(state: Record<string, FileSearchResultItem> | undefined, action: MMReduxAction): any;
|
|
5
5
|
export declare function fileIdsByPostId(state: Record<string, string[]> | undefined, action: MMReduxAction): any;
|
|
6
|
+
export declare function rejectedFiles(state: Set<string> | undefined, action: MMReduxAction): Set<unknown>;
|
|
6
7
|
declare const _default: import("redux").Reducer<{
|
|
7
8
|
files: any;
|
|
8
9
|
filesFromSearch: any;
|
|
9
10
|
fileIdsByPostId: any;
|
|
10
11
|
filePublicLink: any;
|
|
12
|
+
rejectedFiles: Set<unknown>;
|
|
11
13
|
}, import("redux").AnyAction, Partial<{
|
|
12
14
|
files: Record<string, FileInfo> | undefined;
|
|
13
15
|
filesFromSearch: Record<string, FileSearchResultItem> | undefined;
|
|
@@ -15,5 +17,6 @@ declare const _default: import("redux").Reducer<{
|
|
|
15
17
|
filePublicLink: {
|
|
16
18
|
link: string;
|
|
17
19
|
} | undefined;
|
|
20
|
+
rejectedFiles: Set<string> | undefined;
|
|
18
21
|
}>>;
|
|
19
22
|
export default _default;
|
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
5
5
|
exports.files = files;
|
|
6
6
|
exports.filesFromSearch = filesFromSearch;
|
|
7
7
|
exports.fileIdsByPostId = fileIdsByPostId;
|
|
8
|
+
exports.rejectedFiles = rejectedFiles;
|
|
8
9
|
const redux_1 = require("redux");
|
|
9
10
|
const action_types_1 = require("mattermost-redux/action_types");
|
|
10
11
|
function files(state = {}, action) {
|
|
@@ -182,9 +183,27 @@ function filePublicLink(state = { link: '' }, action) {
|
|
|
182
183
|
return state;
|
|
183
184
|
}
|
|
184
185
|
}
|
|
186
|
+
function rejectedFiles(state = new Set(), action) {
|
|
187
|
+
switch (action.type) {
|
|
188
|
+
case action_types_1.FileTypes.FILE_DOWNLOAD_REJECTED: {
|
|
189
|
+
const { file_id: fileId } = action.data;
|
|
190
|
+
if (fileId) {
|
|
191
|
+
const nextState = new Set(state);
|
|
192
|
+
nextState.add(fileId);
|
|
193
|
+
return nextState;
|
|
194
|
+
}
|
|
195
|
+
return state;
|
|
196
|
+
}
|
|
197
|
+
case action_types_1.UserTypes.LOGOUT_SUCCESS:
|
|
198
|
+
return new Set();
|
|
199
|
+
default:
|
|
200
|
+
return state;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
185
203
|
exports.default = (0, redux_1.combineReducers)({
|
|
186
204
|
files,
|
|
187
205
|
filesFromSearch,
|
|
188
206
|
fileIdsByPostId,
|
|
189
207
|
filePublicLink,
|
|
208
|
+
rejectedFiles,
|
|
190
209
|
});
|
|
@@ -95,6 +95,7 @@ declare const _default: import("redux").Reducer<{
|
|
|
95
95
|
filesFromSearch: any;
|
|
96
96
|
fileIdsByPostId: any;
|
|
97
97
|
filePublicLink: any;
|
|
98
|
+
rejectedFiles: Set<unknown>;
|
|
98
99
|
};
|
|
99
100
|
preferences: {
|
|
100
101
|
myPreferences: any;
|
|
@@ -326,6 +327,15 @@ declare const _default: import("redux").Reducer<{
|
|
|
326
327
|
postValues: {
|
|
327
328
|
[key: string]: import("@mattermost/types/properties").PropertyValue<unknown>[];
|
|
328
329
|
};
|
|
330
|
+
flaggedPosts: {
|
|
331
|
+
[key: string]: import("@mattermost/types/posts").Post;
|
|
332
|
+
};
|
|
333
|
+
channels: {
|
|
334
|
+
[key: string]: import("@mattermost/types/channels").Channel;
|
|
335
|
+
};
|
|
336
|
+
teams: {
|
|
337
|
+
[key: string]: import("@mattermost/types/teams").Team;
|
|
338
|
+
};
|
|
329
339
|
};
|
|
330
340
|
}, import("redux").AnyAction, Partial<{
|
|
331
341
|
general: {
|
|
@@ -466,6 +476,7 @@ declare const _default: import("redux").Reducer<{
|
|
|
466
476
|
filesFromSearch: any;
|
|
467
477
|
fileIdsByPostId: any;
|
|
468
478
|
filePublicLink: any;
|
|
479
|
+
rejectedFiles: Set<unknown>;
|
|
469
480
|
} | Partial<{
|
|
470
481
|
files: Record<string, import("@mattermost/types/files").FileInfo> | undefined;
|
|
471
482
|
filesFromSearch: Record<string, import("@mattermost/types/files").FileSearchResultItem> | undefined;
|
|
@@ -473,6 +484,7 @@ declare const _default: import("redux").Reducer<{
|
|
|
473
484
|
filePublicLink: {
|
|
474
485
|
link: string;
|
|
475
486
|
} | undefined;
|
|
487
|
+
rejectedFiles: Set<string> | undefined;
|
|
476
488
|
}> | undefined;
|
|
477
489
|
preferences: {
|
|
478
490
|
myPreferences: any;
|
|
@@ -782,12 +794,30 @@ declare const _default: import("redux").Reducer<{
|
|
|
782
794
|
postValues: {
|
|
783
795
|
[key: string]: import("@mattermost/types/properties").PropertyValue<unknown>[];
|
|
784
796
|
};
|
|
797
|
+
flaggedPosts: {
|
|
798
|
+
[key: string]: import("@mattermost/types/posts").Post;
|
|
799
|
+
};
|
|
800
|
+
channels: {
|
|
801
|
+
[key: string]: import("@mattermost/types/channels").Channel;
|
|
802
|
+
};
|
|
803
|
+
teams: {
|
|
804
|
+
[key: string]: import("@mattermost/types/teams").Team;
|
|
805
|
+
};
|
|
785
806
|
} | Partial<{
|
|
786
807
|
settings: import("@mattermost/types/content_flagging").ContentFlaggingConfig | undefined;
|
|
787
808
|
fields: import("@mattermost/types/properties").NameMappedPropertyFields | undefined;
|
|
788
809
|
postValues: {
|
|
789
810
|
[key: string]: import("@mattermost/types/properties").PropertyValue<unknown>[];
|
|
790
811
|
} | undefined;
|
|
812
|
+
flaggedPosts: {
|
|
813
|
+
[key: string]: import("@mattermost/types/posts").Post;
|
|
814
|
+
} | undefined;
|
|
815
|
+
channels: {
|
|
816
|
+
[key: string]: import("@mattermost/types/channels").Channel;
|
|
817
|
+
} | undefined;
|
|
818
|
+
teams: {
|
|
819
|
+
[key: string]: import("@mattermost/types/teams").Team;
|
|
820
|
+
} | undefined;
|
|
791
821
|
}> | undefined;
|
|
792
822
|
}>>;
|
|
793
823
|
export default _default;
|
package/lib/reducers/index.d.ts
CHANGED
|
@@ -97,6 +97,7 @@ declare const _default: {
|
|
|
97
97
|
filesFromSearch: any;
|
|
98
98
|
fileIdsByPostId: any;
|
|
99
99
|
filePublicLink: any;
|
|
100
|
+
rejectedFiles: Set<unknown>;
|
|
100
101
|
};
|
|
101
102
|
preferences: {
|
|
102
103
|
myPreferences: any;
|
|
@@ -328,6 +329,15 @@ declare const _default: {
|
|
|
328
329
|
postValues: {
|
|
329
330
|
[key: string]: import("@mattermost/types/properties").PropertyValue<unknown>[];
|
|
330
331
|
};
|
|
332
|
+
flaggedPosts: {
|
|
333
|
+
[key: string]: import("@mattermost/types/posts").Post;
|
|
334
|
+
};
|
|
335
|
+
channels: {
|
|
336
|
+
[key: string]: import("@mattermost/types/channels").Channel;
|
|
337
|
+
};
|
|
338
|
+
teams: {
|
|
339
|
+
[key: string]: import("@mattermost/types/teams").Team;
|
|
340
|
+
};
|
|
331
341
|
};
|
|
332
342
|
}, import("redux").AnyAction, Partial<{
|
|
333
343
|
general: {
|
|
@@ -468,6 +478,7 @@ declare const _default: {
|
|
|
468
478
|
filesFromSearch: any;
|
|
469
479
|
fileIdsByPostId: any;
|
|
470
480
|
filePublicLink: any;
|
|
481
|
+
rejectedFiles: Set<unknown>;
|
|
471
482
|
} | Partial<{
|
|
472
483
|
files: Record<string, import("@mattermost/types/files").FileInfo> | undefined;
|
|
473
484
|
filesFromSearch: Record<string, import("@mattermost/types/files").FileSearchResultItem> | undefined;
|
|
@@ -475,6 +486,7 @@ declare const _default: {
|
|
|
475
486
|
filePublicLink: {
|
|
476
487
|
link: string;
|
|
477
488
|
} | undefined;
|
|
489
|
+
rejectedFiles: Set<string> | undefined;
|
|
478
490
|
}> | undefined;
|
|
479
491
|
preferences: {
|
|
480
492
|
myPreferences: any;
|
|
@@ -784,12 +796,30 @@ declare const _default: {
|
|
|
784
796
|
postValues: {
|
|
785
797
|
[key: string]: import("@mattermost/types/properties").PropertyValue<unknown>[];
|
|
786
798
|
};
|
|
799
|
+
flaggedPosts: {
|
|
800
|
+
[key: string]: import("@mattermost/types/posts").Post;
|
|
801
|
+
};
|
|
802
|
+
channels: {
|
|
803
|
+
[key: string]: import("@mattermost/types/channels").Channel;
|
|
804
|
+
};
|
|
805
|
+
teams: {
|
|
806
|
+
[key: string]: import("@mattermost/types/teams").Team;
|
|
807
|
+
};
|
|
787
808
|
} | Partial<{
|
|
788
809
|
settings: import("@mattermost/types/content_flagging").ContentFlaggingConfig | undefined;
|
|
789
810
|
fields: import("@mattermost/types/properties").NameMappedPropertyFields | undefined;
|
|
790
811
|
postValues: {
|
|
791
812
|
[key: string]: import("@mattermost/types/properties").PropertyValue<unknown>[];
|
|
792
813
|
} | undefined;
|
|
814
|
+
flaggedPosts: {
|
|
815
|
+
[key: string]: import("@mattermost/types/posts").Post;
|
|
816
|
+
} | undefined;
|
|
817
|
+
channels: {
|
|
818
|
+
[key: string]: import("@mattermost/types/channels").Channel;
|
|
819
|
+
} | undefined;
|
|
820
|
+
teams: {
|
|
821
|
+
[key: string]: import("@mattermost/types/teams").Team;
|
|
822
|
+
} | undefined;
|
|
793
823
|
}> | undefined;
|
|
794
824
|
}>>;
|
|
795
825
|
errors: (state: Array<{
|
|
@@ -2,7 +2,6 @@ import type { Channel, ChannelWithTeamData, ChannelSearchOpts } from '@mattermos
|
|
|
2
2
|
import type { AccessControlSettings } from '@mattermost/types/config';
|
|
3
3
|
import type { GlobalState } from '@mattermost/types/store';
|
|
4
4
|
export declare const getAccessControlSettings: import("../create_selector").OutputSelector<GlobalState, AccessControlSettings, (res1: AccessControlSettings, res2: any) => AccessControlSettings>;
|
|
5
|
-
export declare function isChannelScopeAccessControlEnabled(state: GlobalState): boolean;
|
|
6
5
|
export declare function getAccessControlPolicy(state: GlobalState, id: string): import("@mattermost/types/access_control").AccessControlPolicy;
|
|
7
6
|
export declare const getChannelIdsForAccessControlPolicy: (state: GlobalState, parentId: string) => string[];
|
|
8
7
|
export declare function makeGetChannelsInAccessControlPolicy(): (b: GlobalState, a: {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// See LICENSE.txt for license information.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.getChannelIdsForAccessControlPolicy = exports.getAccessControlSettings = void 0;
|
|
6
|
-
exports.isChannelScopeAccessControlEnabled = isChannelScopeAccessControlEnabled;
|
|
7
6
|
exports.getAccessControlPolicy = getAccessControlPolicy;
|
|
8
7
|
exports.makeGetChannelsInAccessControlPolicy = makeGetChannelsInAccessControlPolicy;
|
|
9
8
|
exports.searchChannelsInheritsPolicy = searchChannelsInheritsPolicy;
|
|
@@ -19,14 +18,9 @@ exports.getAccessControlSettings = (0, create_selector_1.createSelector)('getAcc
|
|
|
19
18
|
// Otherwise, build from client config (for regular users/channel admins)
|
|
20
19
|
return {
|
|
21
20
|
EnableAttributeBasedAccessControl: config?.EnableAttributeBasedAccessControl === 'true',
|
|
22
|
-
EnableChannelScopeAccessControl: config?.EnableChannelScopeAccessControl === 'true',
|
|
23
21
|
EnableUserManagedAttributes: config?.EnableUserManagedAttributes === 'true',
|
|
24
22
|
};
|
|
25
23
|
});
|
|
26
|
-
function isChannelScopeAccessControlEnabled(state) {
|
|
27
|
-
const settings = (0, exports.getAccessControlSettings)(state);
|
|
28
|
-
return settings?.EnableChannelScopeAccessControl || false;
|
|
29
|
-
}
|
|
30
24
|
function getAccessControlPolicy(state, id) {
|
|
31
25
|
return state.entities.admin.accessControlPolicies[id];
|
|
32
26
|
}
|
|
@@ -6,4 +6,5 @@ export declare function getAgentsStatus(state: GlobalState): {
|
|
|
6
6
|
reason?: string;
|
|
7
7
|
};
|
|
8
8
|
export declare function getAgent(state: GlobalState, agentId: string): Agent | undefined;
|
|
9
|
+
export declare function getDefaultAgent(state: GlobalState): Agent | undefined;
|
|
9
10
|
export declare function getLLMServices(state: GlobalState): LLMService[];
|
|
@@ -5,9 +5,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
5
5
|
exports.getAgents = getAgents;
|
|
6
6
|
exports.getAgentsStatus = getAgentsStatus;
|
|
7
7
|
exports.getAgent = getAgent;
|
|
8
|
+
exports.getDefaultAgent = getDefaultAgent;
|
|
8
9
|
exports.getLLMServices = getLLMServices;
|
|
9
10
|
function getAgents(state) {
|
|
10
|
-
return state.entities.agents?.agents;
|
|
11
|
+
return state.entities.agents?.agents || [];
|
|
11
12
|
}
|
|
12
13
|
function getAgentsStatus(state) {
|
|
13
14
|
return state.entities.agents?.agentsStatus || { available: false };
|
|
@@ -16,6 +17,10 @@ function getAgent(state, agentId) {
|
|
|
16
17
|
const agents = getAgents(state);
|
|
17
18
|
return agents.find((agent) => agent.id === agentId);
|
|
18
19
|
}
|
|
20
|
+
function getDefaultAgent(state) {
|
|
21
|
+
const agents = getAgents(state);
|
|
22
|
+
return agents?.find((agent) => agent.is_default === true);
|
|
23
|
+
}
|
|
19
24
|
function getLLMServices(state) {
|
|
20
25
|
return state.entities.agents?.llmServices || [];
|
|
21
26
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { GlobalState } from '@mattermost/types/store';
|
|
2
|
+
import type { ContentFlaggingChannelRequestIdentifier, ContentFlaggingTeamRequestIdentifier } from 'mattermost-redux/actions/content_flagging';
|
|
2
3
|
export declare const contentFlaggingFeatureEnabled: (state: GlobalState) => boolean;
|
|
3
4
|
export declare const contentFlaggingConfig: (state: GlobalState) => import("@mattermost/types/content_flagging").ContentFlaggingConfig | undefined;
|
|
4
5
|
export declare const contentFlaggingFields: (state: GlobalState) => import("@mattermost/types/properties").NameMappedPropertyFields | undefined;
|
|
5
6
|
export declare const postContentFlaggingValues: (state: GlobalState, postId: string) => import("@mattermost/types/properties").PropertyValue<unknown>[];
|
|
7
|
+
export declare const getFlaggedPost: (state: GlobalState, flaggedPostId: string) => import("@mattermost/types/posts").Post | undefined;
|
|
8
|
+
export declare const getContentFlaggingChannel: (state: GlobalState, { channelId }: ContentFlaggingChannelRequestIdentifier) => import("@mattermost/types/channels").Channel | undefined;
|
|
9
|
+
export declare const getContentFlaggingTeam: (state: GlobalState, { teamId }: ContentFlaggingTeamRequestIdentifier) => import("@mattermost/types/teams").Team | undefined;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
3
|
// See LICENSE.txt for license information.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.postContentFlaggingValues = exports.contentFlaggingFields = exports.contentFlaggingConfig = exports.contentFlaggingFeatureEnabled = void 0;
|
|
5
|
+
exports.getContentFlaggingTeam = exports.getContentFlaggingChannel = exports.getFlaggedPost = exports.postContentFlaggingValues = exports.contentFlaggingFields = exports.contentFlaggingConfig = exports.contentFlaggingFeatureEnabled = void 0;
|
|
6
6
|
const general_1 = require("mattermost-redux/selectors/entities/general");
|
|
7
7
|
const contentFlaggingFeatureEnabled = (state) => {
|
|
8
8
|
const featureFlagEnabled = (0, general_1.getFeatureFlagValue)(state, 'ContentFlagging') === 'true';
|
|
@@ -25,3 +25,30 @@ const postContentFlaggingValues = (state, postId) => {
|
|
|
25
25
|
return values[postId];
|
|
26
26
|
};
|
|
27
27
|
exports.postContentFlaggingValues = postContentFlaggingValues;
|
|
28
|
+
const getFlaggedPost = (state, flaggedPostId) => {
|
|
29
|
+
return state.entities.contentFlagging.flaggedPosts?.[flaggedPostId];
|
|
30
|
+
};
|
|
31
|
+
exports.getFlaggedPost = getFlaggedPost;
|
|
32
|
+
const getContentFlaggingChannel = (state, { channelId }) => {
|
|
33
|
+
// Return channel from the regular channel store if available, else get it from the content flagging store
|
|
34
|
+
if (!channelId) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const channel = state.entities.channels.channels[channelId];
|
|
38
|
+
if (channel) {
|
|
39
|
+
return channel;
|
|
40
|
+
}
|
|
41
|
+
return state.entities.contentFlagging.channels?.[channelId];
|
|
42
|
+
};
|
|
43
|
+
exports.getContentFlaggingChannel = getContentFlaggingChannel;
|
|
44
|
+
const getContentFlaggingTeam = (state, { teamId }) => {
|
|
45
|
+
if (!teamId) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
const team = state.entities.teams.teams[teamId];
|
|
49
|
+
if (team) {
|
|
50
|
+
return team;
|
|
51
|
+
}
|
|
52
|
+
return state.entities.contentFlagging.teams?.[teamId];
|
|
53
|
+
};
|
|
54
|
+
exports.getContentFlaggingTeam = getContentFlaggingTeam;
|
|
@@ -5,6 +5,8 @@ export declare function getFile(state: GlobalState, id: string): FileInfo;
|
|
|
5
5
|
export declare function getFilePublicLink(state: GlobalState): {
|
|
6
6
|
link: string;
|
|
7
7
|
} | undefined;
|
|
8
|
+
export declare function getRejectedFiles(state: GlobalState): Set<string>;
|
|
9
|
+
export declare function isFileRejected(state: GlobalState, fileId: string): boolean;
|
|
8
10
|
export declare function makeGetFileIdsForPost(): (state: GlobalState, postId: string) => string[];
|
|
9
11
|
export declare function makeGetFilesForPost(): (state: GlobalState, postId: string) => FileInfo[];
|
|
10
12
|
export declare function makeGetFilesForEditHistory(): (state: GlobalState, editHistoryPost: Post) => FileInfo[];
|
|
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
5
5
|
exports.getSearchFilesResults = void 0;
|
|
6
6
|
exports.getFile = getFile;
|
|
7
7
|
exports.getFilePublicLink = getFilePublicLink;
|
|
8
|
+
exports.getRejectedFiles = getRejectedFiles;
|
|
9
|
+
exports.isFileRejected = isFileRejected;
|
|
8
10
|
exports.makeGetFileIdsForPost = makeGetFileIdsForPost;
|
|
9
11
|
exports.makeGetFilesForPost = makeGetFilesForPost;
|
|
10
12
|
exports.makeGetFilesForEditHistory = makeGetFilesForEditHistory;
|
|
@@ -23,6 +25,13 @@ function getAllFilesFromSearch(state) {
|
|
|
23
25
|
function getFilePublicLink(state) {
|
|
24
26
|
return state.entities.files.filePublicLink;
|
|
25
27
|
}
|
|
28
|
+
function getRejectedFiles(state) {
|
|
29
|
+
return state.entities.files.rejectedFiles || new Set();
|
|
30
|
+
}
|
|
31
|
+
function isFileRejected(state, fileId) {
|
|
32
|
+
const rejectedFiles = getRejectedFiles(state);
|
|
33
|
+
return rejectedFiles.has(fileId);
|
|
34
|
+
}
|
|
26
35
|
function makeGetFileIdsForPost() {
|
|
27
36
|
return (0, create_selector_1.createSelector)('makeGetFileIdsForPost', (state, postId) => state.entities.files.fileIdsByPostId[postId], (fileIds) => {
|
|
28
37
|
return fileIds || [];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type Comparator = (a: any, b: any) => boolean;
|
|
1
2
|
/**
|
|
2
3
|
* A DataLoader is an object that can be used to batch requests for fetching objects from the server for performance
|
|
3
4
|
* reasons.
|
|
@@ -5,10 +6,12 @@
|
|
|
5
6
|
declare abstract class DataLoader<Identifier, Result = unknown> {
|
|
6
7
|
protected readonly fetchBatch: (identifiers: Identifier[]) => Result;
|
|
7
8
|
private readonly maxBatchSize;
|
|
9
|
+
private readonly comparator?;
|
|
8
10
|
protected readonly pendingIdentifiers: Set<Identifier>;
|
|
9
11
|
constructor(args: {
|
|
10
12
|
fetchBatch: (identifiers: Identifier[]) => Result;
|
|
11
13
|
maxBatchSize: number;
|
|
14
|
+
comparator?: Comparator;
|
|
12
15
|
});
|
|
13
16
|
queue(identifiersToLoad: Identifier[]): void;
|
|
14
17
|
/**
|
|
@@ -61,6 +64,7 @@ export declare class DelayedDataLoader<Identifier> extends DataLoader<Identifier
|
|
|
61
64
|
fetchBatch: (identifiers: Identifier[]) => Promise<unknown>;
|
|
62
65
|
maxBatchSize: number;
|
|
63
66
|
wait: number;
|
|
67
|
+
comparator?: Comparator;
|
|
64
68
|
});
|
|
65
69
|
queue(identifiersToLoad: Identifier[]): void;
|
|
66
70
|
queueAndWait(identifiersToLoad: Identifier[]): Promise<void>;
|
package/lib/utils/data_loader.js
CHANGED
|
@@ -10,17 +10,35 @@ exports.DelayedDataLoader = exports.BackgroundDataLoader = void 0;
|
|
|
10
10
|
class DataLoader {
|
|
11
11
|
fetchBatch;
|
|
12
12
|
maxBatchSize;
|
|
13
|
+
comparator;
|
|
13
14
|
pendingIdentifiers = new Set();
|
|
14
15
|
constructor(args) {
|
|
15
16
|
this.fetchBatch = args.fetchBatch;
|
|
16
17
|
this.maxBatchSize = args.maxBatchSize;
|
|
18
|
+
this.comparator = args.comparator;
|
|
17
19
|
}
|
|
18
20
|
queue(identifiersToLoad) {
|
|
19
21
|
for (const identifier of identifiersToLoad) {
|
|
20
22
|
if (!identifier) {
|
|
21
23
|
continue;
|
|
22
24
|
}
|
|
23
|
-
|
|
25
|
+
// If a custom comparator is provided, manually check for duplicates
|
|
26
|
+
if (this.comparator) {
|
|
27
|
+
let exists = false;
|
|
28
|
+
for (const existing of this.pendingIdentifiers) {
|
|
29
|
+
if (this.comparator(existing, identifier)) {
|
|
30
|
+
exists = true;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (!exists) {
|
|
35
|
+
this.pendingIdentifiers.add(identifier);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// Without a comparator, Set automatically handles uniqueness
|
|
40
|
+
this.pendingIdentifiers.add(identifier);
|
|
41
|
+
}
|
|
24
42
|
}
|
|
25
43
|
}
|
|
26
44
|
/**
|
|
@@ -30,11 +48,11 @@ class DataLoader {
|
|
|
30
48
|
*/
|
|
31
49
|
prepareBatch() {
|
|
32
50
|
let nextBatch;
|
|
33
|
-
// Since we can only fetch a defined number of
|
|
51
|
+
// Since we can only fetch a defined number of identifiers at a time, we need to batch the requests
|
|
34
52
|
if (this.pendingIdentifiers.size >= this.maxBatchSize) {
|
|
35
53
|
nextBatch = [];
|
|
36
54
|
// We use temp buffer here to store up until max buffer size
|
|
37
|
-
// and clear out processed
|
|
55
|
+
// and clear out processed identifiers
|
|
38
56
|
for (const identifier of this.pendingIdentifiers) {
|
|
39
57
|
nextBatch.push(identifier);
|
|
40
58
|
this.pendingIdentifiers.delete(identifier);
|
|
@@ -44,7 +62,7 @@ class DataLoader {
|
|
|
44
62
|
}
|
|
45
63
|
}
|
|
46
64
|
else {
|
|
47
|
-
// If we have less than max buffer size, we can directly fetch the
|
|
65
|
+
// If we have less than max buffer size, we can directly fetch the data
|
|
48
66
|
nextBatch = Array.from(this.pendingIdentifiers);
|
|
49
67
|
this.pendingIdentifiers.clear();
|
|
50
68
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
export
|
|
1
|
+
import { isSystemEmoji, type Emoji } from '@mattermost/types/emojis';
|
|
2
|
+
export { isSystemEmoji };
|
|
3
3
|
export declare function getEmojiImageUrl(emoji: Emoji): string;
|
|
4
4
|
export declare function getEmojiName(emoji: Emoji): string;
|
|
5
5
|
export declare function parseEmojiNamesFromText(text: string): string[];
|
package/lib/utils/emoji_utils.js
CHANGED
|
@@ -2,23 +2,19 @@
|
|
|
2
2
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
3
3
|
// See LICENSE.txt for license information.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.isSystemEmoji =
|
|
5
|
+
exports.isSystemEmoji = void 0;
|
|
6
6
|
exports.getEmojiImageUrl = getEmojiImageUrl;
|
|
7
7
|
exports.getEmojiName = getEmojiName;
|
|
8
8
|
exports.parseEmojiNamesFromText = parseEmojiNamesFromText;
|
|
9
|
+
const emojis_1 = require("@mattermost/types/emojis");
|
|
10
|
+
Object.defineProperty(exports, "isSystemEmoji", { enumerable: true, get: function () { return emojis_1.isSystemEmoji; } });
|
|
9
11
|
const client_1 = require("mattermost-redux/client");
|
|
10
|
-
function isSystemEmoji(emoji) {
|
|
11
|
-
if ('category' in emoji) {
|
|
12
|
-
return emoji.category !== 'custom';
|
|
13
|
-
}
|
|
14
|
-
return !('id' in emoji);
|
|
15
|
-
}
|
|
16
12
|
function getEmojiImageUrl(emoji) {
|
|
17
13
|
// If its the mattermost custom emoji
|
|
18
|
-
if (!isSystemEmoji(emoji) && emoji.id === 'mattermost') {
|
|
14
|
+
if (!(0, emojis_1.isSystemEmoji)(emoji) && emoji.id === 'mattermost') {
|
|
19
15
|
return client_1.Client4.getSystemEmojiImageUrl('mattermost');
|
|
20
16
|
}
|
|
21
|
-
if (isSystemEmoji(emoji)) {
|
|
17
|
+
if ((0, emojis_1.isSystemEmoji)(emoji)) {
|
|
22
18
|
const emojiUnified = emoji?.unified?.toLowerCase() ?? '';
|
|
23
19
|
const filename = emojiUnified || emoji.short_names[0];
|
|
24
20
|
return client_1.Client4.getSystemEmojiImageUrl(filename);
|
|
@@ -26,7 +22,7 @@ function getEmojiImageUrl(emoji) {
|
|
|
26
22
|
return client_1.Client4.getEmojiRoute(emoji.id) + '/image';
|
|
27
23
|
}
|
|
28
24
|
function getEmojiName(emoji) {
|
|
29
|
-
return isSystemEmoji(emoji) ? emoji.short_name : emoji.name;
|
|
25
|
+
return (0, emojis_1.isSystemEmoji)(emoji) ? emoji.short_name : emoji.name;
|
|
30
26
|
}
|
|
31
27
|
function parseEmojiNamesFromText(text) {
|
|
32
28
|
if (!text.includes(':')) {
|
|
@@ -8,7 +8,44 @@ const date_fns_1 = require("date-fns");
|
|
|
8
8
|
const react_intl_1 = require("react-intl");
|
|
9
9
|
// Validation patterns for exact storage format matching
|
|
10
10
|
const DATE_FORMAT_PATTERN = /^\d{4}-\d{2}-\d{2}$/; // YYYY-MM-DD
|
|
11
|
-
const DATETIME_FORMAT_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/; // YYYY-MM-DDTHH:mm:ssZ
|
|
11
|
+
const DATETIME_FORMAT_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})$/; // YYYY-MM-DDTHH:mm:ssZ or with offset
|
|
12
|
+
// Relative pattern: [+-]NNN[dwmHMS]
|
|
13
|
+
const RELATIVE_PATTERN = /^([+-]\d{1,3})([dwmHMS])$/;
|
|
14
|
+
/**
|
|
15
|
+
* Resolves a min_date/max_date bound string to a Date.
|
|
16
|
+
* Handles relative patterns (+2H, +30M, +7d, etc.) and ISO date/datetime strings.
|
|
17
|
+
* Returns null if the value cannot be resolved.
|
|
18
|
+
*/
|
|
19
|
+
function resolveBoundToDate(value) {
|
|
20
|
+
// Named relative words
|
|
21
|
+
if (value === 'today') {
|
|
22
|
+
return (0, date_fns_1.startOfDay)(new Date());
|
|
23
|
+
}
|
|
24
|
+
if (value === 'tomorrow') {
|
|
25
|
+
return (0, date_fns_1.startOfDay)((0, date_fns_1.addDays)(new Date(), 1));
|
|
26
|
+
}
|
|
27
|
+
if (value === 'yesterday') {
|
|
28
|
+
return (0, date_fns_1.startOfDay)((0, date_fns_1.addDays)(new Date(), -1));
|
|
29
|
+
}
|
|
30
|
+
// Dynamic relative patterns: +2H, +30M, +7d, etc.
|
|
31
|
+
const match = value.match(RELATIVE_PATTERN);
|
|
32
|
+
if (match) {
|
|
33
|
+
const amount = parseInt(match[1], 10);
|
|
34
|
+
const unit = match[2];
|
|
35
|
+
const now = new Date();
|
|
36
|
+
switch (unit) {
|
|
37
|
+
case 'd': return (0, date_fns_1.startOfDay)((0, date_fns_1.addDays)(now, amount));
|
|
38
|
+
case 'w': return (0, date_fns_1.startOfDay)((0, date_fns_1.addWeeks)(now, amount));
|
|
39
|
+
case 'm': return (0, date_fns_1.startOfDay)((0, date_fns_1.addMonths)(now, amount));
|
|
40
|
+
case 'H': return (0, date_fns_1.addHours)(now, amount);
|
|
41
|
+
case 'M': return (0, date_fns_1.addMinutes)(now, amount);
|
|
42
|
+
case 'S': return (0, date_fns_1.addSeconds)(now, amount);
|
|
43
|
+
default: return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const parsed = (0, date_fns_1.parseISO)(value);
|
|
47
|
+
return (0, date_fns_1.isValid)(parsed) ? parsed : null;
|
|
48
|
+
}
|
|
12
49
|
/**
|
|
13
50
|
* Validates date/datetime field values for format and range constraints
|
|
14
51
|
*/
|
|
@@ -32,9 +69,28 @@ function validateDateTimeValue(value, elem) {
|
|
|
32
69
|
else if (!DATETIME_FORMAT_PATTERN.test(value)) {
|
|
33
70
|
return (0, react_intl_1.defineMessage)({
|
|
34
71
|
id: 'interactive_dialog.error.bad_datetime_format',
|
|
35
|
-
defaultMessage: 'DateTime field must be in YYYY-MM-DDTHH:mm:ssZ format',
|
|
72
|
+
defaultMessage: 'DateTime field must be in YYYY-MM-DDTHH:mm:ssZ or YYYY-MM-DDTHH:mm:ss+HH:MM format',
|
|
36
73
|
});
|
|
37
74
|
}
|
|
75
|
+
// Range validation against min_date / max_date
|
|
76
|
+
if (elem.min_date) {
|
|
77
|
+
const minDate = resolveBoundToDate(elem.min_date);
|
|
78
|
+
if (minDate && parsedDate < minDate) {
|
|
79
|
+
return (0, react_intl_1.defineMessage)({
|
|
80
|
+
id: 'interactive_dialog.error.before_min_date',
|
|
81
|
+
defaultMessage: 'Selected time is before the minimum allowed date.',
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (elem.max_date) {
|
|
86
|
+
const maxDate = resolveBoundToDate(elem.max_date);
|
|
87
|
+
if (maxDate && parsedDate > maxDate) {
|
|
88
|
+
return (0, react_intl_1.defineMessage)({
|
|
89
|
+
id: 'interactive_dialog.error.after_max_date',
|
|
90
|
+
defaultMessage: 'Selected time is after the maximum allowed date.',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
38
94
|
return null;
|
|
39
95
|
}
|
|
40
96
|
function checkDialogElementForError(elem, value) {
|
package/lib/utils/user_utils.js
CHANGED
|
@@ -81,6 +81,8 @@ function includesAnAdminRole(roles) {
|
|
|
81
81
|
constants_1.General.SYSTEM_USER_MANAGER_ROLE,
|
|
82
82
|
constants_1.General.SYSTEM_READ_ONLY_ADMIN_ROLE,
|
|
83
83
|
constants_1.General.SYSTEM_MANAGER_ROLE,
|
|
84
|
+
constants_1.General.SHARED_CHANNEL_MANAGER_ROLE,
|
|
85
|
+
constants_1.General.SECURE_CONNECTION_MANAGER_ROLE,
|
|
84
86
|
].some((el) => rolesArray.includes(el));
|
|
85
87
|
}
|
|
86
88
|
function isChannelAdmin(roles) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mattermost-redux",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.6.0",
|
|
4
4
|
"description": "Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mattermost"
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"directory": "webapp/platform/mattermost-redux"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@mattermost/client": "11.
|
|
43
|
-
"@mattermost/types": "11.
|
|
42
|
+
"@mattermost/client": "11.6.0",
|
|
43
|
+
"@mattermost/types": "11.6.0",
|
|
44
44
|
"@redux-devtools/extension": "3.3.0",
|
|
45
45
|
"lodash": "^4.17.21",
|
|
46
46
|
"moment-timezone": "^0.5.38",
|