feat: user workspace stats api added (#4467) (HSB-495)

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
Mir Arif Hasan 2024-10-29 00:23:53 +06:00 committed by GitHub
parent 936c97b53a
commit 161e598809
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 109 additions and 3 deletions

View File

@ -28,6 +28,7 @@ import {
CreateUserInvitationRequest, CreateUserInvitationRequest,
CreateUserInvitationResponse, CreateUserInvitationResponse,
DeleteUserResponse, DeleteUserResponse,
GetUserWorkspacesResponse,
} from './request-response.dto'; } from './request-response.dto';
import * as E from 'fp-ts/Either'; import * as E from 'fp-ts/Either';
import * as O from 'fp-ts/Option'; import * as O from 'fp-ts/Option';
@ -104,9 +105,8 @@ export class InfraTokensController {
async getPendingUserInvitation( async getPendingUserInvitation(
@Query() paginationQuery: OffsetPaginationArgs, @Query() paginationQuery: OffsetPaginationArgs,
) { ) {
const pendingInvitedUsers = await this.adminService.fetchInvitedUsers( const pendingInvitedUsers =
paginationQuery, await this.adminService.fetchInvitedUsers(paginationQuery);
);
return plainToInstance(GetUserInvitationResponse, pendingInvitedUsers, { return plainToInstance(GetUserInvitationResponse, pendingInvitedUsers, {
excludeExtraneousValues: true, excludeExtraneousValues: true,
@ -275,4 +275,28 @@ export class InfraTokensController {
}, },
); );
} }
@Get('users/:uid/workspaces')
@ApiOkResponse({
description: 'Get user workspaces',
type: [GetUserWorkspacesResponse],
})
@ApiNotFoundResponse({ type: ExceptionResponse })
async getUserWorkspaces(@Param('uid') uid: string) {
const userWorkspaces = await this.userService.fetchUserWorkspaces(uid);
if (E.isLeft(userWorkspaces)) {
const statusCode =
userWorkspaces.left === USER_NOT_FOUND
? HttpStatus.NOT_FOUND
: HttpStatus.BAD_REQUEST;
throwHTTPErr({ message: userWorkspaces.left, statusCode });
}
return plainToInstance(GetUserWorkspacesResponse, userWorkspaces.right, {
excludeExtraneousValues: true,
enableImplicitConversion: true,
});
}
} }

View File

@ -10,6 +10,7 @@ import {
IsString, IsString,
MinLength, MinLength,
} from 'class-validator'; } from 'class-validator';
import { TeamMemberRole } from 'src/team/team.model';
import { OffsetPaginationArgs } from 'src/types/input-types.args'; import { OffsetPaginationArgs } from 'src/types/input-types.args';
// POST v1/infra/user-invitations // POST v1/infra/user-invitations
@ -128,3 +129,34 @@ export class DeleteUserResponse {
@Expose() @Expose()
message: string; message: string;
} }
// GET v1/infra/users/:uid/workspaces
export class GetUserWorkspacesResponse {
@ApiProperty()
@Expose()
id: string;
@ApiProperty()
@Expose()
name: string;
@ApiProperty({ enum: TeamMemberRole })
@Expose()
role: string;
@ApiProperty()
@Expose()
owner_count: number;
@ApiProperty()
@Expose()
editor_count: number;
@ApiProperty()
@Expose()
viewer_count: number;
@ApiProperty()
@Expose()
member_count: number;
}

View File

@ -20,6 +20,8 @@ import { encrypt, stringToJson, taskEitherValidateArraySeq } from 'src/utils';
import { UserDataHandler } from './user.data.handler'; import { UserDataHandler } from './user.data.handler';
import { User as DbUser } from '@prisma/client'; import { User as DbUser } from '@prisma/client';
import { OffsetPaginationArgs } from 'src/types/input-types.args'; import { OffsetPaginationArgs } from 'src/types/input-types.args';
import { GetUserWorkspacesResponse } from 'src/infra-token/request-response.dto';
import { TeamMemberRole } from 'src/team/team.model';
@Injectable() @Injectable()
export class UserService { export class UserService {
@ -598,4 +600,52 @@ export class UserService {
return E.right(true); return E.right(true);
} }
async fetchUserWorkspaces(userUid: string) {
const user = await this.prisma.user.findUnique({ where: { uid: userUid } });
if (!user) return E.left(USER_NOT_FOUND);
const team = await this.prisma.team.findMany({
where: {
members: {
some: {
userUid,
},
},
},
include: {
members: {
select: {
userUid: true,
role: true,
},
},
},
});
const workspaces: GetUserWorkspacesResponse[] = [];
team.forEach((t) => {
const ownerCount = t.members.filter(
(m) => m.role === TeamMemberRole.OWNER,
).length;
const editorCount = t.members.filter(
(m) => m.role === TeamMemberRole.EDITOR,
).length;
const viewerCount = t.members.filter(
(m) => m.role === TeamMemberRole.VIEWER,
).length;
const memberCount = t.members.length;
workspaces.push({
id: t.id,
name: t.name,
role: t.members.find((m) => m.userUid === userUid)?.role,
owner_count: ownerCount,
editor_count: editorCount,
viewer_count: viewerCount,
member_count: memberCount,
});
});
return E.right(workspaces);
}
} }