Files
workavia-drive/tdrive/frontend/src/app/features/users/api/user-api-client.ts
T
Montassar Ghanmy 84270a31e2 🕹 Manage root users
🕹 Manage root users
2023-08-28 09:23:52 +01:00

253 lines
7.1 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-explicit-any */
import { CompanyType } from '@features/companies/types/company';
import { UserPreferencesType, UserType } from '@features/users/types/user';
import Api from '../../global/framework/api-service';
import { TdriveService } from '../../global/framework/registry-decorator-service';
import { WebsocketRoom } from '../../global/types/websocket-types';
import WorkspaceAPIClient from '../../workspaces/api/workspace-api-client';
import CurrentUser from '../../../deprecated/user/CurrentUser';
import { setUserList } from '../hooks/use-user-list';
import Logger from 'features/global/framework/logger-service';
export type SearchContextType = {
scope: 'company' | 'workspace' | 'all';
companyId?: string;
workspaceId?: string;
};
type SearchUserApiResponse<T> = {
next_page_token: unknown;
resources: T[];
};
@TdriveService('UserAPIClientService')
class UserAPIClientService {
private readonly prefixUrl: string = '/internal/services/users/v1';
private realtime: Map<string, WebsocketRoom> = new Map();
private logger = Logger.getLogger('UserAPIClientService');
websocket(userId: string): WebsocketRoom {
return this.realtime.get(userId) || { room: '', token: '' };
}
/**
* Get users from their ID
*
* @param id
*/
private listBuffer: any[] = [];
async list(
users: string[] = [],
companyIds?: string[],
options?: { bufferize?: boolean; callback?: (res: UserType[]) => void },
): Promise<UserType[]> {
if (options?.bufferize) {
const isFirst = this.listBuffer.length === 0;
this.listBuffer = this.listBuffer.concat({
users: users,
companies: companyIds,
callback: options.callback,
});
if (isFirst) {
await new Promise(r => setTimeout(r, 100));
users = this.listBuffer.reduce(
(c, acc) => (Array.isArray(c.users) ? acc.concat(c.users) : []),
[],
);
companyIds = this.listBuffer.reduce(
(c, acc) => (Array.isArray(c.companies) ? acc.concat(c.companies) : []),
[],
);
const callbacks = this.listBuffer.reduce(
(c, acc) => (Array.isArray(acc) ? acc.push(c.callback) : []),
[],
);
this.listBuffer = [];
this.list(users, companyIds, {
bufferize: false,
callback: (res: UserType[]) => {
callbacks.forEach((b: (res: UserType[]) => void) => b && b(res));
},
});
}
return [];
}
const res = await new Promise<UserType[]>(resolve =>
Api.get(
`/internal/services/users/v1/users${users.length ? `?user_ids=${users.join(',')}` : ''}${
companyIds?.length ? `?company_ids=${companyIds.join(',')}` : ''
}`,
(res: { resources: UserType[] }): void => {
resolve(res.resources && res.resources.length ? res.resources : []);
},
),
);
if (options?.callback) options.callback(res);
//Update state management
setUserList(res);
return res;
}
async all(
companyId: string,
options?: { bufferize?: boolean; callback?: (res: UserType[]) => void },
): Promise<UserType[]> {
const res = await new Promise<UserType[]>(resolve =>
Api.post(
`/internal/services/users/v1/users/${companyId}/all`,
{
include_companies: true,
},
(res: { resources: UserType[] }): void => {
resolve(res.resources && res.resources.length ? res.resources : []);
},
),
);
if (options?.callback) options.callback(res);
return res;
}
async getCurrentUserCompanies(): Promise<CompanyType[]> {
return this.listCompanies(CurrentUser.get()?.id || '');
}
/**
* Get all the companies of the given user.
* If the user is not the current one, it will return the companies intersection.
*
* @param userId
* @returns
*/
async listCompanies(userId: string): Promise<CompanyType[]> {
return WorkspaceAPIClient.listCompanies(userId);
}
async getCurrent(disableJWTAuthentication = false): Promise<UserType> {
return Api.get<{ resource: UserType; websocket: WebsocketRoom }>(
'/internal/services/users/v1/users/me',
undefined,
false,
{ disableJWTAuthentication },
).then(result => {
if (!result?.resource?.id) {
throw new Error('User not found');
}
result.resource.id && this.realtime.set(result.resource.id, result.websocket);
return result.resource;
});
}
async getCompany(companyId: string): Promise<CompanyType> {
return Api.get<{ resource: CompanyType }>(
`/internal/services/users/v1/companies/${companyId}`,
).then(a => a.resource);
}
async logout() {
return Api.post('users/logout', {});
}
async updateUserStatus(user: string) {
await Api.post<{ resource: string }, { resource: UserType }>(`${this.prefixUrl}/users/me`, {
resource: user,
});
}
/**
* Legacy API, will have to be removed!
*
* @returns
*/
async _fetchCurrent(): Promise<UserType> {
return Api.post<{ timezone: number }, { data: UserType }>(
'users/current/get',
{ timezone: new Date().getTimezoneOffset() },
undefined,
false,
{ disableJWTAuthentication: true },
).then(result => result.data);
}
async search<T>(
query: string | undefined,
context: SearchContextType,
callback?: (users: T[]) => void,
) {
let result: T[] = [];
if (query === 'me') {
const currentUser = await this.getCurrent();
result = [
context.scope === 'workspace'
? ({ user: currentUser } as unknown as T)
: (currentUser as unknown as T),
...result,
];
} else {
result = await Api.get<SearchUserApiResponse<T>>(
this.getSearchUsersRoute(query, context),
).then(data => data.resources);
}
if (callback) callback(result);
this.logger.debug(
`Search by value "${query}" with options`,
context,
'Found',
result.length,
'users',
);
return result;
}
getSearchUsersRoute(query = '', context: SearchContextType) {
let route = '';
if (context.scope === 'company' || context.scope === 'all') {
route = `${this.prefixUrl}/users${
query.length
? `?include_companies=1&search=${encodeURIComponent(query)}${
context.companyId && context.scope === 'company'
? `&search_company_id=${context.companyId}`
: ''
}`
: ''
}`;
}
if (context.scope === 'workspace') {
const workspacePrefix = '/internal/services/workspaces/v1/companies';
route = `${workspacePrefix}/${context.companyId}/workspaces/${context.workspaceId}/users${
query.length > 0 ? `?search=${encodeURIComponent(query)}` : ''
}`;
}
return route;
}
setUserPreferences(partials: UserPreferencesType) {
return Api.post<Partial<UserPreferencesType>, Partial<UserPreferencesType>>(
`${this.prefixUrl}/users/me/preferences`,
{
...partials,
},
);
}
}
const UserAPIClient = new UserAPIClientService();
export default UserAPIClient;