Properly sync teams (#5793)

This commit is contained in:
Elias Nahum
2021-10-26 20:48:09 -03:00
committed by GitHub
parent 884dcb1789
commit 458a006cde
4 changed files with 50 additions and 23 deletions

View File

@@ -279,6 +279,7 @@ const fetchAppEntryData = async (serverUrl: string, initialTeamId: string): Prom
fetchMe(serverUrl, fetchOnly),
];
const removeTeamIds: string[] = [];
const resolution = await Promise.all(promises);
const [teamData, , prefData, meData] = resolution;
let [, chData] = resolution;
@@ -287,7 +288,7 @@ const fetchAppEntryData = async (serverUrl: string, initialTeamId: string): Prom
// If no initial team was set in the database but got teams in the response
const config = await queryConfig(database);
const teamOrderPreference = getPreferenceValue(prefData.preferences || [], Preferences.TEAMS_ORDER, '', '') as string;
const teamMembers = teamData.memberships.map((m) => m.team_id);
const teamMembers = teamData.memberships.filter((m) => m.delete_at === 0).map((m) => m.team_id);
const myTeams = teamData.teams!.filter((t) => teamMembers?.includes(t.id));
const defaultTeam = selectDefaultTeam(myTeams, meData.user?.locale || DEFAULT_LOCALE, teamOrderPreference, config.ExperimentalPrimaryTeam);
if (defaultTeam?.id) {
@@ -295,18 +296,24 @@ const fetchAppEntryData = async (serverUrl: string, initialTeamId: string): Prom
}
}
const removedFromTeam = teamData.memberships?.filter((m) => m.delete_at > 0);
if (removedFromTeam?.length) {
removeTeamIds.push(...removedFromTeam.map((m) => m.team_id));
}
let data: AppEntryData = {
initialTeamId,
teamData,
chData,
prefData,
meData,
removeTeamIds,
};
if (teamData.teams?.length === 0) {
// User is no longer a member of any team
const myTeams = await queryMyTeams(database);
const removeTeamIds: string[] = myTeams?.map((myTeam) => myTeam.id) || [];
removeTeamIds.push(...(myTeams?.map((myTeam) => myTeam.id) || []));
return {
...data,
@@ -319,7 +326,9 @@ const fetchAppEntryData = async (serverUrl: string, initialTeamId: string): Prom
const chError = chData?.error as ClientError | undefined;
if (!inTeam || chError?.status_code === 403) {
// User is no longer a member of the current team
const removeTeamIds = [initialTeamId];
if (!removeTeamIds.includes(initialTeamId)) {
removeTeamIds.push(initialTeamId);
}
const availableTeamIds = await queryAvailableTeamIds(database, initialTeamId, teamData.teams, prefData.preferences, meData.user?.locale);
const alternateTeamData = await fetchAlternateTeamData(serverUrl, availableTeamIds, removeTeamIds, includeDeletedChannels, lastDisconnected, fetchOnly);

View File

@@ -8,7 +8,7 @@ import DatabaseManager from '@database/manager';
import NetworkManager from '@init/network_manager';
import {prepareMyChannelsForTeam, queryDefaultChannelForTeam} from '@queries/servers/channel';
import {queryWebSocketLastDisconnected} from '@queries/servers/system';
import {prepareMyTeams, syncTeamTable} from '@queries/servers/team';
import {prepareDeleteTeam, prepareMyTeams, queryTeamsById, syncTeamTable} from '@queries/servers/team';
import {isTablet} from '@utils/helpers';
import {fetchMyChannelsForTeam} from './channel';
@@ -92,10 +92,23 @@ export const fetchMyTeams = async (serverUrl: string, fetchOnly = false): Promis
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
const modelPromises: Array<Promise<Model[]>> = [];
if (operator) {
const prepare = prepareMyTeams(operator, teams, memberships);
const removeTeamIds = memberships.filter((m) => m.delete_at > 0).map((m) => m.team_id);
const remainingTeams = teams.filter((t) => !removeTeamIds.includes(t.id));
const prepare = prepareMyTeams(operator, remainingTeams, memberships);
if (prepare) {
modelPromises.push(...prepare);
}
if (removeTeamIds.length) {
if (removeTeamIds?.length) {
// Immediately delete myTeams so that the UI renders only teams the user is a member of.
const removeTeams = await queryTeamsById(operator.database, removeTeamIds);
removeTeams?.forEach((team) => {
modelPromises.push(prepareDeleteTeam(team));
});
}
}
if (modelPromises.length) {
const models = await Promise.all(modelPromises);
const flattenedModels = models.flat() as Model[];

View File

@@ -22,18 +22,17 @@ import type UserModel from '@typings/database/models/servers/user';
const {SERVER: {SYSTEM, MY_TEAM, TEAM, USER, ROLE}} = MM_TABLES;
type PropsInput = WithDatabaseArgs & {
currentUser: UserModel;
}
const enhanced = 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 rolesArray = currentUser.pipe(
switchMap((u) => of$(u.roles.split(' '))),
);
const roles = rolesArray.pipe(
switchMap((values) => database.get<RoleModel>(ROLE).query(Q.where('name', Q.oneOf(values))).observe()),
);
const withSystem = withObservables([], ({database}: WithDatabaseArgs) => ({
currentUser: database.get(SYSTEM).findAndObserve(SYSTEM_IDENTIFIERS.CURRENT_USER_ID).pipe(
switchMap((currentUserId: SystemModel) => database.get(USER).findAndObserve(currentUserId.value))),
}));
const withTeams = withObservables([], ({currentUser, database}: PropsInput) => {
const rolesArray = [...currentUser.roles.split(' ')];
const roles = database.get<RoleModel>(ROLE).query(Q.where('name', Q.oneOf(rolesArray))).observe();
const canCreateTeams = roles.pipe(switchMap((r) => of$(hasPermission(r, Permissions.CREATE_TEAM, false))));
const otherTeams = database.get<MyTeam>(MY_TEAM).query().observe().pipe(
@@ -50,4 +49,4 @@ const withTeams = withObservables([], ({currentUser, database}: PropsInput) => {
};
});
export default withDatabase(withSystem(withTeams(TeamSidebar)));
export default withDatabase(enhanced(TeamSidebar));

View File

@@ -130,13 +130,19 @@ export const queryLastTeam = async (database: Database) => {
export const syncTeamTable = async (operator: ServerDataOperator, teams: Team[]) => {
try {
const notAvailable = await operator.database.get<TeamModel>(TEAM).query(Q.where('id', Q.notIn(teams.map((t) => t.id)))).fetch();
const deletedTeams = teams.filter((t) => t.delete_at > 0).map((t) => t.id);
const availableTeams = teams.filter((a) => !deletedTeams.includes(a.id));
const models = [];
const deletions = await Promise.all(notAvailable.map((t) => prepareDeleteTeam(t)));
for (const d of deletions) {
models.push(...d);
if (deletedTeams.length) {
const notAvailable = await operator.database.get<TeamModel>(TEAM).query(Q.where('id', Q.oneOf(deletedTeams))).fetch();
const deletions = await Promise.all(notAvailable.map((t) => prepareDeleteTeam(t)));
for (const d of deletions) {
models.push(...d);
}
}
models.push(...await operator.handleTeam({teams, prepareRecordsOnly: true}));
models.push(...await operator.handleTeam({teams: availableTeams, prepareRecordsOnly: true}));
await operator.batchRecords(models);
return {};
} catch (error) {
@@ -163,7 +169,7 @@ export const queryDefaultTeam = async (database: Database) => {
export const prepareMyTeams = (operator: ServerDataOperator, teams: Team[], memberships: TeamMembership[]) => {
try {
const teamRecords = operator.handleTeam({prepareRecordsOnly: true, teams});
const teamMemberships = memberships.filter((m) => teams.find((t) => t.id === m.team_id));
const teamMemberships = memberships.filter((m) => teams.find((t) => t.id === m.team_id) && m.delete_at === 0);
const teamMembershipRecords = operator.handleTeamMemberships({prepareRecordsOnly: true, teamMemberships});
const myTeams: MyTeam[] = teamMemberships.map((tm) => {
return {id: tm.team_id, roles: tm.roles ?? ''};