diff --git a/src/script/main/app.ts b/src/script/main/app.ts index e280d013c88..b84c9c6aa7c 100644 --- a/src/script/main/app.ts +++ b/src/script/main/app.ts @@ -415,7 +415,7 @@ export class App { onProgress(10); telemetry.timeStep(AppInitTimingsStep.INITIALIZED_CRYPTOGRAPHY); - const {members: teamMembers} = await teamRepository.initTeam(selfUser.teamId); + const teamMembers = await teamRepository.initTeam(selfUser.teamId); telemetry.timeStep(AppInitTimingsStep.RECEIVED_USER_DATA); const connections = await connectionRepository.getConnections(); diff --git a/src/script/team/TeamEntity.ts b/src/script/team/TeamEntity.ts index dc5a0dd28ae..43ad1c5bcaa 100644 --- a/src/script/team/TeamEntity.ts +++ b/src/script/team/TeamEntity.ts @@ -20,7 +20,6 @@ import ko from 'knockout'; import {AssetRemoteData} from '../assets/AssetRemoteData'; -import type {User} from '../entity/User'; import {assetV3} from '../util/ValidationUtil'; export class TeamEntity { @@ -30,14 +29,12 @@ export class TeamEntity { /** Team icon (asset key) */ iconKey?: string; id?: string; - members: ko.ObservableArray; name: ko.Observable; constructor(id?: string) { this.creator = undefined; this.icon = ''; this.iconKey = undefined; - this.members = ko.observableArray([]); this.id = id; this.name = ko.observable(''); } @@ -46,7 +43,7 @@ export class TeamEntity { let hasIcon = false; try { - hasIcon = this.icon && assetV3(this.icon); + hasIcon = !!this.icon && assetV3(this.icon); } catch (error) {} if (hasIcon) { diff --git a/src/script/team/TeamMapper.ts b/src/script/team/TeamMapper.ts index 7080095b688..d8439a9c29f 100644 --- a/src/script/team/TeamMapper.ts +++ b/src/script/team/TeamMapper.ts @@ -19,14 +19,10 @@ import type {MemberData, TeamData} from '@wireapp/api-client/lib/team/'; import type {TeamUpdateData} from '@wireapp/api-client/lib/team/data/'; -import type {PermissionsData} from '@wireapp/api-client/lib/team/member/PermissionsData'; import {TeamEntity} from './TeamEntity'; import {TeamMemberEntity} from './TeamMemberEntity'; -import type {User} from '../entity/User'; -import {roleFromTeamPermissions} from '../user/UserPermission'; - export class TeamMapper { mapTeamFromObject(data: TeamData, teamEntity?: TeamEntity): TeamEntity { return this.updateTeamFromObject(data, teamEntity); @@ -81,11 +77,4 @@ export class TeamMapper { return member; } - - mapRole(userEntity: User, permissions?: PermissionsData): void { - if (permissions) { - const teamRole = roleFromTeamPermissions(permissions); - userEntity.teamRole(teamRole); - } - } } diff --git a/src/script/team/TeamRepository.ts b/src/script/team/TeamRepository.ts index d6734d10c6f..776a315756b 100644 --- a/src/script/team/TeamRepository.ts +++ b/src/script/team/TeamRepository.ts @@ -30,6 +30,7 @@ import type { } from '@wireapp/api-client/lib/event'; import {TEAM_EVENT} from '@wireapp/api-client/lib/event/TeamEvent'; import {FeatureStatus, FeatureList} from '@wireapp/api-client/lib/team/feature/'; +import type {PermissionsData} from '@wireapp/api-client/lib/team/member/PermissionsData'; import type {TeamData} from '@wireapp/api-client/lib/team/team/TeamData'; import {QualifiedId} from '@wireapp/api-client/lib/user'; import {amplify} from 'amplify'; @@ -102,44 +103,44 @@ export class TeamRepository extends TypedEventEmitter { this.userRepository = userRepository; this.userRepository.getTeamMembersFromUsers = this.getTeamMembersFromUsers; - this.teamState.teamMembers.subscribe(() => this.userRepository.mapGuestStatus()); - - this.isSelfConnectedTo = userId => { - return ( - this.teamState.memberRoles()[userId] !== ROLE.PARTNER || - this.teamState.memberInviters()[userId] === this.userState.self().id - ); - }; amplify.subscribe(WebAppEvents.TEAM.EVENT_FROM_BACKEND, this.onTeamEvent); amplify.subscribe(WebAppEvents.EVENT.NOTIFICATION_HANDLING_STATE, this.updateTeamConfig); amplify.subscribe(WebAppEvents.TEAM.UPDATE_INFO, this.sendAccountInfo.bind(this)); } - readonly getRoleBadge = (userId: string): string => { + getRoleBadge(userId: string): string { return this.teamState.isExternal(userId) ? t('rolePartner') : ''; - }; + } - readonly isSelfConnectedTo = (userId: string): boolean => { + isSelfConnectedTo(userId: string): boolean { return ( this.teamState.memberRoles()[userId] !== ROLE.PARTNER || this.teamState.memberInviters()[userId] === this.userState.self().id ); - }; + } - initTeam = async ( - teamId?: string, - ): Promise<{team: TeamEntity; members: QualifiedId[]} | {team: undefined; members: never[]}> => { + async initTeam(teamId?: string): Promise { const team = await this.getTeam(); // get the fresh feature config from backend await this.updateFeatureConfig(); if (!teamId) { - return {team: undefined, members: []}; + return []; } + this.teamState.teamMembers.subscribe(members => { + // Subscribe to team members change and update the user role and guest status + this.userRepository.mapGuestStatus(members); + const roles = this.teamState.memberRoles(); + members.forEach(user => { + if (roles[user.id]) { + user.teamRole(roles[user.id]); + } + }); + }); const members = await this.loadTeamMembers(team); this.scheduleTeamRefresh(); - return {team, members}; - }; + return members; + } private async updateFeatureConfig(): Promise<{newFeatureList: FeatureList; prevFeatureList?: FeatureList}> { const prevFeatureList = this.teamState.teamFeatures(); @@ -185,7 +186,7 @@ export class TeamRepository extends TypedEventEmitter { async getSelfMember(teamId: string): Promise { const memberEntity = await this.getTeamMember(teamId, this.userState.self().id); - this.teamMapper.mapRole(this.userState.self(), memberEntity.permissions); + this.updateUserRole(this.userState.self(), memberEntity.permissions); return memberEntity; } @@ -201,7 +202,7 @@ export class TeamRepository extends TypedEventEmitter { return this.teamService.conversationHasGuestLink(conversationId); } - getTeamMembersFromUsers = async (users: User[]): Promise => { + private getTeamMembersFromUsers = async (users: User[]): Promise => { const selfTeamId = this.userState.self().teamId; if (!selfTeamId) { return; @@ -337,18 +338,8 @@ export class TeamRepository extends TypedEventEmitter { this.teamState.memberRoles({}); this.teamState.memberInviters({}); } - const userEntities = await this.userRepository.getUsersById( - memberIds.map(memberId => ({domain: this.teamState.teamDomain(), id: memberId})), - ); - if (append) { - const knownUserIds = teamEntity.members().map(({id}) => id); - const newUserEntities = userEntities.filter(({id}) => !knownUserIds.includes(id)); - teamEntity.members.push(...newUserEntities); - } else { - teamEntity.members(userEntities); - } - this.updateMemberRoles(teamEntity, mappedMembers); + this.updateMemberRoles(mappedMembers); } private async loadTeamMembers(teamEntity: TeamEntity): Promise { @@ -356,20 +347,12 @@ export class TeamRepository extends TypedEventEmitter { this.teamState.memberRoles({}); this.teamState.memberInviters({}); - this.updateMemberRoles(teamEntity, teamMembers); + this.updateMemberRoles(teamMembers); return teamMembers .filter(({userId}) => userId !== this.userState.self().id) .map(memberEntity => ({domain: this.teamState.teamDomain() ?? '', id: memberEntity.userId})); } - private addUserToTeam(userEntity: User): void { - const members = this.teamState.team().members; - - if (!members().find(member => member.id === userEntity.id)) { - members.push(userEntity); - } - } - private getTeamById(teamId: string): Promise { return this.teamService.getTeamById(teamId); } @@ -391,7 +374,7 @@ export class TeamRepository extends TypedEventEmitter { amplify.publish(WebAppEvents.CONVERSATION.DELETE, {domain: '', id: conversationId}); } - private _onMemberJoin(eventJson: TeamMemberJoinEvent): void { + private async _onMemberJoin(eventJson: TeamMemberJoinEvent) { const { data: {user: userId}, team: teamId, @@ -400,10 +383,9 @@ export class TeamRepository extends TypedEventEmitter { const isOtherUser = this.userState.self().id !== userId; if (isLocalTeam && isOtherUser) { - this.userRepository - .getUserById({domain: this.userState.self().domain, id: userId}) - .then(userEntity => this.addUserToTeam(userEntity)); - this.getTeamMember(teamId, userId).then(member => this.updateMemberRoles(this.teamState.team(), [member])); + await this.userRepository.getUserById({domain: this.userState.self().domain, id: userId}); + const member = await this.getTeamMember(teamId, userId); + this.updateMemberRoles([member]); } } @@ -443,7 +425,6 @@ export class TeamRepository extends TypedEventEmitter { return this.onDelete(eventJson); } - this.teamState.team().members.remove(member => member.id === userId); amplify.publish(WebAppEvents.TEAM.MEMBER_LEAVE, teamId, {domain: '', id: userId}, new Date(time).toISOString()); } } @@ -454,34 +435,36 @@ export class TeamRepository extends TypedEventEmitter { team: teamId, } = eventJson; const isLocalTeam = this.teamState.team().id === teamId; + if (!isLocalTeam) { + return; + } + const isSelfUser = this.userState.self().id === userId; - if (isLocalTeam && isSelfUser) { + if (isSelfUser) { const memberEntity = permissions ? {permissions} : await this.getTeamMember(teamId, userId); - this.teamMapper.mapRole(this.userState.self(), memberEntity.permissions); + this.updateUserRole(this.userState.self(), memberEntity.permissions); await this.sendAccountInfo(); - } - if (isLocalTeam && !isSelfUser) { + } else { const member = await this.getTeamMember(teamId, userId); - this.updateMemberRoles(this.teamState.team(), [member]); + this.updateMemberRoles([member]); } } - private updateMemberRoles(team: TeamEntity, members: TeamMemberEntity[] = []): void { - members.forEach(member => { - const user = team.members().find(({id}) => member.userId === id); - if (user) { - this.teamMapper.mapRole(user, member.permissions); - } - }); + private updateUserRole(user: User, permissions: PermissionsData): void { + user.teamRole(roleFromTeamPermissions(permissions)); + } + private updateMemberRoles(members: TeamMemberEntity[] = []): void { const memberRoles = members.reduce((accumulator, member) => { accumulator[member.userId] = member.permissions ? roleFromTeamPermissions(member.permissions) : ROLE.INVALID; return accumulator; }, this.teamState.memberRoles()); const memberInvites = members.reduce((accumulator, member) => { - accumulator[member.userId] = member.invitedBy; + if (member.invitedBy) { + accumulator[member.userId] = member.invitedBy; + } return accumulator; }, this.teamState.memberInviters()); diff --git a/src/script/team/TeamState.ts b/src/script/team/TeamState.ts index e5998d53175..26f76802467 100644 --- a/src/script/team/TeamState.ts +++ b/src/script/team/TeamState.ts @@ -33,8 +33,8 @@ import {UserState} from '../user/UserState'; @singleton() export class TeamState { public readonly isTeamDeleted: ko.Observable; - public readonly memberInviters: ko.Observable; - public readonly memberRoles: ko.Observable; + public readonly memberInviters: ko.Observable>; + public readonly memberRoles: ko.Observable>; public readonly supportsLegalHold: ko.Observable; public readonly teamName: ko.PureComputed; public readonly teamFeatures: ko.Observable; @@ -138,7 +138,7 @@ export class TeamState { return !!team.id && entity.domain === this.teamDomain() && entity.teamId === team.id; } - readonly isExternal = (userId: string): boolean => { + isExternal(userId: string): boolean { return this.memberRoles()[userId] === ROLE.PARTNER; - }; + } }