feat: groups

This commit is contained in:
Philipinho
2024-03-05 16:22:24 +00:00
parent 181bd78951
commit 528b9d70b1
21 changed files with 596 additions and 7 deletions

View File

@ -0,0 +1,121 @@
import {
BadRequestException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { DataSource, EntityManager } from 'typeorm';
import { GroupUserRepository } from '../respositories/group-user.repository';
import { PaginationOptions } from '../../../helpers/pagination/pagination-options';
import {
WorkspaceUser,
WorkspaceUserRole,
} from '../../workspace/entities/workspace-user.entity';
import { transactionWrapper } from '../../../helpers/db.helper';
import { User } from '../../user/entities/user.entity';
import { GroupUser } from '../entities/group-user.entity';
import { PaginationMetaDto } from '../../../helpers/pagination/pagination-meta-dto';
import { PaginatedResult } from '../../../helpers/pagination/paginated-result';
@Injectable()
export class GroupUserService {
constructor(
private groupUserRepository: GroupUserRepository,
private dataSource: DataSource,
) {}
async getGroupUsers(
groupId,
workspaceId: string,
paginationOptions: PaginationOptions,
): Promise<PaginatedResult<User>> {
const [groupUsers, count] = await this.groupUserRepository.findAndCount({
relations: ['user'],
where: {
group: {
workspaceId: workspaceId,
},
},
take: paginationOptions.limit,
skip: paginationOptions.skip,
});
const users = groupUsers.map((groupUser: GroupUser) => groupUser.user);
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
return new PaginatedResult(users, paginationMeta);
}
async addUserToGroup(
userId: string,
groupId: string,
workspaceId: string,
manager?: EntityManager,
): Promise<WorkspaceUser> {
let addedUser;
await transactionWrapper(
async (manager) => {
// TODO: make duplicate code reusable
const userExists = await manager.exists(User, {
where: { id: userId },
});
if (!userExists) {
throw new NotFoundException('User not found');
}
// only workspace users can be added to workspace groups
const workspaceUser = await manager.findOneBy(WorkspaceUser, {
userId: userId,
workspaceId: workspaceId,
});
if (!workspaceUser) {
throw new NotFoundException('User is not a member of this workspace');
}
const existingGroupUser = await manager.findOneBy(GroupUser, {
userId: userId,
groupId: groupId,
});
if (existingGroupUser) {
throw new BadRequestException(
'User is already a member of this group',
);
}
const groupUser = new GroupUser();
groupUser.userId = userId;
groupUser.groupId = groupId;
addedUser = await manager.save(groupUser);
},
this.dataSource,
manager,
);
return addedUser;
}
async removeUserFromGroup(userId: string, groupId: string): Promise<void> {
const groupUser = await this.findGroupUser(userId, groupId);
if (!groupUser) {
throw new BadRequestException('Group member not found');
}
await this.groupUserRepository.delete({
userId,
groupId,
});
}
async findGroupUser(userId: string, groupId: string): Promise<GroupUser> {
return await this.groupUserRepository.findOneBy({
userId,
groupId,
});
}
}

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { GroupService } from './group.service';
describe('GroupService', () => {
let service: GroupService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [GroupService],
}).compile();
service = module.get<GroupService>(GroupService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -0,0 +1,82 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateGroupDto } from '../dto/create-group.dto';
import { GroupRepository } from '../respositories/group.repository';
import { Group } from '../entities/group.entity';
import { plainToInstance } from 'class-transformer';
import { User } from '../../user/entities/user.entity';
import { PaginationMetaDto } from '../../../helpers/pagination/pagination-meta-dto';
import { PaginatedResult } from '../../../helpers/pagination/paginated-result';
import { PaginationOptions } from '../../../helpers/pagination/pagination-options';
import { UpdateGroupDto } from '../dto/update-group.dto';
@Injectable()
export class GroupService {
constructor(private groupRepository: GroupRepository) {}
async createGroup(
authUser: User,
workspaceId: string,
createGroupDto: CreateGroupDto,
): Promise<Group> {
const group = plainToInstance(Group, createGroupDto);
group.creatorId = authUser.id;
group.workspaceId = workspaceId;
return await this.groupRepository.save(group);
}
async updateGroup(
workspaceId: string,
updateGroupDto: UpdateGroupDto,
): Promise<Group> {
const group = new Group();
if (updateGroupDto.name) {
group.name = updateGroupDto.name;
}
if (updateGroupDto.description) {
group.description = updateGroupDto.description;
}
return await this.groupRepository.save(group);
}
async getGroup(groupId: string, workspaceId: string): Promise<Group> {
const group = await this.groupRepository.findOneBy({
id: groupId,
workspaceId: workspaceId,
});
//TODO: get group member count
if (!group) {
throw new NotFoundException('Group not found');
}
return group;
}
async getGroupsInWorkspace(
workspaceId: string,
paginationOptions: PaginationOptions,
): Promise<PaginatedResult<Group>> {
const [groupsInWorkspace, count] = await this.groupRepository.findAndCount({
where: {
workspaceId: workspaceId,
},
take: paginationOptions.limit,
skip: paginationOptions.skip,
});
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
return new PaginatedResult(groupsInWorkspace, paginationMeta);
}
async deleteGroup(groupId: string, workspaceId: string) {
await this.getGroup(groupId, workspaceId);
await this.groupRepository.delete(groupId);
}
}