forked from Ivasoft/mattermost-mobile
[Gekidou MM-39729] Websocket Events - Groups (#5930)
Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {fetchChannelStats, fetchMissingSidebarInfo, fetchMyChannelsForTeam, markChannelAsRead, MyChannelsRequest} from '@actions/remote/channel';
|
||||
import {fetchGroupsForTeam} from '@actions/remote/group';
|
||||
import {fetchPostsForChannel, fetchPostsForUnreadChannels} from '@actions/remote/post';
|
||||
import {MyPreferencesRequest, fetchMyPreferences} from '@actions/remote/preference';
|
||||
import {fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
@@ -183,11 +182,6 @@ export const deferredAppEntryActions = async (
|
||||
fetchPostsForUnreadChannels(serverUrl, chData.channels, chData.memberships, initialChannelId);
|
||||
}
|
||||
|
||||
// defer groups for team
|
||||
if (initialTeamId) {
|
||||
fetchGroupsForTeam(serverUrl, initialTeamId, since);
|
||||
}
|
||||
|
||||
// defer fetch channels and unread posts for other teams
|
||||
if (teamData.teams?.length && teamData.memberships?.length) {
|
||||
await fetchTeamsChannelsAndUnreadPosts(serverUrl, since, teamData.teams, teamData.memberships, initialTeamId);
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Model} from '@nozbe/watermelondb';
|
||||
|
||||
import DatabaseManager from '@database/manager';
|
||||
import NetworkManager from '@init/network_manager';
|
||||
import {queryCommonSystemValues} from '@queries/servers/system';
|
||||
import {queryTeamById} from '@queries/servers/team';
|
||||
|
||||
import {forceLogoutIfNecessary} from './session';
|
||||
|
||||
export const fetchGroupsForTeam = async (serverUrl: string, teamId: string, since: number) => {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl]?.database;
|
||||
if (!database) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
|
||||
let client;
|
||||
try {
|
||||
client = NetworkManager.getClient(serverUrl);
|
||||
} catch (error) {
|
||||
return {error};
|
||||
}
|
||||
|
||||
try {
|
||||
const system = await queryCommonSystemValues(database);
|
||||
const team = await queryTeamById(database, teamId);
|
||||
const hasLicense = system.license.IsLicensed === 'true' && system.license.LDAPGroups === 'true';
|
||||
|
||||
if (hasLicense && team) {
|
||||
const groups: Group[] = [];
|
||||
const groupsChannels: GroupChannelRelation[] = [];
|
||||
const groupsTeams: GroupTeamRelation[] = [];
|
||||
const groupMemberships: GroupMembership[] = [];
|
||||
if (team.isGroupConstrained) {
|
||||
const [groupsAssociatedToChannelsInTeam, groupsAssociatedToTeam]: [{groups: Record<string, Group[]>}, {groups: Group[]; total_group_count: number}] = await Promise.all([
|
||||
client.getAllGroupsAssociatedToChannelsInTeam(teamId, true),
|
||||
client.getAllGroupsAssociatedToTeam(teamId, true),
|
||||
]);
|
||||
|
||||
if (groupsAssociatedToChannelsInTeam.groups) {
|
||||
const keys = Object.keys(groupsAssociatedToChannelsInTeam.groups);
|
||||
for (const key of keys) {
|
||||
for (const group of groupsAssociatedToChannelsInTeam.groups[key]) {
|
||||
groups.push(group);
|
||||
groupsChannels.push({
|
||||
channel_id: key,
|
||||
group_id: group.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (groupsAssociatedToTeam.groups) {
|
||||
for (const group of groupsAssociatedToTeam.groups) {
|
||||
groups.push(group);
|
||||
groupsTeams.push({group_id: group.id, team_id: teamId});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const [groupsAssociatedToChannelsInTeam, allGroups]: [{groups: Record<string, Group[]>}, Group[]] = await Promise.all([
|
||||
client.getAllGroupsAssociatedToChannelsInTeam(teamId, true),
|
||||
client.getGroups(true, 0, 0, since),
|
||||
]);
|
||||
|
||||
if (groupsAssociatedToChannelsInTeam.groups) {
|
||||
const keys = Object.keys(groupsAssociatedToChannelsInTeam.groups);
|
||||
for (const key of keys) {
|
||||
for (const group of groupsAssociatedToChannelsInTeam.groups[key]) {
|
||||
groups.push(group);
|
||||
groupsChannels.push({
|
||||
channel_id: key,
|
||||
group_id: group.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allGroups?.length) {
|
||||
groups.push(...allGroups);
|
||||
}
|
||||
}
|
||||
|
||||
const userGroups = await client.getGroupsByUserId(system.currentUserId);
|
||||
if (userGroups) {
|
||||
for (const mg of userGroups) {
|
||||
groupMemberships.push({group_id: mg.id, user_id: system.currentUserId});
|
||||
groups.push(mg);
|
||||
}
|
||||
}
|
||||
|
||||
const models: Model[] = [];
|
||||
const {operator} = DatabaseManager.serverDatabases[serverUrl];
|
||||
if (groups.length) {
|
||||
const gModels = await operator.handleGroup({groups, prepareRecordsOnly: true});
|
||||
if (gModels.length) {
|
||||
models.push(...gModels);
|
||||
}
|
||||
}
|
||||
|
||||
if (groupsChannels.length) {
|
||||
const gcModels = await operator.handleGroupsChannel({groupsChannels, prepareRecordsOnly: true});
|
||||
if (gcModels.length) {
|
||||
models.push(...gcModels);
|
||||
}
|
||||
}
|
||||
|
||||
if (groupsTeams.length) {
|
||||
const gtModels = await operator.handleGroupsTeam({groupsTeams, prepareRecordsOnly: true});
|
||||
if (gtModels.length) {
|
||||
models.push(...gtModels);
|
||||
}
|
||||
}
|
||||
|
||||
if (groupMemberships.length) {
|
||||
const gmModels = await operator.handleGroupMembership({groupMemberships, prepareRecordsOnly: true});
|
||||
if (gmModels.length) {
|
||||
models.push(...gmModels);
|
||||
}
|
||||
}
|
||||
|
||||
if (models.length) {
|
||||
await operator.batchRecords(models.flat());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
forceLogoutIfNecessary(serverUrl, error as ClientErrorProps);
|
||||
return {error};
|
||||
}
|
||||
};
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
import {fetchMissingSidebarInfo, switchToChannelById} from '@actions/remote/channel';
|
||||
import {AppEntryData, AppEntryError, fetchAppEntryData} from '@actions/remote/entry/common';
|
||||
import {fetchGroupsForTeam} from '@actions/remote/group';
|
||||
import {fetchPostsForUnreadChannels, fetchPostsSince} from '@actions/remote/post';
|
||||
import {fetchRoles} from '@actions/remote/role';
|
||||
import {fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
@@ -179,10 +178,6 @@ async function doReconnect(serverUrl: string) {
|
||||
}
|
||||
}
|
||||
|
||||
if (initialTeamId) {
|
||||
fetchGroupsForTeam(serverUrl, initialTeamId, lastDisconnectedAt);
|
||||
}
|
||||
|
||||
// defer fetch channels and unread posts for other teams
|
||||
if (teamData.teams?.length && teamData.memberships?.length) {
|
||||
await fetchTeamsChannelsAndUnreadPosts(serverUrl, lastDisconnectedAt, teamData.teams, teamData.memberships, initialTeamId);
|
||||
@@ -335,11 +330,6 @@ export async function handleEvent(serverUrl: string, msg: WebSocketMessage) {
|
||||
case WebsocketEvents.OPEN_DIALOG:
|
||||
break;
|
||||
|
||||
// return dispatch(handleOpenDialogEvent(msg));
|
||||
case WebsocketEvents.RECEIVED_GROUP:
|
||||
break;
|
||||
|
||||
// return dispatch(handleGroupUpdatedEvent(msg));
|
||||
case WebsocketEvents.THREAD_UPDATED:
|
||||
break;
|
||||
|
||||
|
||||
@@ -20,11 +20,9 @@ import {useTheme} from '@context/theme';
|
||||
import UserModel from '@database/models/server/user';
|
||||
import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
|
||||
import {bottomSheet, dismissBottomSheet, showModal} from '@screens/navigation';
|
||||
import {displayUsername, getUserMentionKeys, getUsersByUsername} from '@utils/user';
|
||||
import {displayUsername, getUsersByUsername} from '@utils/user';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type UserModelType from '@typings/database/models/servers/user';
|
||||
@@ -33,19 +31,17 @@ type AtMentionProps = {
|
||||
currentUserId: string;
|
||||
database: Database;
|
||||
disableAtChannelMentionHighlight?: boolean;
|
||||
groups: GroupModel[];
|
||||
isSearchResult?: boolean;
|
||||
mentionKeys?: Array<{key: string }>;
|
||||
mentionName: string;
|
||||
mentionStyle: TextStyle;
|
||||
myGroups: GroupMembershipModel[];
|
||||
onPostPress?: (e: GestureResponderEvent) => void;
|
||||
teammateNameDisplay: string;
|
||||
textStyle?: StyleProp<TextStyle>;
|
||||
users: UserModelType[];
|
||||
}
|
||||
|
||||
const {SERVER: {GROUP, GROUP_MEMBERSHIP, PREFERENCE, SYSTEM, USER}} = MM_TABLES;
|
||||
const {SERVER: {PREFERENCE, SYSTEM, USER}} = MM_TABLES;
|
||||
|
||||
const style = StyleSheet.create({
|
||||
bottomSheet: {
|
||||
@@ -57,12 +53,10 @@ const AtMention = ({
|
||||
currentUserId,
|
||||
database,
|
||||
disableAtChannelMentionHighlight,
|
||||
groups,
|
||||
isSearchResult,
|
||||
mentionName,
|
||||
mentionKeys,
|
||||
mentionStyle,
|
||||
myGroups,
|
||||
onPostPress,
|
||||
teammateNameDisplay,
|
||||
textStyle,
|
||||
@@ -99,13 +93,9 @@ const AtMention = ({
|
||||
if (user.id !== currentUserId) {
|
||||
return [];
|
||||
}
|
||||
return getUserMentionKeys(user, groups, myGroups);
|
||||
}, [currentUserId, groups, mentionKeys, myGroups, user]);
|
||||
|
||||
const getGroupFromMentionName = () => {
|
||||
const mentionNameTrimmed = mentionName.toLowerCase().replace(/[._-]*$/, '');
|
||||
return groups.find((g) => g.name === mentionNameTrimmed);
|
||||
};
|
||||
return user.mentionKeys;
|
||||
}, [currentUserId, mentionKeys, user]);
|
||||
|
||||
const goToUserProfile = useCallback(() => {
|
||||
const screen = 'UserProfile';
|
||||
@@ -199,24 +189,16 @@ const AtMention = ({
|
||||
isMention = true;
|
||||
canPress = true;
|
||||
} else {
|
||||
const group = getGroupFromMentionName();
|
||||
if (group?.allowReference) {
|
||||
highlighted = userMentionKeys.some((item) => item.key === `@${group.name}`);
|
||||
isMention = true;
|
||||
mention = group.name;
|
||||
suffix = mentionName.substring(group.name.length);
|
||||
} else {
|
||||
const pattern = new RegExp(/\b(all|channel|here)(?:\.\B|_\b|\b)/, 'i');
|
||||
const mentionMatch = pattern.exec(mentionName);
|
||||
const pattern = new RegExp(/\b(all|channel|here)(?:\.\B|_\b|\b)/, 'i');
|
||||
const mentionMatch = pattern.exec(mentionName);
|
||||
|
||||
if (mentionMatch && !disableAtChannelMentionHighlight) {
|
||||
mention = mentionMatch.length > 1 ? mentionMatch[1] : mentionMatch[0];
|
||||
suffix = mentionName.replace(mention, '');
|
||||
isMention = true;
|
||||
highlighted = true;
|
||||
} else {
|
||||
mention = mentionName;
|
||||
}
|
||||
if (mentionMatch && !disableAtChannelMentionHighlight) {
|
||||
mention = mentionMatch.length > 1 ? mentionMatch[1] : mentionMatch[0];
|
||||
suffix = mentionName.replace(mention, '');
|
||||
isMention = true;
|
||||
highlighted = true;
|
||||
} else {
|
||||
mention = mentionName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,8 +258,6 @@ const withAtMention = withObservables(['mentionName'], ({database, mentionName}:
|
||||
|
||||
return {
|
||||
currentUserId,
|
||||
groups: database.get(GROUP).query(Q.where('delete_at', Q.eq(0))).observe(),
|
||||
myGroups: database.get(GROUP_MEMBERSHIP).query().observe(),
|
||||
teammateNameDisplay,
|
||||
users: database.get(USER).query(
|
||||
Q.where('username', Q.like(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Q} from '@nozbe/watermelondb';
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {combineLatest, of as of$, from as from$} from 'rxjs';
|
||||
@@ -18,11 +17,10 @@ import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type ChannelInfoModel from '@typings/database/models/servers/channel_info';
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
const {SERVER: {SYSTEM, USER, CHANNEL, GROUP, GROUPS_TEAM, GROUPS_CHANNEL, CUSTOM_EMOJI}} = MM_TABLES;
|
||||
const {SERVER: {SYSTEM, USER, CHANNEL, CUSTOM_EMOJI}} = MM_TABLES;
|
||||
|
||||
type OwnProps = {
|
||||
rootId: string;
|
||||
@@ -75,27 +73,6 @@ const enhanced = withObservables([], (ownProps: WithDatabaseArgs & OwnProps) =>
|
||||
}),
|
||||
);
|
||||
|
||||
const license = database.get<SystemModel>(SYSTEM).findAndObserve(SYSTEM_IDENTIFIERS.LICENSE).pipe(
|
||||
switchMap(({value}) => of$(value as ClientLicense)),
|
||||
);
|
||||
|
||||
const useGroupMentions = combineLatest([channel, currentUser, license]).pipe(
|
||||
switchMap(([c, u, l]) => {
|
||||
if (!c || l?.IsLicensed !== 'true') {
|
||||
return of$(false);
|
||||
}
|
||||
|
||||
return from$(hasPermissionForChannel(c, u, Permissions.USE_GROUP_MENTIONS, true));
|
||||
}),
|
||||
);
|
||||
|
||||
const groupsWithAllowReference = channel.pipe(switchMap(
|
||||
(c) => database.get<GroupModel>(GROUP).query(
|
||||
Q.experimentalJoinTables([GROUPS_TEAM, GROUPS_CHANNEL]),
|
||||
Q.or(Q.on(GROUPS_TEAM, 'team_id', c.teamId), Q.on(GROUPS_CHANNEL, 'channel_id', c.id)),
|
||||
).observeWithColumns(['name'])),
|
||||
);
|
||||
|
||||
const channelInfo = channel.pipe(switchMap((c) => c.info.observe()));
|
||||
const membersCount = channelInfo.pipe(
|
||||
switchMap((i: ChannelInfoModel) => of$(i.memberCount)),
|
||||
@@ -111,8 +88,6 @@ const enhanced = withObservables([], (ownProps: WithDatabaseArgs & OwnProps) =>
|
||||
membersCount,
|
||||
userIsOutOfOffice,
|
||||
useChannelMentions,
|
||||
useGroupMentions,
|
||||
groupsWithAllowReference,
|
||||
customEmojis,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {DeviceEventEmitter} from 'react-native';
|
||||
|
||||
import {getChannelMemberCountsByGroup, getChannelTimezones} from '@actions/remote/channel';
|
||||
import {getChannelTimezones} from '@actions/remote/channel';
|
||||
import {executeCommand, handleGotoLocation} from '@actions/remote/command';
|
||||
import {createPost} from '@actions/remote/post';
|
||||
import {handleReactionToLatestPost} from '@actions/remote/reactions';
|
||||
@@ -22,7 +22,6 @@ import {confirmOutOfOfficeDisabled} from '@utils/user';
|
||||
import DraftInput from '../draft_input';
|
||||
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
|
||||
type Props = {
|
||||
testID?: string;
|
||||
@@ -38,8 +37,6 @@ type Props = {
|
||||
membersCount?: number;
|
||||
useChannelMentions: boolean;
|
||||
userIsOutOfOffice: boolean;
|
||||
useGroupMentions: boolean;
|
||||
groupsWithAllowReference: GroupModel[];
|
||||
customEmojis: CustomEmojiModel[];
|
||||
|
||||
// DRAFT Handler
|
||||
@@ -68,8 +65,6 @@ export default function SendHandler({
|
||||
userIsOutOfOffice,
|
||||
customEmojis,
|
||||
value,
|
||||
useGroupMentions,
|
||||
groupsWithAllowReference,
|
||||
clearDraft,
|
||||
updateValue,
|
||||
addFiles,
|
||||
@@ -82,7 +77,6 @@ export default function SendHandler({
|
||||
|
||||
const [channelTimezoneCount, setChannelTimezoneCount] = useState(0);
|
||||
const [sendingMessage, setSendingMessage] = useState(false);
|
||||
const [channelMemberCountsByGroup, setChannelMemberCountsByGroup] = useState<ChannelMemberCountByGroup[]>([]);
|
||||
|
||||
const canSend = useCallback(() => {
|
||||
if (sendingMessage) {
|
||||
@@ -134,15 +128,6 @@ export default function SendHandler({
|
||||
DraftUtils.alertChannelWideMention(intl, notifyAllMessage, doSubmitMessage, cancel);
|
||||
}, [intl, isTimezoneEnabled, channelTimezoneCount, doSubmitMessage]);
|
||||
|
||||
const showSendToGroupsAlert = useCallback((groupMentions: string[], memberNotifyCount: number, calculatedChannelTimezoneCount: number) => {
|
||||
const notifyAllMessage = DraftUtils.buildGroupMentionsMessage(intl, groupMentions, memberNotifyCount, calculatedChannelTimezoneCount);
|
||||
const cancel = () => {
|
||||
setSendingMessage(false);
|
||||
};
|
||||
|
||||
DraftUtils.alertSendToGroups(intl, notifyAllMessage, doSubmitMessage, cancel);
|
||||
}, [intl, doSubmitMessage]);
|
||||
|
||||
const sendCommand = useCallback(async () => {
|
||||
const status = DraftUtils.getStatusFromSlashCommand(value);
|
||||
if (userIsOutOfOffice && status) {
|
||||
@@ -182,40 +167,23 @@ export default function SendHandler({
|
||||
|
||||
const sendMessage = useCallback(() => {
|
||||
const notificationsToChannel = enableConfirmNotificationsToChannel && useChannelMentions;
|
||||
const notificationsToGroups = enableConfirmNotificationsToChannel && useGroupMentions;
|
||||
const toAllOrChannel = DraftUtils.textContainsAtAllAtChannel(value);
|
||||
const toHere = DraftUtils.textContainsAtHere(value);
|
||||
const groupMentions = (!toAllOrChannel && !toHere && notificationsToGroups) ? DraftUtils.groupsMentionedInText(groupsWithAllowReference, value) : [];
|
||||
|
||||
if (value.indexOf('/') === 0) {
|
||||
sendCommand();
|
||||
} else if (notificationsToChannel && membersCount > NOTIFY_ALL_MEMBERS && (toAllOrChannel || toHere)) {
|
||||
showSendToAllOrChannelOrHereAlert(membersCount, toHere && !toAllOrChannel);
|
||||
} else if (groupMentions.length > 0) {
|
||||
const {
|
||||
groupMentionsSet,
|
||||
memberNotifyCount,
|
||||
channelTimezoneCount: calculatedChannelTimezoneCount,
|
||||
} = DraftUtils.mapGroupMentions(channelMemberCountsByGroup, groupMentions);
|
||||
if (memberNotifyCount > 0) {
|
||||
showSendToGroupsAlert(Array.from(groupMentionsSet), memberNotifyCount, calculatedChannelTimezoneCount);
|
||||
} else {
|
||||
doSubmitMessage();
|
||||
}
|
||||
} else {
|
||||
doSubmitMessage();
|
||||
}
|
||||
}, [
|
||||
enableConfirmNotificationsToChannel,
|
||||
useChannelMentions,
|
||||
useGroupMentions,
|
||||
value,
|
||||
groupsWithAllowReference,
|
||||
channelTimezoneCount,
|
||||
channelMemberCountsByGroup,
|
||||
sendCommand,
|
||||
showSendToAllOrChannelOrHereAlert,
|
||||
showSendToGroupsAlert,
|
||||
doSubmitMessage,
|
||||
]);
|
||||
|
||||
@@ -248,21 +216,6 @@ export default function SendHandler({
|
||||
}
|
||||
}), [canSend, value, handleReaction, files, sendMessage, customEmojis]);
|
||||
|
||||
useEffect(() => {
|
||||
if (useGroupMentions) {
|
||||
getChannelMemberCountsByGroup(serverUrl, channelId, isTimezoneEnabled).then((resp) => {
|
||||
if (resp.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
const received = resp.channelMemberCountsByGroup || [];
|
||||
if (received.length || channelMemberCountsByGroup.length) {
|
||||
setChannelMemberCountsByGroup(received);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [useGroupMentions, channelId, isTimezoneEnabled, channelMemberCountsByGroup.length]);
|
||||
|
||||
useEffect(() => {
|
||||
getChannelTimezones(serverUrl, channelId).then(({channelTimezones}) => {
|
||||
setChannelTimezoneCount(channelTimezones?.length || 0);
|
||||
|
||||
@@ -3,34 +3,24 @@
|
||||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {from as from$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import {queryGroupForPosts} from '@helpers/database/groups';
|
||||
|
||||
import Message from './message';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
const {SERVER: {SYSTEM, USER}} = MM_TABLES;
|
||||
|
||||
type MessageInputArgs = {
|
||||
post: PostModel;
|
||||
}
|
||||
|
||||
const withMessageInput = withObservables(['post'], ({database, post}: WithDatabaseArgs & MessageInputArgs) => {
|
||||
const withMessageInput = withObservables([], ({database}: WithDatabaseArgs) => {
|
||||
const currentUser = database.get<SystemModel>(SYSTEM).findAndObserve(SYSTEM_IDENTIFIERS.CURRENT_USER_ID).pipe(
|
||||
switchMap(({value}) => database.get<UserModel>(USER).findAndObserve(value)),
|
||||
);
|
||||
const groupsForPosts = from$(queryGroupForPosts(post));
|
||||
|
||||
return {
|
||||
currentUser,
|
||||
groupsForPosts,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -9,18 +9,15 @@ import Markdown from '@components/markdown';
|
||||
import {SEARCH} from '@constants/screens';
|
||||
import {useShowMoreAnimatedStyle} from '@hooks/show_more';
|
||||
import {getMarkdownTextStyles, getMarkdownBlockStyles} from '@utils/markdown';
|
||||
import {getMentionKeysForPost} from '@utils/post';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import ShowMoreButton from './show_more_button';
|
||||
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type MessageProps = {
|
||||
currentUser: UserModel;
|
||||
groupsForPosts: GroupModel[];
|
||||
highlight: boolean;
|
||||
isEdited: boolean;
|
||||
isPendingOrFailed: boolean;
|
||||
@@ -52,7 +49,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
};
|
||||
});
|
||||
|
||||
const Message = ({currentUser, groupsForPosts, highlight, isEdited, isPendingOrFailed, isReplyPost, location, post, theme}: MessageProps) => {
|
||||
const Message = ({currentUser, highlight, isEdited, isPendingOrFailed, isReplyPost, location, post, theme}: MessageProps) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [height, setHeight] = useState<number|undefined>();
|
||||
const dimensions = useWindowDimensions();
|
||||
@@ -61,9 +58,10 @@ const Message = ({currentUser, groupsForPosts, highlight, isEdited, isPendingOrF
|
||||
const style = getStyleSheet(theme);
|
||||
const blockStyles = getMarkdownBlockStyles(theme);
|
||||
const textStyles = getMarkdownTextStyles(theme);
|
||||
|
||||
const mentionKeys = useMemo(() => {
|
||||
return getMentionKeysForPost(currentUser, post, groupsForPosts);
|
||||
}, [currentUser, post.message, groupsForPosts]);
|
||||
return currentUser.mentionKeys;
|
||||
}, [currentUser]);
|
||||
|
||||
const onLayout = useCallback((event: LayoutChangeEvent) => setHeight(event.nativeEvent.layout.height), []);
|
||||
const onPress = () => setOpen(!open);
|
||||
|
||||
@@ -18,10 +18,6 @@ export const MM_TABLES = {
|
||||
CUSTOM_EMOJI: 'CustomEmoji',
|
||||
DRAFT: 'Draft',
|
||||
FILE: 'File',
|
||||
GROUP: 'Group',
|
||||
GROUPS_CHANNEL: 'GroupsChannel',
|
||||
GROUPS_TEAM: 'GroupsTeam',
|
||||
GROUP_MEMBERSHIP: 'GroupMembership',
|
||||
MY_CHANNEL: 'MyChannel',
|
||||
MY_CHANNEL_SETTINGS: 'MyChannelSettings',
|
||||
MY_TEAM: 'MyTeam',
|
||||
|
||||
@@ -44,7 +44,6 @@ const WebsocketEvents = {
|
||||
OPEN_DIALOG: 'open_dialog',
|
||||
INCREASE_POST_VISIBILITY_BY_ONE: 'increase_post_visibility_by_one',
|
||||
MEMBERROLE_UPDATED: 'memberrole_updated',
|
||||
RECEIVED_GROUP: 'received_group',
|
||||
THREAD_UPDATED: 'thread_updated',
|
||||
THREAD_FOLLOW_CHANGED: 'thread_follow_changed',
|
||||
THREAD_READ_CHANGED: 'thread_read_changed',
|
||||
|
||||
@@ -12,7 +12,7 @@ import AppDatabaseMigrations from '@database/migration/app';
|
||||
import ServerDatabaseMigrations from '@database/migration/server';
|
||||
import {InfoModel, GlobalModel, ServersModel} from '@database/models/app';
|
||||
import {CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
GroupModel, GroupMembershipModel, GroupsChannelModel, GroupsTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
TermsOfServiceModel, UserModel,
|
||||
@@ -48,7 +48,7 @@ class DatabaseManager {
|
||||
this.appModels = [InfoModel, GlobalModel, ServersModel];
|
||||
this.serverModels = [
|
||||
CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
GroupModel, GroupMembershipModel, GroupsChannelModel, GroupsTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
TermsOfServiceModel, UserModel,
|
||||
|
||||
@@ -13,7 +13,7 @@ import AppDatabaseMigrations from '@database/migration/app';
|
||||
import ServerDatabaseMigrations from '@database/migration/server';
|
||||
import {InfoModel, GlobalModel, ServersModel} from '@database/models/app';
|
||||
import {CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
GroupModel, GroupMembershipModel, GroupsChannelModel, GroupsTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
TermsOfServiceModel, UserModel,
|
||||
@@ -43,7 +43,7 @@ class DatabaseManager {
|
||||
this.appModels = [InfoModel, GlobalModel, ServersModel];
|
||||
this.serverModels = [
|
||||
CategoryModel, CategoryChannelModel, ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel,
|
||||
GroupModel, GroupMembershipModel, GroupsChannelModel, GroupsTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
MyChannelModel, MyChannelSettingsModel, MyTeamModel,
|
||||
PostModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel,
|
||||
SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel,
|
||||
TermsOfServiceModel, UserModel,
|
||||
|
||||
@@ -10,7 +10,6 @@ import {MM_TABLES} from '@constants/database';
|
||||
import type ChannelInfoModel from '@typings/database/models/servers/channel_info';
|
||||
import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership';
|
||||
import type DraftModel from '@typings/database/models/servers/draft';
|
||||
import type GroupsChannelModel from '@typings/database/models/servers/groups_channel';
|
||||
import type MyChannelModel from '@typings/database/models/servers/my_channel';
|
||||
import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
@@ -24,7 +23,6 @@ const {
|
||||
CHANNEL_INFO,
|
||||
CHANNEL_MEMBERSHIP,
|
||||
DRAFT,
|
||||
GROUPS_CHANNEL,
|
||||
MY_CHANNEL,
|
||||
MY_CHANNEL_SETTINGS,
|
||||
POSTS_IN_CHANNEL,
|
||||
@@ -52,9 +50,6 @@ export default class ChannelModel extends Model {
|
||||
/** A CHANNEL can be associated with multiple DRAFT (relationship is 1:N) */
|
||||
[DRAFT]: {type: 'has_many', foreignKey: 'channel_id'},
|
||||
|
||||
/** A CHANNEL can be associated with multiple GROUPS_CHANNEL (relationship is 1:N) */
|
||||
[GROUPS_CHANNEL]: {type: 'has_many', foreignKey: 'channel_id'},
|
||||
|
||||
/** A CHANNEL can be associated with multiple POSTS_IN_CHANNEL (relationship is 1:N) */
|
||||
[POSTS_IN_CHANNEL]: {type: 'has_many', foreignKey: 'channel_id'},
|
||||
|
||||
@@ -110,9 +105,6 @@ export default class ChannelModel extends Model {
|
||||
/** drafts : All drafts for this channel */
|
||||
@children(DRAFT) drafts!: DraftModel[];
|
||||
|
||||
/** groupsChannel : Every group contained in this channel */
|
||||
@children(GROUPS_CHANNEL) groupsChannel!: GroupsChannelModel[];
|
||||
|
||||
/** posts : All posts made in that channel */
|
||||
@children(POST) posts!: PostModel[];
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {children, field} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type GroupsChannelModel from '@typings/database/models/servers/groups_channel';
|
||||
import type GroupsTeamModel from '@typings/database/models/servers/groups_team';
|
||||
|
||||
const {GROUP, GROUPS_CHANNEL, GROUPS_TEAM, GROUP_MEMBERSHIP} = MM_TABLES.SERVER;
|
||||
|
||||
/**
|
||||
* The Group model unifies/assembles users, teams and channels based on a common ground. For example, a group can be
|
||||
* all users who are in the mobile team. If one needs to send that group a message, then s/he can mention the group's
|
||||
* name in the message. (e.g @mobile_team)
|
||||
*/
|
||||
export default class GroupModel extends Model {
|
||||
/** table (name) : Group */
|
||||
static table = GROUP;
|
||||
|
||||
/** associations : Describes every relationship to this table. */
|
||||
static associations: Associations = {
|
||||
|
||||
/** A GROUP has a 1:N relationship with GROUPS_CHANNEL */
|
||||
[GROUPS_CHANNEL]: {type: 'has_many', foreignKey: 'group_id'},
|
||||
|
||||
/** A GROUP has a 1:N relationship with GROUPS_TEAM */
|
||||
[GROUPS_TEAM]: {type: 'has_many', foreignKey: 'group_id'},
|
||||
|
||||
/** A GROUP has a 1:N relationship with GROUP_MEMBERSHIP */
|
||||
[GROUP_MEMBERSHIP]: {type: 'has_many', foreignKey: 'group_id'},
|
||||
};
|
||||
|
||||
/** allow_reference : Determins if the group can be referenced in mentions */
|
||||
@field('allow_reference') allowReference!: boolean;
|
||||
|
||||
/** delete_at : When the group was deleted */
|
||||
@field('delete_at') deleteAt!: number;
|
||||
|
||||
/** display_name : The display name for the group */
|
||||
@field('display_name') displayName!: string;
|
||||
|
||||
/** name : The name of the group */
|
||||
@field('name') name!: string;
|
||||
|
||||
/** groupsChannel : All the related children records from GroupsChannel */
|
||||
@children(GROUPS_CHANNEL) groupsChannel!: GroupsChannelModel[];
|
||||
|
||||
/** groupsTeam : All the related children records from GroupsTeam */
|
||||
@children(GROUPS_TEAM) groupsTeam!: GroupsTeamModel[];
|
||||
|
||||
/** groupMemberships : All the related children records from GroupMembership */
|
||||
@children(GROUP_MEMBERSHIP) groupMemberships!: GroupMembershipModel[];
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Relation} from '@nozbe/watermelondb';
|
||||
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
const {GROUP, GROUP_MEMBERSHIP, USER} = MM_TABLES.SERVER;
|
||||
|
||||
/**
|
||||
* The GroupMembership model represents the 'association table' where many groups have users and many users are in
|
||||
* groups (relationship type N:N)
|
||||
*/
|
||||
export default class GroupMembershipModel extends Model {
|
||||
/** table (name) : GroupMembership */
|
||||
static table = GROUP_MEMBERSHIP;
|
||||
|
||||
/** associations : Describes every relationship to this table */
|
||||
static associations: Associations = {
|
||||
|
||||
/** A GROUP can have multiple users in it */
|
||||
[GROUP]: {type: 'belongs_to', key: 'group_id'},
|
||||
|
||||
/** A USER can be part of multiple groups */
|
||||
[USER]: {type: 'belongs_to', key: 'user_id'},
|
||||
};
|
||||
|
||||
/* group_id: The foreign key to the related Group record*/
|
||||
@field('group_id') groupId!: string;
|
||||
|
||||
/* user_id: The foreign key to the related User record*/
|
||||
@field('user_id') userId!: string;
|
||||
|
||||
/** group : The related group this user belongs to */
|
||||
@immutableRelation(GROUP, 'group_id') group!: Relation<GroupModel>;
|
||||
|
||||
/** user : The related user in the group */
|
||||
@immutableRelation(USER, 'user_id') user!: Relation<UserModel>;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Relation} from '@nozbe/watermelondb';
|
||||
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
|
||||
const {GROUP, GROUPS_CHANNEL, CHANNEL} = MM_TABLES.SERVER;
|
||||
|
||||
/**
|
||||
* The GroupsChannel links the Channel model with the Group model
|
||||
*/
|
||||
export default class GroupsChannelModel extends Model {
|
||||
/** table (name) : GroupsChannel */
|
||||
static table = GROUPS_CHANNEL;
|
||||
|
||||
/** associations : Describes every relationship to this table. */
|
||||
static associations: Associations = {
|
||||
|
||||
/** A GROUP can be associated with multiple GROUPS_CHANNEL (relationship is 1:N) */
|
||||
[GROUP]: {type: 'belongs_to', key: 'group_id'},
|
||||
|
||||
/** A CHANNEL can be associated with multiple GROUPS_CHANNEL (relationship is 1:N) */
|
||||
[CHANNEL]: {type: 'belongs_to', key: 'channel_id'},
|
||||
};
|
||||
|
||||
/** channel_id : The foreign key of the related CHANNEL model */
|
||||
@field('channel_id') channelId!: string;
|
||||
|
||||
/** group_id : The foreign key of the related GROUP model */
|
||||
@field('group_id') groupId!: string;
|
||||
|
||||
/** channel : The related record to the parent Channel model */
|
||||
@immutableRelation(CHANNEL, 'channel_id') channel!: Relation<ChannelModel>;
|
||||
|
||||
/** group : The related record to the parent Group model */
|
||||
@immutableRelation(GROUP, 'group_id') group!: Relation<GroupModel>;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Relation} from '@nozbe/watermelondb';
|
||||
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type TeamModel from '@typings/database/models/servers/team';
|
||||
|
||||
const {GROUP, GROUPS_TEAM, TEAM} = MM_TABLES.SERVER;
|
||||
|
||||
/**
|
||||
* The GroupsTeam links the Team model with the Group model
|
||||
*/
|
||||
export default class GroupsTeamModel extends Model {
|
||||
/** table (name) : GroupsTeam */
|
||||
static table = GROUPS_TEAM;
|
||||
|
||||
/** associations : Describes every relationship to this table. */
|
||||
static associations: Associations = {
|
||||
|
||||
/** GroupsTeam can belong to only one Group */
|
||||
[GROUP]: {type: 'belongs_to', key: 'group_id'},
|
||||
|
||||
/** GroupsTeam can belong to only one Team */
|
||||
[TEAM]: {type: 'belongs_to', key: 'team_id'},
|
||||
};
|
||||
|
||||
/** group_id : The foreign key to the related Group record */
|
||||
@field('group_id') groupId!: string;
|
||||
|
||||
/** team_id : The foreign key to the related Team record */
|
||||
@field('team_id') teamId!: string;
|
||||
|
||||
/** team : The related record to the parent Team model */
|
||||
@immutableRelation(TEAM, 'team_id') team!: Relation<TeamModel>;
|
||||
|
||||
/** group : The related record to the parent Team model */
|
||||
@immutableRelation(GROUP, 'group_id') group!: Relation<GroupModel>;
|
||||
}
|
||||
@@ -9,10 +9,6 @@ export {default as ChannelModel} from './channel';
|
||||
export {default as CustomEmojiModel} from './custom_emoji';
|
||||
export {default as DraftModel} from './draft';
|
||||
export {default as FileModel} from './file';
|
||||
export {default as GroupMembershipModel} from './group_membership';
|
||||
export {default as GroupModel} from './group';
|
||||
export {default as GroupsChannelModel} from './groups_channel';
|
||||
export {default as GroupsTeamModel} from './groups_team';
|
||||
export {default as MyChannelModel} from './my_channel';
|
||||
export {default as MyChannelSettingsModel} from './my_channel_settings';
|
||||
export {default as MyTeamModel} from './my_team';
|
||||
|
||||
@@ -8,7 +8,6 @@ import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type GroupsTeamModel from '@typings/database/models/servers/groups_team';
|
||||
import type MyTeamModel from '@typings/database/models/servers/my_team';
|
||||
import type SlashCommandModel from '@typings/database/models/servers/slash_command';
|
||||
import type TeamChannelHistoryModel from '@typings/database/models/servers/team_channel_history';
|
||||
@@ -17,7 +16,6 @@ import type TeamSearchHistoryModel from '@typings/database/models/servers/team_s
|
||||
|
||||
const {
|
||||
CHANNEL,
|
||||
GROUPS_TEAM,
|
||||
TEAM,
|
||||
MY_TEAM,
|
||||
SLASH_COMMAND,
|
||||
@@ -39,9 +37,6 @@ export default class TeamModel extends Model {
|
||||
/** A TEAM has a 1:N relationship with CHANNEL. A TEAM can possess multiple channels */
|
||||
[CHANNEL]: {type: 'has_many', foreignKey: 'team_id'},
|
||||
|
||||
/** A TEAM has a 1:N relationship with GROUPS_TEAM. A TEAM can possess multiple groups */
|
||||
[GROUPS_TEAM]: {type: 'has_many', foreignKey: 'team_id'},
|
||||
|
||||
/** A TEAM can be associated to one MY_TEAM (relationship is 1:1) */
|
||||
[MY_TEAM]: {type: 'has_many', foreignKey: 'id'},
|
||||
|
||||
@@ -85,9 +80,6 @@ export default class TeamModel extends Model {
|
||||
/** channels : All the channels associated with this team */
|
||||
@children(CHANNEL) channels!: ChannelModel[];
|
||||
|
||||
/** groupsTeam : All the groups associated with this team */
|
||||
@children(GROUPS_TEAM) groupsTeam!: GroupsTeamModel[];
|
||||
|
||||
/** myTeam : Retrieves additional information about the team that this user is possibly part of. */
|
||||
@immutableRelation(MY_TEAM, 'id') myTeam!: Relation<MyTeamModel>;
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import {safeParseJSON} from '@utils/helpers';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type ReactionModel from '@typings/database/models/servers/reaction';
|
||||
@@ -19,7 +18,6 @@ import type {UserMentionKey} from '@typings/global/markdown';
|
||||
const {
|
||||
CHANNEL,
|
||||
CHANNEL_MEMBERSHIP,
|
||||
GROUP_MEMBERSHIP,
|
||||
POST,
|
||||
PREFERENCE,
|
||||
REACTION,
|
||||
@@ -44,9 +42,6 @@ export default class UserModel extends Model {
|
||||
/** USER has a 1:N relationship with CHANNEL_MEMBERSHIP. A user can be part of multiple channels */
|
||||
[CHANNEL_MEMBERSHIP]: {type: 'has_many', foreignKey: 'user_id'},
|
||||
|
||||
/** USER has a 1:N relationship with GROUP_MEMBERSHIP. A user can be part of multiple groups */
|
||||
[GROUP_MEMBERSHIP]: {type: 'has_many', foreignKey: 'user_id'},
|
||||
|
||||
/** USER has a 1:N relationship with POST. A user can author multiple posts */
|
||||
[POST]: {type: 'has_many', foreignKey: 'user_id'},
|
||||
|
||||
@@ -122,9 +117,6 @@ export default class UserModel extends Model {
|
||||
/** channels : All the channels that this user is part of */
|
||||
@children(CHANNEL_MEMBERSHIP) channels!: ChannelMembershipModel[];
|
||||
|
||||
/** groups : All the groups that this user is part of */
|
||||
@children(GROUP_MEMBERSHIP) groups!: GroupMembershipModel[];
|
||||
|
||||
/** posts : All the posts that this user has written*/
|
||||
@children(POST) posts!: PostModel[];
|
||||
|
||||
|
||||
@@ -9,10 +9,6 @@ import type ChannelMembershipModel from '@typings/database/models/servers/channe
|
||||
import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji';
|
||||
import type DraftModel from '@typings/database/models/servers/draft';
|
||||
import type FileModel from '@typings/database/models/servers/file';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type GroupsChannelModel from '@typings/database/models/servers/groups_channel';
|
||||
import type GroupsTeamModel from '@typings/database/models/servers/groups_team';
|
||||
import type MyChannelModel from '@typings/database/models/servers/my_channel';
|
||||
import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings';
|
||||
import type MyTeamModel from '@typings/database/models/servers/my_team';
|
||||
@@ -83,26 +79,10 @@ export const isRecordCustomEmojiEqualToRaw = (record: CustomEmojiModel, raw: Cus
|
||||
return raw.id === record.id;
|
||||
};
|
||||
|
||||
export const isRecordGroupMembershipEqualToRaw = (record: GroupMembershipModel, raw: GroupMembership) => {
|
||||
return raw.user_id === record.userId && raw.group_id === record.groupId;
|
||||
};
|
||||
|
||||
export const isRecordChannelMembershipEqualToRaw = (record: ChannelMembershipModel, raw: Pick<ChannelMembership, 'user_id' | 'channel_id'>) => {
|
||||
return raw.user_id === record.userId && raw.channel_id === record.channelId;
|
||||
};
|
||||
|
||||
export const isRecordGroupEqualToRaw = (record: GroupModel, raw: Group) => {
|
||||
return raw.id === record.id;
|
||||
};
|
||||
|
||||
export const isRecordGroupsTeamEqualToRaw = (record: GroupsTeamModel, raw: GroupTeam) => {
|
||||
return raw.team_id === record.teamId && raw.group_id === record.groupId;
|
||||
};
|
||||
|
||||
export const isRecordGroupsChannelEqualToRaw = (record: GroupsChannelModel, raw: GroupChannel) => {
|
||||
return raw.channel_id === record.channelId && raw.group_id === record.groupId;
|
||||
};
|
||||
|
||||
export const isRecordTeamEqualToRaw = (record: TeamModel, raw: Team) => {
|
||||
return raw.id === record.id;
|
||||
};
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {
|
||||
isRecordGroupEqualToRaw,
|
||||
isRecordGroupMembershipEqualToRaw,
|
||||
isRecordGroupsChannelEqualToRaw,
|
||||
isRecordGroupsTeamEqualToRaw,
|
||||
} from '@database/operator/server_data_operator/comparators';
|
||||
import {
|
||||
transformGroupMembershipRecord,
|
||||
transformGroupRecord,
|
||||
transformGroupsChannelRecord,
|
||||
transformGroupsTeamRecord,
|
||||
} from '@database/operator/server_data_operator/transformers/group';
|
||||
|
||||
import ServerDataOperator from '..';
|
||||
|
||||
describe('*** Operator: Group Handlers tests ***', () => {
|
||||
let operator: ServerDataOperator;
|
||||
beforeAll(async () => {
|
||||
await DatabaseManager.init(['baseHandler.test.com']);
|
||||
operator = DatabaseManager.serverDatabases['baseHandler.test.com'].operator;
|
||||
});
|
||||
|
||||
it('=> HandleGroup: should write to the GROUP table', async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords');
|
||||
const groups: Group[] = [
|
||||
{
|
||||
id: 'id_groupdfjdlfkjdkfdsf',
|
||||
name: 'mobile_team',
|
||||
display_name: 'mobile team',
|
||||
description: '',
|
||||
remote_id: '',
|
||||
create_at: 0,
|
||||
update_at: 0,
|
||||
delete_at: 0,
|
||||
has_syncables: true,
|
||||
type: '',
|
||||
member_count: 1,
|
||||
allow_reference: true,
|
||||
},
|
||||
];
|
||||
|
||||
await operator.handleGroup({
|
||||
groups,
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
expect(spyOnHandleRecords).toHaveBeenCalledTimes(1);
|
||||
expect(spyOnHandleRecords).toHaveBeenCalledWith({
|
||||
fieldName: 'id',
|
||||
createOrUpdateRawValues: groups,
|
||||
tableName: 'Group',
|
||||
prepareRecordsOnly: false,
|
||||
findMatchingRecordBy: isRecordGroupEqualToRaw,
|
||||
transformer: transformGroupRecord,
|
||||
});
|
||||
});
|
||||
|
||||
it('=> HandleGroupsTeam: should write to the GROUPS_TEAM table', async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords');
|
||||
const groupsTeams = [
|
||||
{
|
||||
team_id: 'team_899',
|
||||
team_display_name: '',
|
||||
team_type: '',
|
||||
group_id: 'group_id89',
|
||||
auto_add: true,
|
||||
create_at: 0,
|
||||
delete_at: 0,
|
||||
update_at: 0,
|
||||
},
|
||||
];
|
||||
|
||||
await operator.handleGroupsTeam({
|
||||
groupsTeams,
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
expect(spyOnHandleRecords).toHaveBeenCalledTimes(1);
|
||||
expect(spyOnHandleRecords).toHaveBeenCalledWith({
|
||||
fieldName: 'group_id',
|
||||
createOrUpdateRawValues: groupsTeams,
|
||||
tableName: 'GroupsTeam',
|
||||
prepareRecordsOnly: false,
|
||||
findMatchingRecordBy: isRecordGroupsTeamEqualToRaw,
|
||||
transformer: transformGroupsTeamRecord,
|
||||
});
|
||||
});
|
||||
|
||||
it('=> HandleGroupsChannel: should write to the GROUPS_CHANNEL table', async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords');
|
||||
const groupsChannels = [
|
||||
{
|
||||
auto_add: true,
|
||||
channel_display_name: '',
|
||||
channel_id: 'channelid',
|
||||
channel_type: '',
|
||||
create_at: 0,
|
||||
delete_at: 0,
|
||||
group_id: 'groupId',
|
||||
team_display_name: '',
|
||||
team_id: '',
|
||||
team_type: '',
|
||||
update_at: 0,
|
||||
},
|
||||
];
|
||||
|
||||
await operator.handleGroupsChannel({
|
||||
groupsChannels,
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
expect(spyOnHandleRecords).toHaveBeenCalledTimes(1);
|
||||
expect(spyOnHandleRecords).toHaveBeenCalledWith({
|
||||
fieldName: 'group_id',
|
||||
createOrUpdateRawValues: groupsChannels,
|
||||
tableName: 'GroupsChannel',
|
||||
prepareRecordsOnly: false,
|
||||
findMatchingRecordBy: isRecordGroupsChannelEqualToRaw,
|
||||
transformer: transformGroupsChannelRecord,
|
||||
});
|
||||
});
|
||||
|
||||
it('=> HandleGroupMembership: should write to the GROUP_MEMBERSHIP table', async () => {
|
||||
expect.assertions(2);
|
||||
|
||||
const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords');
|
||||
const groupMemberships = [
|
||||
{
|
||||
user_id: 'u4cprpki7ri81mbx8efixcsb8jo',
|
||||
group_id: 'g4cprpki7ri81mbx8efixcsb8jo',
|
||||
},
|
||||
];
|
||||
|
||||
await operator.handleGroupMembership({
|
||||
groupMemberships,
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
expect(spyOnHandleRecords).toHaveBeenCalledTimes(1);
|
||||
expect(spyOnHandleRecords).toHaveBeenCalledWith({
|
||||
fieldName: 'group_id',
|
||||
createOrUpdateRawValues: groupMemberships,
|
||||
tableName: 'GroupMembership',
|
||||
prepareRecordsOnly: false,
|
||||
findMatchingRecordBy: isRecordGroupMembershipEqualToRaw,
|
||||
transformer: transformGroupMembershipRecord,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,152 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import DataOperatorException from '@database/exceptions/data_operator_exception';
|
||||
import {
|
||||
isRecordGroupEqualToRaw,
|
||||
isRecordGroupMembershipEqualToRaw,
|
||||
isRecordGroupsChannelEqualToRaw,
|
||||
isRecordGroupsTeamEqualToRaw,
|
||||
} from '@database/operator/server_data_operator/comparators';
|
||||
import {
|
||||
transformGroupMembershipRecord,
|
||||
transformGroupRecord,
|
||||
transformGroupsChannelRecord,
|
||||
transformGroupsTeamRecord,
|
||||
} from '@database/operator/server_data_operator/transformers/group';
|
||||
import {getUniqueRawsBy} from '@database/operator/utils/general';
|
||||
|
||||
import type {HandleGroupArgs, HandleGroupMembershipArgs, HandleGroupsChannelArgs, HandleGroupsTeamArgs} from '@typings/database/database';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type GroupsChannelModel from '@typings/database/models/servers/groups_channel';
|
||||
import type GroupsTeamModel from '@typings/database/models/servers/groups_team';
|
||||
|
||||
const {
|
||||
GROUP,
|
||||
GROUPS_CHANNEL,
|
||||
GROUPS_TEAM,
|
||||
GROUP_MEMBERSHIP,
|
||||
} = MM_TABLES.SERVER;
|
||||
|
||||
export interface GroupHandlerMix {
|
||||
handleGroupMembership: ({groupMemberships, prepareRecordsOnly}: HandleGroupMembershipArgs) => Promise<GroupMembershipModel[]>;
|
||||
handleGroup: ({groups, prepareRecordsOnly}: HandleGroupArgs) => Promise<GroupModel[]>;
|
||||
handleGroupsTeam: ({groupsTeams, prepareRecordsOnly}: HandleGroupsTeamArgs) => Promise<GroupsTeamModel[]>;
|
||||
handleGroupsChannel: ({groupsChannels, prepareRecordsOnly}: HandleGroupsChannelArgs) => Promise<GroupsChannelModel[]>;
|
||||
}
|
||||
|
||||
const GroupHandler = (superclass: any) => class extends superclass {
|
||||
/**
|
||||
* handleGroupMembership: Handler responsible for the Create/Update operations occurring on the GROUP_MEMBERSHIP table from the 'Server' schema
|
||||
* @param {HandleGroupMembershipArgs} groupMembershipsArgs
|
||||
* @param {RawGroupMembership[]} groupMembershipsArgs.groupMemberships
|
||||
* @param {boolean} groupMembershipsArgs.prepareRecordsOnly
|
||||
* @throws DataOperatorException
|
||||
* @returns {Promise<GroupMembershipModel[]>}
|
||||
*/
|
||||
handleGroupMembership = ({groupMemberships, prepareRecordsOnly = true}: HandleGroupMembershipArgs): Promise<GroupMembershipModel[]> => {
|
||||
if (!groupMemberships.length) {
|
||||
throw new DataOperatorException(
|
||||
'An empty "groupMemberships" array has been passed to the handleGroupMembership method',
|
||||
);
|
||||
}
|
||||
|
||||
const createOrUpdateRawValues = getUniqueRawsBy({raws: groupMemberships, key: 'group_id'});
|
||||
|
||||
return this.handleRecords({
|
||||
fieldName: 'group_id',
|
||||
findMatchingRecordBy: isRecordGroupMembershipEqualToRaw,
|
||||
transformer: transformGroupMembershipRecord,
|
||||
prepareRecordsOnly,
|
||||
createOrUpdateRawValues,
|
||||
tableName: GROUP_MEMBERSHIP,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* handleGroup: Handler responsible for the Create/Update operations occurring on the GROUP table from the 'Server' schema
|
||||
* @param {HandleGroupArgs} groupsArgs
|
||||
* @param {RawGroup[]} groupsArgs.groups
|
||||
* @param {boolean} groupsArgs.prepareRecordsOnly
|
||||
* @throws DataOperatorException
|
||||
* @returns {Promise<GroupModel[]>}
|
||||
*/
|
||||
handleGroup = ({groups, prepareRecordsOnly = true}: HandleGroupArgs): Promise<GroupModel[]> => {
|
||||
if (!groups.length) {
|
||||
throw new DataOperatorException(
|
||||
'An empty "groups" array has been passed to the handleGroup method',
|
||||
);
|
||||
}
|
||||
|
||||
const createOrUpdateRawValues = getUniqueRawsBy({raws: groups, key: 'id'});
|
||||
|
||||
return this.handleRecords({
|
||||
fieldName: 'id',
|
||||
findMatchingRecordBy: isRecordGroupEqualToRaw,
|
||||
transformer: transformGroupRecord,
|
||||
prepareRecordsOnly,
|
||||
createOrUpdateRawValues,
|
||||
tableName: GROUP,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* handleGroupsTeam: Handler responsible for the Create/Update operations occurring on the GROUPS_TEAM table from the 'Server' schema
|
||||
* @param {HandleGroupsTeamArgs} groupsTeamsArgs
|
||||
* @param {GroupsTeam[]} groupsTeamsArgs.groupsTeams
|
||||
* @param {boolean} groupsTeamsArgs.prepareRecordsOnly
|
||||
* @throws DataOperatorException
|
||||
* @returns {Promise<GroupsTeamModel[]>}
|
||||
*/
|
||||
handleGroupsTeam = ({groupsTeams, prepareRecordsOnly = true}: HandleGroupsTeamArgs): Promise<GroupsTeamModel[]> => {
|
||||
if (!groupsTeams.length) {
|
||||
throw new DataOperatorException(
|
||||
'An empty "groups" array has been passed to the handleGroupsTeam method',
|
||||
);
|
||||
}
|
||||
|
||||
const createOrUpdateRawValues = groupsTeams.filter((gt, index, self) => (
|
||||
index === self.findIndex((item) => item.team_id === gt.team_id && item.group_id === gt.group_id)));
|
||||
|
||||
return this.handleRecords({
|
||||
fieldName: 'group_id',
|
||||
findMatchingRecordBy: isRecordGroupsTeamEqualToRaw,
|
||||
transformer: transformGroupsTeamRecord,
|
||||
prepareRecordsOnly,
|
||||
createOrUpdateRawValues,
|
||||
tableName: GROUPS_TEAM,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* handleGroupsChannel: Handler responsible for the Create/Update operations occurring on the GROUPS_CHANNEL table from the 'Server' schema
|
||||
* @param {HandleGroupsChannelArgs} groupsChannelsArgs
|
||||
* @param {GroupsChannel[]} groupsChannelsArgs.groupsChannels
|
||||
* @param {boolean} groupsChannelsArgs.prepareRecordsOnly
|
||||
* @throws DataOperatorException
|
||||
* @returns {Promise<GroupsChannelModel[]>}
|
||||
*/
|
||||
handleGroupsChannel = ({groupsChannels, prepareRecordsOnly = true}: HandleGroupsChannelArgs): Promise<GroupsChannelModel[]> => {
|
||||
if (!groupsChannels.length) {
|
||||
throw new DataOperatorException(
|
||||
'An empty "groups" array has been passed to the handleGroupsTeam method',
|
||||
);
|
||||
}
|
||||
|
||||
const createOrUpdateRawValues = groupsChannels.filter((gc, index, self) => (
|
||||
index === self.findIndex((item) => item.channel_id === gc.channel_id && item.group_id === gc.group_id)));
|
||||
|
||||
return this.handleRecords({
|
||||
fieldName: 'group_id',
|
||||
findMatchingRecordBy: isRecordGroupsChannelEqualToRaw,
|
||||
transformer: transformGroupsChannelRecord,
|
||||
prepareRecordsOnly,
|
||||
createOrUpdateRawValues,
|
||||
tableName: GROUPS_CHANNEL,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export default GroupHandler;
|
||||
@@ -4,7 +4,6 @@
|
||||
import ServerDataOperatorBase from '@database/operator/server_data_operator/handlers';
|
||||
import CategoryHandler, {CategoryHandlerMix} from '@database/operator/server_data_operator/handlers/category';
|
||||
import ChannelHandler, {ChannelHandlerMix} from '@database/operator/server_data_operator/handlers/channel';
|
||||
import GroupHandler, {GroupHandlerMix} from '@database/operator/server_data_operator/handlers/group';
|
||||
import PostHandler, {PostHandlerMix} from '@database/operator/server_data_operator/handlers/post';
|
||||
import PostsInChannelHandler, {PostsInChannelHandlerMix} from '@database/operator/server_data_operator/handlers/posts_in_channel';
|
||||
import PostsInThreadHandler, {PostsInThreadHandlerMix} from '@database/operator/server_data_operator/handlers/posts_in_thread';
|
||||
@@ -15,12 +14,11 @@ import mix from '@utils/mix';
|
||||
import type {Database} from '@nozbe/watermelondb';
|
||||
|
||||
interface ServerDataOperator extends ServerDataOperatorBase, PostHandlerMix, PostsInChannelHandlerMix,
|
||||
PostsInThreadHandlerMix, UserHandlerMix, GroupHandlerMix, ChannelHandlerMix, CategoryHandlerMix, TeamHandlerMix {}
|
||||
PostsInThreadHandlerMix, UserHandlerMix, ChannelHandlerMix, CategoryHandlerMix, TeamHandlerMix {}
|
||||
|
||||
class ServerDataOperator extends mix(ServerDataOperatorBase).with(
|
||||
CategoryHandler,
|
||||
ChannelHandler,
|
||||
GroupHandler,
|
||||
PostHandler,
|
||||
PostsInChannelHandler,
|
||||
PostsInThreadHandler,
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {
|
||||
transformGroupMembershipRecord,
|
||||
transformGroupRecord,
|
||||
transformGroupsChannelRecord,
|
||||
transformGroupsTeamRecord,
|
||||
} from '@database/operator/server_data_operator/transformers/group';
|
||||
import {createTestConnection} from '@database/operator/utils/create_test_connection';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
describe('*** GROUP Prepare Records Test ***', () => {
|
||||
it('=> transformGroupRecord: should return an array of type Group', async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'group_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
const preparedRecords = await transformGroupRecord({
|
||||
action: OperationType.CREATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: undefined,
|
||||
raw: {
|
||||
id: 'id_groupdfjdlfkjdkfdsf',
|
||||
name: 'mobile_team',
|
||||
display_name: 'mobile team',
|
||||
description: '',
|
||||
type: '',
|
||||
remote_id: '',
|
||||
create_at: 0,
|
||||
update_at: 0,
|
||||
delete_at: 0,
|
||||
has_syncables: true,
|
||||
member_count: 0,
|
||||
allow_reference: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(preparedRecords).toBeTruthy();
|
||||
expect(preparedRecords!.collection.modelClass.name).toBe('GroupModel');
|
||||
});
|
||||
|
||||
it('=> transformGroupsTeamRecord: should return an array of type GroupsTeam', async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'group_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
const preparedRecords = await transformGroupsTeamRecord({
|
||||
action: OperationType.CREATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: undefined,
|
||||
raw: {
|
||||
team_id: 'team_89',
|
||||
team_display_name: '',
|
||||
team_type: '',
|
||||
group_id: 'group_id89',
|
||||
auto_add: true,
|
||||
create_at: 0,
|
||||
delete_at: 0,
|
||||
update_at: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(preparedRecords).toBeTruthy();
|
||||
expect(preparedRecords!.collection.modelClass.name).toBe('GroupsTeamModel');
|
||||
});
|
||||
|
||||
it('=> transformGroupsChannelRecord: should return an array of type GroupsChannel', async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'group_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
const preparedRecords = await transformGroupsChannelRecord({
|
||||
action: OperationType.CREATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: undefined,
|
||||
raw: {
|
||||
auto_add: true,
|
||||
channel_display_name: '',
|
||||
channel_id: 'channelid',
|
||||
channel_type: '',
|
||||
create_at: 0,
|
||||
delete_at: 0,
|
||||
group_id: 'groupId',
|
||||
team_display_name: '',
|
||||
team_id: '',
|
||||
team_type: '',
|
||||
update_at: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(preparedRecords).toBeTruthy();
|
||||
expect(preparedRecords!.collection.modelClass.name).toBe('GroupsChannelModel');
|
||||
});
|
||||
|
||||
it('=> transformGroupMembershipRecord: should return an array of type GroupMembership', async () => {
|
||||
expect.assertions(3);
|
||||
|
||||
const database = await createTestConnection({databaseName: 'group_prepare_records', setActive: true});
|
||||
expect(database).toBeTruthy();
|
||||
|
||||
const preparedRecords = await transformGroupMembershipRecord({
|
||||
action: OperationType.CREATE,
|
||||
database: database!,
|
||||
value: {
|
||||
record: undefined,
|
||||
raw: {
|
||||
user_id: 'u4cprpki7ri81mbx8efixcsb8jo',
|
||||
group_id: 'g4cprpki7ri81mbx8efixcsb8jo',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(preparedRecords).toBeTruthy();
|
||||
expect(preparedRecords!.collection.modelClass.name).toBe('GroupMembershipModel');
|
||||
});
|
||||
});
|
||||
@@ -1,131 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index';
|
||||
import {OperationType} from '@typings/database/enums';
|
||||
|
||||
import type {TransformerArgs} from '@typings/database/database';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type GroupsChannelModel from '@typings/database/models/servers/groups_channel';
|
||||
import type GroupsTeamModel from '@typings/database/models/servers/groups_team';
|
||||
|
||||
const {
|
||||
GROUP,
|
||||
GROUPS_CHANNEL,
|
||||
GROUPS_TEAM,
|
||||
GROUP_MEMBERSHIP,
|
||||
} = MM_TABLES.SERVER;
|
||||
|
||||
/**
|
||||
* transformGroupMembershipRecord: Prepares a record of the SERVER database 'GroupMembership' table for update or create actions.
|
||||
* @param {TransformerArgs} operator
|
||||
* @param {Database} operator.database
|
||||
* @param {RecordPair} operator.value
|
||||
* @returns {Promise<GroupMembershipModel>}
|
||||
*/
|
||||
export const transformGroupMembershipRecord = ({action, database, value}: TransformerArgs): Promise<GroupMembershipModel> => {
|
||||
const raw = value.raw as GroupMembership;
|
||||
const record = value.record as GroupMembershipModel;
|
||||
const isCreateAction = action === OperationType.CREATE;
|
||||
|
||||
// If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database
|
||||
const fieldsMapper = (groupMember: GroupMembershipModel) => {
|
||||
groupMember._raw.id = isCreateAction ? (raw?.id ?? groupMember.id) : record.id;
|
||||
groupMember.groupId = raw.group_id;
|
||||
groupMember.userId = raw.user_id;
|
||||
};
|
||||
|
||||
return prepareBaseRecord({
|
||||
action,
|
||||
database,
|
||||
tableName: GROUP_MEMBERSHIP,
|
||||
value,
|
||||
fieldsMapper,
|
||||
}) as Promise<GroupMembershipModel>;
|
||||
};
|
||||
|
||||
/**
|
||||
* transformGroupRecord: Prepares a record of the SERVER database 'Group' table for update or create actions.
|
||||
* @param {DataFactory} operator
|
||||
* @param {Database} operator.database
|
||||
* @param {RecordPair} operator.value
|
||||
* @returns {Promise<GroupModel>}
|
||||
*/
|
||||
export const transformGroupRecord = ({action, database, value}: TransformerArgs): Promise<GroupModel> => {
|
||||
const raw = value.raw as Group;
|
||||
const record = value.record as GroupModel;
|
||||
const isCreateAction = action === OperationType.CREATE;
|
||||
|
||||
// If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database
|
||||
const fieldsMapper = (group: GroupModel) => {
|
||||
group._raw.id = isCreateAction ? (raw?.id ?? group.id) : record.id;
|
||||
group.allowReference = raw.allow_reference;
|
||||
group.deleteAt = raw.delete_at;
|
||||
group.name = raw.name;
|
||||
group.displayName = raw.display_name;
|
||||
};
|
||||
|
||||
return prepareBaseRecord({
|
||||
action,
|
||||
database,
|
||||
tableName: GROUP,
|
||||
value,
|
||||
fieldsMapper,
|
||||
}) as Promise<GroupModel>;
|
||||
};
|
||||
|
||||
/**
|
||||
* transformGroupsTeamRecord: Prepares a record of the SERVER database 'GroupsTeam' table for update or create actions.
|
||||
* @param {DataFactory} operator
|
||||
* @param {Database} operator.database
|
||||
* @param {RecordPair} operator.value
|
||||
* @returns {Promise<GroupsTeamModel>}
|
||||
*/
|
||||
export const transformGroupsTeamRecord = ({action, database, value}: TransformerArgs): Promise<GroupsTeamModel> => {
|
||||
const raw = value.raw as GroupTeam;
|
||||
const record = value.record as GroupsTeamModel;
|
||||
const isCreateAction = action === OperationType.CREATE;
|
||||
|
||||
const fieldsMapper = (groupsTeam: GroupsTeamModel) => {
|
||||
groupsTeam._raw.id = isCreateAction ? groupsTeam.id : record.id;
|
||||
groupsTeam.teamId = raw.team_id;
|
||||
groupsTeam.groupId = raw.group_id;
|
||||
};
|
||||
|
||||
return prepareBaseRecord({
|
||||
action,
|
||||
database,
|
||||
tableName: GROUPS_TEAM,
|
||||
value,
|
||||
fieldsMapper,
|
||||
}) as Promise<GroupsTeamModel>;
|
||||
};
|
||||
|
||||
/**
|
||||
* transformGroupsChannelRecord: Prepares a record of the SERVER database 'GroupsChannel' table for update or create actions.
|
||||
* @param {DataFactory} operator
|
||||
* @param {Database} operator.database
|
||||
* @param {RecordPair} operator.value
|
||||
* @returns {Promise<GroupsChannelModel>}
|
||||
*/
|
||||
export const transformGroupsChannelRecord = ({action, database, value}: TransformerArgs): Promise<GroupsChannelModel> => {
|
||||
const raw = value.raw as GroupChannelRelation;
|
||||
const record = value.record as GroupsChannelModel;
|
||||
const isCreateAction = action === OperationType.CREATE;
|
||||
|
||||
const fieldsMapper = (groupsChannel: GroupsChannelModel) => {
|
||||
groupsChannel._raw.id = isCreateAction ? groupsChannel.id : record.id;
|
||||
groupsChannel.channelId = raw.channel_id;
|
||||
groupsChannel.groupId = raw.group_id;
|
||||
};
|
||||
|
||||
return prepareBaseRecord({
|
||||
action,
|
||||
database,
|
||||
tableName: GROUPS_CHANNEL,
|
||||
value,
|
||||
fieldsMapper,
|
||||
}) as Promise<GroupsChannelModel>;
|
||||
};
|
||||
@@ -12,10 +12,6 @@ import {
|
||||
CustomEmojiSchema,
|
||||
DraftSchema,
|
||||
FileSchema,
|
||||
GroupMembershipSchema,
|
||||
GroupSchema,
|
||||
GroupsChannelSchema,
|
||||
GroupsTeamSchema,
|
||||
MyChannelSchema,
|
||||
MyChannelSettingsSchema,
|
||||
MyTeamSchema,
|
||||
@@ -46,10 +42,6 @@ export const serverSchema: AppSchema = appSchema({
|
||||
CustomEmojiSchema,
|
||||
DraftSchema,
|
||||
FileSchema,
|
||||
GroupMembershipSchema,
|
||||
GroupSchema,
|
||||
GroupsChannelSchema,
|
||||
GroupsTeamSchema,
|
||||
MyChannelSchema,
|
||||
MyChannelSettingsSchema,
|
||||
MyTeamSchema,
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {tableSchema} from '@nozbe/watermelondb';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
const {GROUP} = MM_TABLES.SERVER;
|
||||
|
||||
export default tableSchema({
|
||||
name: GROUP,
|
||||
columns: [
|
||||
{name: 'allow_reference', type: 'boolean'},
|
||||
{name: 'delete_at', type: 'number'},
|
||||
{name: 'display_name', type: 'string'},
|
||||
{name: 'name', type: 'string'},
|
||||
],
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {tableSchema} from '@nozbe/watermelondb';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
const {GROUP_MEMBERSHIP} = MM_TABLES.SERVER;
|
||||
|
||||
export default tableSchema({
|
||||
name: GROUP_MEMBERSHIP,
|
||||
columns: [
|
||||
{name: 'group_id', type: 'string', isIndexed: true},
|
||||
{name: 'user_id', type: 'string', isIndexed: true},
|
||||
],
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {tableSchema} from '@nozbe/watermelondb';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
const {GROUPS_CHANNEL} = MM_TABLES.SERVER;
|
||||
|
||||
export default tableSchema({
|
||||
name: GROUPS_CHANNEL,
|
||||
columns: [
|
||||
{name: 'channel_id', type: 'string', isIndexed: true},
|
||||
{name: 'group_id', type: 'string', isIndexed: true},
|
||||
{name: 'member_count', type: 'number'},
|
||||
{name: 'timezone_count', type: 'number'},
|
||||
],
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {tableSchema} from '@nozbe/watermelondb';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
const {GROUPS_TEAM} = MM_TABLES.SERVER;
|
||||
|
||||
export default tableSchema({
|
||||
name: GROUPS_TEAM,
|
||||
columns: [
|
||||
{name: 'group_id', type: 'string', isIndexed: true},
|
||||
{name: 'team_id', type: 'string', isIndexed: true},
|
||||
],
|
||||
});
|
||||
@@ -9,10 +9,6 @@ export {default as ChannelSchema} from './channel';
|
||||
export {default as CustomEmojiSchema} from './custom_emoji';
|
||||
export {default as DraftSchema} from './draft';
|
||||
export {default as FileSchema} from './file';
|
||||
export {default as GroupMembershipSchema} from './group_membership';
|
||||
export {default as GroupSchema} from './group';
|
||||
export {default as GroupsChannelSchema} from './groups_channel';
|
||||
export {default as GroupsTeamSchema} from './groups_team';
|
||||
export {default as MyChannelSchema} from './my_channel';
|
||||
export {default as MyChannelSettingsSchema} from './my_channel_settings';
|
||||
export {default as MyTeamSchema} from './my_team';
|
||||
|
||||
@@ -16,10 +16,6 @@ const {
|
||||
CUSTOM_EMOJI,
|
||||
DRAFT,
|
||||
FILE,
|
||||
GROUP,
|
||||
GROUPS_CHANNEL,
|
||||
GROUPS_TEAM,
|
||||
GROUP_MEMBERSHIP,
|
||||
MY_CHANNEL,
|
||||
MY_CHANNEL_SETTINGS,
|
||||
MY_TEAM,
|
||||
@@ -292,62 +288,6 @@ describe('*** Test schema for SERVER database ***', () => {
|
||||
{name: 'user_id', type: 'string', isIndexed: true},
|
||||
],
|
||||
},
|
||||
[GROUP]: {
|
||||
name: GROUP,
|
||||
unsafeSql: undefined,
|
||||
columns: {
|
||||
allow_reference: {name: 'allow_reference', type: 'boolean'},
|
||||
delete_at: {name: 'delete_at', type: 'number'},
|
||||
display_name: {name: 'display_name', type: 'string'},
|
||||
name: {name: 'name', type: 'string'},
|
||||
},
|
||||
columnArray: [
|
||||
{name: 'allow_reference', type: 'boolean'},
|
||||
{name: 'delete_at', type: 'number'},
|
||||
{name: 'display_name', type: 'string'},
|
||||
{name: 'name', type: 'string'},
|
||||
],
|
||||
},
|
||||
[GROUPS_CHANNEL]: {
|
||||
name: GROUPS_CHANNEL,
|
||||
unsafeSql: undefined,
|
||||
columns: {
|
||||
channel_id: {name: 'channel_id', type: 'string', isIndexed: true},
|
||||
group_id: {name: 'group_id', type: 'string', isIndexed: true},
|
||||
member_count: {name: 'member_count', type: 'number'},
|
||||
timezone_count: {name: 'timezone_count', type: 'number'},
|
||||
},
|
||||
columnArray: [
|
||||
{name: 'channel_id', type: 'string', isIndexed: true},
|
||||
{name: 'group_id', type: 'string', isIndexed: true},
|
||||
{name: 'member_count', type: 'number'},
|
||||
{name: 'timezone_count', type: 'number'},
|
||||
],
|
||||
},
|
||||
[GROUPS_TEAM]: {
|
||||
name: GROUPS_TEAM,
|
||||
unsafeSql: undefined,
|
||||
columns: {
|
||||
group_id: {name: 'group_id', type: 'string', isIndexed: true},
|
||||
team_id: {name: 'team_id', type: 'string', isIndexed: true},
|
||||
},
|
||||
columnArray: [
|
||||
{name: 'group_id', type: 'string', isIndexed: true},
|
||||
{name: 'team_id', type: 'string', isIndexed: true},
|
||||
],
|
||||
},
|
||||
[GROUP_MEMBERSHIP]: {
|
||||
name: GROUP_MEMBERSHIP,
|
||||
unsafeSql: undefined,
|
||||
columns: {
|
||||
group_id: {name: 'group_id', type: 'string', isIndexed: true},
|
||||
user_id: {name: 'user_id', type: 'string', isIndexed: true},
|
||||
},
|
||||
columnArray: [
|
||||
{name: 'group_id', type: 'string', isIndexed: true},
|
||||
{name: 'user_id', type: 'string', isIndexed: true},
|
||||
],
|
||||
},
|
||||
[PREFERENCE]: {
|
||||
name: PREFERENCE,
|
||||
unsafeSql: undefined,
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type GroupsChannelModel from '@typings/database/models/servers/groups_channel';
|
||||
import type GroupsTeamModel from '@typings/database/models/servers/groups_team';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type TeamModel from '@typings/database/models/servers/team';
|
||||
|
||||
export const queryGroupsAssociatedToChannelForReference = async (channel: ChannelModel) => {
|
||||
const groupChannels = await channel.groupsChannel.fetch() as GroupsChannelModel[];
|
||||
const groupChannelPromises = groupChannels.map((g) => g.group.fetch());
|
||||
const groups = await Promise.all(groupChannelPromises) as GroupModel[];
|
||||
return groups.filter((g) => g.deleteAt === 0);
|
||||
};
|
||||
|
||||
export const queryGroupsAssociatedToTeamForReference = async (team: TeamModel) => {
|
||||
const groupTeams = await team.groupsTeam.fetch() as GroupsTeamModel[];
|
||||
const teamGroupPromises = groupTeams.map((g) => g.group.fetch());
|
||||
const groups = await Promise.all(teamGroupPromises) as GroupModel[];
|
||||
return groups.filter((g) => g.deleteAt === 0);
|
||||
};
|
||||
|
||||
export const queryGroupForPosts = async (post: PostModel) => {
|
||||
try {
|
||||
if (post.id === post.pendingPostId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const channel = await post.channel.fetch() as ChannelModel;
|
||||
const team = await channel?.team.fetch() as TeamModel | undefined;
|
||||
let groupsForReference: GroupModel[] | null = null;
|
||||
|
||||
if (team?.isGroupConstrained && channel.isGroupConstrained) {
|
||||
const groupsFromChannel = await queryGroupsAssociatedToChannelForReference(channel);
|
||||
const groupsFromTeam = await queryGroupsAssociatedToTeamForReference(team);
|
||||
groupsForReference = groupsFromChannel.concat(groupsFromTeam.filter((item) => groupsFromChannel.indexOf(item) < 0));
|
||||
} else if (team?.isGroupConstrained) {
|
||||
groupsForReference = await queryGroupsAssociatedToTeamForReference(team);
|
||||
} else if (channel.isGroupConstrained) {
|
||||
groupsForReference = await queryGroupsAssociatedToChannelForReference(channel);
|
||||
} else {
|
||||
const myGroups = await post.collections.get(MM_TABLES.SERVER.GROUP_MEMBERSHIP).query().fetch() as GroupMembershipModel[];
|
||||
const myGroupsPromises = myGroups.map((g) => g.group.fetch());
|
||||
groupsForReference = await Promise.all(myGroupsPromises) as GroupModel[];
|
||||
}
|
||||
|
||||
return groupsForReference;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -111,7 +111,6 @@ export const prepareDeleteChannel = async (channel: ChannelModel): Promise<Model
|
||||
const associatedChildren: Array<Query<any>> = [
|
||||
channel.members,
|
||||
channel.drafts,
|
||||
channel.groupsChannel,
|
||||
channel.postsInChannel,
|
||||
];
|
||||
for await (const children of associatedChildren) {
|
||||
|
||||
@@ -221,7 +221,6 @@ export const prepareDeleteTeam = async (team: TeamModel): Promise<Model[]> => {
|
||||
|
||||
const associatedChildren: Array<Query<any>> = [
|
||||
team.members,
|
||||
team.groupsTeam,
|
||||
team.slashCommands,
|
||||
team.teamSearchHistories,
|
||||
];
|
||||
|
||||
@@ -5,11 +5,9 @@ import {MessageDescriptor} from '@formatjs/intl/src/types';
|
||||
import {Alert, AlertButton} from 'react-native';
|
||||
|
||||
import {General} from '@constants';
|
||||
import {AT_MENTION_REGEX_GLOBAL, CODE_REGEX} from '@constants/autocomplete';
|
||||
import {NOTIFY_ALL_MEMBERS} from '@constants/post_draft';
|
||||
import {CODE_REGEX} from '@constants/autocomplete';
|
||||
import {t} from '@i18n';
|
||||
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type {IntlShape} from 'react-intl';
|
||||
|
||||
type AlertCallback = (value?: string) => void;
|
||||
@@ -79,106 +77,6 @@ export const textContainsAtHere = (text: string) => {
|
||||
return (/(?:\B|\b_+)@(here)(?!(\.|-|_)*[^\W_])/i).test(textWithoutCode);
|
||||
};
|
||||
|
||||
export const groupsMentionedInText = (groupsWithAllowReference: GroupModel[], text: string) => {
|
||||
if (!groupsWithAllowReference.length) {
|
||||
return [];
|
||||
}
|
||||
const textWithoutCode = text.replace(CODE_REGEX, '');
|
||||
const mentions = textWithoutCode.match(AT_MENTION_REGEX_GLOBAL) || [];
|
||||
return groupsWithAllowReference.filter((g) => mentions.includes(g.id));
|
||||
};
|
||||
|
||||
// mapGroupMentions remove duplicates from the groupMentions, and if any of the
|
||||
// groups has more members than the NOTIFY_ALL_MEMBERS, return the highest
|
||||
// number of notifications and the timezones of that group.
|
||||
export const mapGroupMentions = (channelMemberCountsByGroup: ChannelMemberCountByGroup[], groupMentions: GroupModel[]) => {
|
||||
let memberNotifyCount = 0;
|
||||
let channelTimezoneCount = 0;
|
||||
const groupMentionsSet = new Set<string>();
|
||||
const mappedChannelMemberCountsByGroup: ChannelMemberCountsByGroup = {};
|
||||
channelMemberCountsByGroup.forEach((group) => {
|
||||
mappedChannelMemberCountsByGroup[group.group_id] = group;
|
||||
});
|
||||
groupMentions.
|
||||
forEach((group) => {
|
||||
const mappedValue = mappedChannelMemberCountsByGroup[group.id];
|
||||
if (mappedValue?.channel_member_count > NOTIFY_ALL_MEMBERS && mappedValue?.channel_member_count > memberNotifyCount) {
|
||||
memberNotifyCount = mappedValue.channel_member_count;
|
||||
channelTimezoneCount = mappedValue.channel_member_timezones_count;
|
||||
}
|
||||
if (group.name) {
|
||||
groupMentionsSet.add(`@${group.name}`);
|
||||
}
|
||||
});
|
||||
return {groupMentionsSet, memberNotifyCount, channelTimezoneCount};
|
||||
};
|
||||
|
||||
export function buildGroupMentionsMessage(intl: IntlShape, groupMentions: string[], memberNotifyCount: number, channelTimezoneCount: number) {
|
||||
let notifyAllMessage = '';
|
||||
|
||||
if (groupMentions.length === 1) {
|
||||
if (channelTimezoneCount > 0) {
|
||||
notifyAllMessage = (
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: 'mobile.post_textbox.one_group.message.with_timezones',
|
||||
defaultMessage: 'By using {mention} you are about to send notifications to {totalMembers} people in {timezones, number} {timezones, plural, one {timezone} other {timezones}}. Are you sure you want to do this?',
|
||||
},
|
||||
{
|
||||
mention: groupMentions[0],
|
||||
totalMembers: memberNotifyCount,
|
||||
timezones: channelTimezoneCount,
|
||||
},
|
||||
)
|
||||
);
|
||||
} else {
|
||||
notifyAllMessage = (
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: 'mobile.post_textbox.one_group.message.without_timezones',
|
||||
defaultMessage: 'By using {mention} you are about to send notifications to {totalMembers} people. Are you sure you want to do this?',
|
||||
},
|
||||
{
|
||||
mention: groupMentions[0],
|
||||
totalMembers: memberNotifyCount,
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
} else if (channelTimezoneCount > 0) {
|
||||
notifyAllMessage = (
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: 'mobile.post_textbox.multi_group.message.with_timezones',
|
||||
defaultMessage: 'By using {mentions} and {finalMention} you are about to send notifications to at least {totalMembers} people in {timezones, number} {timezones, plural, one {timezone} other {timezones}}. Are you sure you want to do this?',
|
||||
},
|
||||
{
|
||||
mentions: groupMentions.slice(0, -1).join(', '),
|
||||
finalMention: groupMentions[groupMentions.length - 1],
|
||||
totalMembers: memberNotifyCount,
|
||||
timezones: channelTimezoneCount,
|
||||
},
|
||||
)
|
||||
);
|
||||
} else {
|
||||
notifyAllMessage = (
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: 'mobile.post_textbox.multi_group.message.without_timezones',
|
||||
defaultMessage: 'By using {mentions} and {finalMention} you are about to send notifications to at least {totalMembers} people. Are you sure you want to do this?',
|
||||
},
|
||||
{
|
||||
mentions: groupMentions.slice(0, -1).join(', '),
|
||||
finalMention: groupMentions[groupMentions.length - 1],
|
||||
totalMembers: memberNotifyCount,
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return notifyAllMessage;
|
||||
}
|
||||
|
||||
export function buildChannelWideMentionMessage(intl: IntlShape, membersCount: number, isTimezoneEnabled: boolean, channelTimezoneCount: number, atHere: boolean) {
|
||||
let notifyAllMessage = '';
|
||||
if (isTimezoneEnabled && channelTimezoneCount) {
|
||||
|
||||
@@ -5,10 +5,8 @@ import {Post} from '@constants';
|
||||
import {DEFAULT_LOCALE} from '@i18n';
|
||||
import {displayUsername} from '@utils/user';
|
||||
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
import type {UserMentionKey} from '@typings/global/markdown';
|
||||
|
||||
export function areConsecutivePosts(post: PostModel, previousPost: PostModel) {
|
||||
let consecutive = false;
|
||||
@@ -60,20 +58,6 @@ export function postUserDisplayName(post: PostModel, author?: UserModel, teammat
|
||||
return displayUsername(author, author?.locale || DEFAULT_LOCALE, teammateNameDisplay, true);
|
||||
}
|
||||
|
||||
export const getMentionKeysForPost = (user: UserModel, post: PostModel, groups: GroupModel[] | null) => {
|
||||
const keys: UserMentionKey[] = user.mentionKeys;
|
||||
|
||||
if (groups?.length) {
|
||||
for (const group of groups) {
|
||||
if (group.name && group.name.trim()) {
|
||||
keys.push({key: `@${group.name}`});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
};
|
||||
|
||||
export function shouldIgnorePost(post: Post): boolean {
|
||||
return Post.IGNORE_POST_TYPES.includes(post.type);
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import {UserModel} from '@database/models/server';
|
||||
import {DEFAULT_LOCALE, getLocalizedMessage, t} from '@i18n';
|
||||
import {toTitleCase} from '@utils/helpers';
|
||||
|
||||
import type GroupModel from '@typings/database/models/servers/group';
|
||||
import type GroupMembershipModel from '@typings/database/models/servers/group_membership';
|
||||
import type {IntlShape} from 'react-intl';
|
||||
|
||||
export function displayUsername(user?: UserProfile | UserModel, locale?: string, teammateDisplayNameSetting?: string, useFallbackUsername = true) {
|
||||
@@ -103,24 +101,6 @@ export const getUsersByUsername = (users: UserModel[]) => {
|
||||
return usersByUsername;
|
||||
};
|
||||
|
||||
export const getUserMentionKeys = (user: UserModel, groups: GroupModel[], userGroups: GroupMembershipModel[]) => {
|
||||
const keys = user.mentionKeys;
|
||||
|
||||
if (groups.length && userGroups.length) {
|
||||
const groupMentions = userGroups.reduce((result: Array<{key: string}>, ug: GroupMembershipModel) => {
|
||||
const group = groups.find((g) => ug.groupId === g.id);
|
||||
if (group) {
|
||||
result.push({key: `@${group.name}`});
|
||||
}
|
||||
return result;
|
||||
}, []);
|
||||
|
||||
keys.push(...groupMentions);
|
||||
}
|
||||
|
||||
return keys;
|
||||
};
|
||||
|
||||
export const getUserTimezone = (user: UserModel) => {
|
||||
return getTimezone(user.timezone);
|
||||
};
|
||||
|
||||
@@ -286,10 +286,6 @@
|
||||
"mobile.post_textbox.entire_channel.message.with_timezones": "By using @all or @channel you are about to send notifications to {totalMembers, number} {totalMembers, plural, one {person} other {people}} in {timezones, number} {timezones, plural, one {timezone} other {timezones}}. Are you sure you want to do this?",
|
||||
"mobile.post_textbox.entire_channel.title": "Confirm sending notifications to entire channel",
|
||||
"mobile.post_textbox.groups.title": "Confirm sending notifications to groups",
|
||||
"mobile.post_textbox.multi_group.message.with_timezones": "By using {mentions} and {finalMention} you are about to send notifications to at least {totalMembers} people in {timezones, number} {timezones, plural, one {timezone} other {timezones}}. Are you sure you want to do this?",
|
||||
"mobile.post_textbox.multi_group.message.without_timezones": "By using {mentions} and {finalMention} you are about to send notifications to at least {totalMembers} people. Are you sure you want to do this?",
|
||||
"mobile.post_textbox.one_group.message.with_timezones": "By using {mention} you are about to send notifications to {totalMembers} people in {timezones, number} {timezones, plural, one {timezone} other {timezones}}. Are you sure you want to do this?",
|
||||
"mobile.post_textbox.one_group.message.without_timezones": "By using {mention} you are about to send notifications to {totalMembers} people. Are you sure you want to do this?",
|
||||
"mobile.post_textbox.uploadFailedDesc": "Some attachments failed to upload to the server. Are you sure you want to post the message?",
|
||||
"mobile.post_textbox.uploadFailedTitle": "Attachment failure",
|
||||
"mobile.post.cancel": "Cancel",
|
||||
|
||||
16
types/database/database.d.ts
vendored
16
types/database/database.d.ts
vendored
@@ -219,26 +219,10 @@ export type HandleTeamArgs = PrepareOnly & {
|
||||
teams: Team[];
|
||||
};
|
||||
|
||||
export type HandleGroupsChannelArgs = PrepareOnly & {
|
||||
groupsChannels: GroupChannelRelation[];
|
||||
};
|
||||
|
||||
export type HandleGroupsTeamArgs = PrepareOnly &{
|
||||
groupsTeams: GroupTeamRelation[];
|
||||
};
|
||||
|
||||
export type HandleGroupArgs = PrepareOnly & {
|
||||
groups: Group[];
|
||||
};
|
||||
|
||||
export type HandleChannelMembershipArgs = PrepareOnly & {
|
||||
channelMemberships: Array<Pick<ChannelMembership, 'user_id' | 'channel_id'>>;
|
||||
};
|
||||
|
||||
export type HandleGroupMembershipArgs = PrepareOnly & {
|
||||
groupMemberships: GroupMembership[];
|
||||
};
|
||||
|
||||
export type HandleTeamMembershipArgs = PrepareOnly & {
|
||||
teamMemberships: TeamMembership[];
|
||||
};
|
||||
|
||||
3
types/database/models/servers/channel.d.ts
vendored
3
types/database/models/servers/channel.d.ts
vendored
@@ -50,9 +50,6 @@ export default class ChannelModel extends Model {
|
||||
/** drafts : All drafts for this channel */
|
||||
drafts: Query<DraftModel>;
|
||||
|
||||
/** groupsChannel : Every group contained in this channel */
|
||||
groupsChannel: Query<GroupsChannelModel>;
|
||||
|
||||
/** posts : All posts made in the channel */
|
||||
posts: Query<PostModel>;
|
||||
|
||||
|
||||
38
types/database/models/servers/group.d.ts
vendored
38
types/database/models/servers/group.d.ts
vendored
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
/**
|
||||
* The Group model unifies/assembles users, teams and channels based on a common ground. For example, a group can be
|
||||
* all users who are in the mobile team. If one needs to send that group a message, then s/he can mention the group's
|
||||
* name in the message. (e.g @mobile_team)
|
||||
*/
|
||||
export default class GroupModel extends Model {
|
||||
/** table (name) : Group */
|
||||
static table: string;
|
||||
|
||||
/** associations : Describes every relationship to this table. */
|
||||
static associations: Associations;
|
||||
|
||||
/** allow_reference : Determins if the group can be referenced in mentions */
|
||||
allowReference: boolean;
|
||||
|
||||
/** delete_at : When the group was deleted */
|
||||
deleteAt: number;
|
||||
|
||||
/** display_name : The display name for the group */
|
||||
displayName: string;
|
||||
|
||||
/** name : The name of the group */
|
||||
name: string;
|
||||
|
||||
/** groupsChannel : All the related children records from GroupsChannel */
|
||||
groupsChannel: Query<GroupsChannelModel>;
|
||||
|
||||
/** groupsTeam : All the related children records from GroupsTeam */
|
||||
groupsTeam: Query<GroupsTeamModel>;
|
||||
|
||||
/** groupMemberships : All the related children records from GroupMembership */
|
||||
groupMemberships: Query<GroupMembershipModel>;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Relation} from '@nozbe/watermelondb';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
/**
|
||||
* The GroupMembership model represents the 'association table' where many groups have users and many users are in
|
||||
* groups (relationship type N:N)
|
||||
*/
|
||||
export default class GroupMembershipModel extends Model {
|
||||
/** table (name) : GroupMembership */
|
||||
static table: string;
|
||||
|
||||
/** associations : Describes every relationship to this table */
|
||||
static associations: Associations;
|
||||
groupId: string;
|
||||
userId: string;
|
||||
|
||||
/** group : The related group this user belongs to */
|
||||
group: Relation<GroupModel>;
|
||||
|
||||
/** user : The related user in the group */
|
||||
user: Relation<UserModel>;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Relation} from '@nozbe/watermelondb';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
/**
|
||||
* The GroupsChannel links the Channel model with the Group model
|
||||
*/
|
||||
export default class GroupsChannelModel extends Model {
|
||||
/** table (name) : GroupsChannel */
|
||||
static table: string;
|
||||
|
||||
/** associations : Describes every relationship to this table. */
|
||||
static associations: Associations;
|
||||
|
||||
/** channel_id : The foreign key of the related CHANNEL model */
|
||||
channelId: string;
|
||||
|
||||
/** group_id : The foreign key of the related GROUP model */
|
||||
groupId: string;
|
||||
|
||||
/** channel : The related record to the parent Channel model */
|
||||
channel: Relation<ChannelModel>;
|
||||
|
||||
/** group : The related record to the parent Group model */
|
||||
group: Relation<GroupModel>;
|
||||
}
|
||||
34
types/database/models/servers/groups_team.d.ts
vendored
34
types/database/models/servers/groups_team.d.ts
vendored
@@ -1,34 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Relation} from '@nozbe/watermelondb';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
/**
|
||||
* The GroupsTeam links the Team model with the Group model
|
||||
*/
|
||||
export default class GroupsTeamModel extends Model {
|
||||
/** table (name) : GroupsTeam */
|
||||
static table: string;
|
||||
|
||||
/** associations : Describes every relationship to this table. */
|
||||
static associations: Associations;
|
||||
|
||||
/** group_id : The foreign key to the related Group record */
|
||||
groupId: string;
|
||||
|
||||
/** member_count : The number of users in the group */
|
||||
memberCount: number;
|
||||
|
||||
/** team_id : The foreign key to the related Team record */
|
||||
teamId: string;
|
||||
|
||||
/** timezone_count : The number of timezones */
|
||||
timezoneCount: number;
|
||||
|
||||
/** team : The related record to the parent Team model */
|
||||
team: Relation<TeamModel>;
|
||||
|
||||
/** group : The related record to the parent Team model */
|
||||
group: Relation<GroupModel>;
|
||||
}
|
||||
3
types/database/models/servers/team.d.ts
vendored
3
types/database/models/servers/team.d.ts
vendored
@@ -44,9 +44,6 @@ export default class TeamModel extends Model {
|
||||
/** channels : All the channels associated with this team */
|
||||
channels: Query<ChannelModel>;
|
||||
|
||||
/** groupsTeam : All the groups associated with this team */
|
||||
groupsTeam: Query<GroupsTeamModel>;
|
||||
|
||||
/** myTeam : Retrieves additional information about the team that this user is possibly part of. This query might yield no result if the user isn't part of a team. */
|
||||
myTeam: Relation<MyTeamModel>;
|
||||
|
||||
|
||||
3
types/database/models/servers/user.d.ts
vendored
3
types/database/models/servers/user.d.ts
vendored
@@ -76,9 +76,6 @@ export default class UserModel extends Model {
|
||||
/** channels : All the channels that this user is part of */
|
||||
channels: Query<ChannelMembershipModel>;
|
||||
|
||||
/** groups : All the groups that this user is part of */
|
||||
groups: Query<GroupMembershipModel>;
|
||||
|
||||
/** posts : All the posts that this user has written*/
|
||||
posts: Query<PostModel>;
|
||||
|
||||
|
||||
20
types/database/raw_values.d.ts
vendored
20
types/database/raw_values.d.ts
vendored
@@ -23,22 +23,6 @@ type Draft = {
|
||||
root_id: string;
|
||||
};
|
||||
|
||||
type GroupMembership = {
|
||||
id?: string;
|
||||
user_id: string;
|
||||
group_id: string;
|
||||
};
|
||||
|
||||
type GroupChannelRelation = {
|
||||
channel_id: string;
|
||||
group_id: string;
|
||||
}
|
||||
|
||||
type GroupTeamRelation = {
|
||||
group_id: string;
|
||||
team_id: string;
|
||||
}
|
||||
|
||||
type MyTeam = {
|
||||
id: string;
|
||||
roles: string;
|
||||
@@ -104,10 +88,6 @@ type RawValue =
|
||||
| CustomEmoji
|
||||
| Draft
|
||||
| FileInfo
|
||||
| Group
|
||||
| GroupMembership
|
||||
| GroupChannel
|
||||
| GroupTeam
|
||||
| IdValue
|
||||
| Metadata
|
||||
| MyTeam
|
||||
|
||||
Reference in New Issue
Block a user