Skip to content

Commit

Permalink
refactor: Use UserEntities to get clients by user (#10923)
Browse files Browse the repository at this point in the history
  • Loading branch information
ffflorian authored Apr 20, 2021
1 parent 2cfa23e commit 32a74bf
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 113 deletions.
15 changes: 8 additions & 7 deletions src/script/client/ClientRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*
*/

import {ClientClassification, ClientType} from '@wireapp/api-client/src/client/';
import {ClientClassification, ClientType, PublicClient, QualifiedPublicClients} from '@wireapp/api-client/src/client/';
import {StatusCodes as HTTP_STATUS} from 'http-status-codes';
import {Runtime} from '@wireapp/commons';

Expand Down Expand Up @@ -47,16 +47,14 @@ describe('ClientRepository', () => {

testFactory.client_repository['clientState'].currentClient(client);

/** @type {import('@wireapp/api-client/src/client').PublicClient[]} */
const allClients = [
const allClients: PublicClient[] = [
{class: ClientClassification.DESKTOP, id: '706f64373b1bcf79'},
{class: ClientClassification.PHONE, id: '809fd276d6709474'},
{class: ClientClassification.DESKTOP, id: '8e11e06549c8cf1a'},
{class: ClientClassification.TABLET, id: 'c411f97b139c818b'},
{class: ClientClassification.DESKTOP, id: 'cbf3ea49214702d8'},
];
/** @type {import('@wireapp/api-client/src/client').QualifiedPublicClients} */
const userClientMap = {
const userClientMap: QualifiedPublicClients = {
none: {
[entities.user.john_doe.id]: allClients,
},
Expand All @@ -65,8 +63,11 @@ describe('ClientRepository', () => {
Promise.resolve(userClientMap),
);

const clientEntities = await testFactory.client_repository.getClientsByUserIds([entities.user.john_doe.id]);
expect(clientEntities[entities.user.john_doe.id].length).toBe(allClients.length);
const clientEntities = await testFactory.client_repository.getClientsByUserIds(
[entities.user.john_doe.id],
false,
);
expect(clientEntities.none[entities.user.john_doe.id].length).toBe(allClients.length);
});
});

Expand Down
36 changes: 22 additions & 14 deletions src/script/client/ClientRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
*/

import ko from 'knockout';
import {ClientType, PublicClient, RegisteredClient} from '@wireapp/api-client/src/client/';
import {USER_EVENT, UserClientAddEvent, UserClientRemoveEvent} from '@wireapp/api-client/src/event/';
import {ClientType, PublicClient, QualifiedPublicClients, RegisteredClient} from '@wireapp/api-client/src/client/';
import {USER_EVENT, UserClientAddEvent, UserClientRemoveEvent} from '@wireapp/api-client/src/event';
import {QualifiedId} from '@wireapp/api-client/src/user/';
import {Runtime} from '@wireapp/commons';
import {amplify} from 'amplify';
import {WebAppEvents} from '@wireapp/webapp-events';
Expand All @@ -43,6 +44,8 @@ import {ClientError} from '../error/ClientError';
import {ClientRecord} from '../storage';
import {ClientState} from './ClientState';

export type QualifiedUserClientMap = {[domain: string]: {[userId: string]: ClientEntity[]}};

export class ClientRepository {
private readonly logger: Logger;
public selfUser: ko.Observable<User>;
Expand Down Expand Up @@ -342,29 +345,34 @@ export class ClientRepository {
* Retrieves meta information about all the clients of a given user.
* @note If you want to get very detailed information about the devices from the own user, then use `getClients()`.
*
* @param userId User ID to retrieve client information for
* @param userIds User IDs to retrieve client information for
* @param updateClients Automatically update the clients
* @returns Resolves with an array of client entities
*/
async getClientsByUserIds(userId: string[], updateClients: false): Promise<Record<string, PublicClient[]>>;
async getClientsByUserIds(userId: string[], updateClients?: boolean): Promise<Record<string, ClientEntity[]>>;
async getClientsByUserIds(userIds: (QualifiedId | string)[], updateClients: true): Promise<QualifiedUserClientMap>;
async getClientsByUserIds(userIds: (QualifiedId | string)[], updateClients: false): Promise<QualifiedPublicClients>;
async getClientsByUserIds(
userId: string[],
updateClients: boolean = true,
): Promise<Record<string, ClientEntity[]> | Record<string, PublicClient[]>> {
const userClientsMap = await this.clientService.getClientsByUserIds(userId);
userIds: (QualifiedId | string)[],
updateClients: boolean,
): Promise<QualifiedPublicClients | QualifiedUserClientMap> {
const userClientsMap = await this.clientService.getClientsByUserIds(userIds);

if (updateClients) {
const clientEntityMap: Record<string, ClientEntity[]> = {};
const clientEntityMap: QualifiedUserClientMap = {};
await Promise.all(
Object.entries(userClientsMap.none).map(async ([userId, clients]) => {
clientEntityMap[userId] = await this.updateClientsOfUserById(userId, clients);
}),
Object.entries(userClientsMap).map(([domain, userClientMap]) =>
Object.entries(userClientMap).map(async ([userId, clients]) => {
if (!clientEntityMap[domain]) {
clientEntityMap[domain] = {};
}
clientEntityMap[domain][userId] = await this.updateClientsOfUserById(userId, clients);
}),
),
);
return clientEntityMap;
}

return userClientsMap.none;
return userClientsMap;
}

private async getClientByUserIdFromDb(requestedUserId: string): Promise<ClientRecord[]> {
Expand Down
29 changes: 24 additions & 5 deletions src/script/client/ClientService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
*
*/

import type {NewClient, QualifiedPublicClients, RegisteredClient} from '@wireapp/api-client/src/client/';
import type {NewClient, QualifiedPublicClients, RegisteredClient} from '@wireapp/api-client/src/client';
import type {QualifiedId} from '@wireapp/api-client/src/user';
import {container} from 'tsyringe';

import {Logger, getLogger} from 'Util/Logger';
Expand Down Expand Up @@ -100,13 +101,31 @@ export class ClientService {
* @param userId ID of user to retrieve clients for
* @returns Resolves with the clients of a user
*/
async getClientsByUserIds(userIds: string[]): Promise<QualifiedPublicClients> {
const clients: QualifiedPublicClients = {none: {}};

for (const userId of userIds) {
async getClientsByUserIds(userIds: (QualifiedId | string)[]): Promise<QualifiedPublicClients> {
// Add 'none' as domain for non-federated users
let clients: QualifiedPublicClients = {none: {}};

const {qualifiedIds, stringIds} = userIds.reduce(
(result, userId) => {
if (typeof userId === 'string') {
result.stringIds.push(userId);
} else {
result.qualifiedIds.push(userId);
}
return result;
},
{qualifiedIds: [], stringIds: []},
);

for (const userId of stringIds) {
clients.none[userId] = await this.apiClient.user.api.getClients(userId);
}

if (qualifiedIds.length) {
const listedClients = await this.apiClient.user.api.postListClients(qualifiedIds);
clients = {...clients, ...listedClients};
}

return clients;
}

Expand Down
16 changes: 9 additions & 7 deletions src/script/components/userDevices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,15 @@ ko.components.register('user-devices', {
this.showDevicesNotFound = () => showDeviceList() && this.deviceMode() === FIND_MODE.NOT_FOUND;

clientRepository
.getClientsByUserIds([userEntity().id])
.then(clientEntityMap => {
for (const clientEntities of Object.values(clientEntityMap)) {
this.clientEntities(sortUserDevices(clientEntities));
const hasDevices = clientEntities.length > 0;
const deviceMode = hasDevices ? FIND_MODE.FOUND : FIND_MODE.NOT_FOUND;
this.deviceMode(deviceMode);
.getClientsByUserIds([userEntity().id], true)
.then(qualifiedUsersMap => {
for (const userClientMaps of Object.values(qualifiedUsersMap)) {
for (const clientEntities of Object.values(userClientMaps)) {
this.clientEntities(sortUserDevices(clientEntities));
const hasDevices = clientEntities.length > 0;
const deviceMode = hasDevices ? FIND_MODE.FOUND : FIND_MODE.NOT_FOUND;
this.deviceMode(deviceMode);
}
}
})
.catch(error => {
Expand Down
Loading

0 comments on commit 32a74bf

Please sign in to comment.