feat: groups
This commit is contained in:
@@ -1,4 +1,11 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
AlbumGroupCreateAllDto,
|
||||
AlbumGroupDeleteAllDto,
|
||||
AlbumGroupResponseDto,
|
||||
AlbumGroupUpdateDto,
|
||||
mapAlbumGroup,
|
||||
} from 'src/dtos/album-group.dto';
|
||||
import {
|
||||
AddUsersDto,
|
||||
AlbumInfoDto,
|
||||
@@ -204,6 +211,38 @@ export class AlbumService extends BaseService {
|
||||
return results;
|
||||
}
|
||||
|
||||
async getGroups(auth: AuthDto, id: string): Promise<AlbumGroupResponseDto[]> {
|
||||
await this.requireAccess({ auth, permission: Permission.AlbumRead, ids: [id] });
|
||||
const albumGroups = await this.albumGroupRepository.getAll(id);
|
||||
return albumGroups.map((albumGroup) => mapAlbumGroup(albumGroup));
|
||||
}
|
||||
|
||||
async upsertGroups(auth: AuthDto, id: string, { groups }: AlbumGroupCreateAllDto): Promise<AlbumGroupResponseDto[]> {
|
||||
await this.requireAccess({ auth, permission: Permission.AlbumUpdate, ids: [id] });
|
||||
const albumGroups = await this.albumGroupRepository.createAll(id, groups);
|
||||
return albumGroups.map((albumGroup) => mapAlbumGroup(albumGroup));
|
||||
}
|
||||
|
||||
async removeGroups(auth: AuthDto, id: string, dto: AlbumGroupDeleteAllDto): Promise<void> {
|
||||
await this.requireAccess({ auth, permission: Permission.AlbumUpdate, ids: [id] });
|
||||
await this.albumGroupRepository.deleteAll(id, dto.groupIds);
|
||||
}
|
||||
|
||||
async updateGroup(
|
||||
auth: AuthDto,
|
||||
id: string,
|
||||
groupId: string,
|
||||
dto: AlbumGroupUpdateDto,
|
||||
): Promise<AlbumGroupResponseDto> {
|
||||
await this.requireAccess({ auth, permission: Permission.AlbumUpdate, ids: [id] });
|
||||
const exists = await this.albumGroupRepository.exists({ albumId: id, groupId });
|
||||
if (!exists) {
|
||||
throw new BadRequestException('Album group not found');
|
||||
}
|
||||
const albumGroup = await this.albumGroupRepository.update({ albumId: id, groupId }, { role: dto.role });
|
||||
return mapAlbumGroup(albumGroup);
|
||||
}
|
||||
|
||||
async addUsers(auth: AuthDto, id: string, { albumUsers }: AddUsersDto): Promise<AlbumResponseDto> {
|
||||
await this.requireAccess({ auth, permission: Permission.AlbumShare, ids: [id] });
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { StorageCore } from 'src/cores/storage.core';
|
||||
import { UserAdmin } from 'src/database';
|
||||
import { AccessRepository } from 'src/repositories/access.repository';
|
||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||
import { AlbumGroupRepository } from 'src/repositories/album-group.repository';
|
||||
import { AlbumUserRepository } from 'src/repositories/album-user.repository';
|
||||
import { AlbumRepository } from 'src/repositories/album.repository';
|
||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||
@@ -21,6 +22,8 @@ import { DownloadRepository } from 'src/repositories/download.repository';
|
||||
import { DuplicateRepository } from 'src/repositories/duplicate.repository';
|
||||
import { EmailRepository } from 'src/repositories/email.repository';
|
||||
import { EventRepository } from 'src/repositories/event.repository';
|
||||
import { GroupUserRepository } from 'src/repositories/group-user.repository';
|
||||
import { GroupRepository } from 'src/repositories/group.repository';
|
||||
import { JobRepository } from 'src/repositories/job.repository';
|
||||
import { LibraryRepository } from 'src/repositories/library.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
@@ -111,6 +114,7 @@ export class BaseService {
|
||||
protected accessRepository: AccessRepository,
|
||||
protected activityRepository: ActivityRepository,
|
||||
protected albumRepository: AlbumRepository,
|
||||
protected albumGroupRepository: AlbumGroupRepository,
|
||||
protected albumUserRepository: AlbumUserRepository,
|
||||
protected apiKeyRepository: ApiKeyRepository,
|
||||
protected assetRepository: AssetRepository,
|
||||
@@ -124,6 +128,8 @@ export class BaseService {
|
||||
protected duplicateRepository: DuplicateRepository,
|
||||
protected emailRepository: EmailRepository,
|
||||
protected eventRepository: EventRepository,
|
||||
protected groupRepository: GroupRepository,
|
||||
protected groupUserRepository: GroupUserRepository,
|
||||
protected jobRepository: JobRepository,
|
||||
protected libraryRepository: LibraryRepository,
|
||||
protected machineLearningRepository: MachineLearningRepository,
|
||||
|
||||
95
server/src/services/group-admin.service.ts
Normal file
95
server/src/services/group-admin.service.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { PostgresError } from 'postgres';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import {
|
||||
GroupUserCreateAllDto,
|
||||
GroupUserDeleteAllDto,
|
||||
GroupUserResponseDto,
|
||||
mapGroupUser,
|
||||
} from 'src/dtos/group-user.dto';
|
||||
import {
|
||||
GroupAdminCreateDto,
|
||||
GroupAdminResponseDto,
|
||||
GroupAdminSearchDto,
|
||||
GroupAdminUpdateDto,
|
||||
mapGroupAdmin,
|
||||
} from 'src/dtos/group.dto';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
|
||||
@Injectable()
|
||||
export class GroupAdminService extends BaseService {
|
||||
async search(auth: AuthDto, dto: GroupAdminSearchDto): Promise<GroupAdminResponseDto[]> {
|
||||
const groups = await this.groupRepository.search(dto);
|
||||
return groups.map((group) => mapGroupAdmin(group));
|
||||
}
|
||||
|
||||
async create(auth: AuthDto, dto: GroupAdminCreateDto): Promise<GroupAdminResponseDto> {
|
||||
try {
|
||||
const { users, ...groupDto } = dto;
|
||||
const group = await this.groupRepository.create(groupDto, users);
|
||||
return mapGroupAdmin(group);
|
||||
} catch (error) {
|
||||
this.handleError(error);
|
||||
}
|
||||
}
|
||||
|
||||
async get(auth: AuthDto, id: string): Promise<GroupAdminResponseDto> {
|
||||
const group = await this.findOrFail(id);
|
||||
return mapGroupAdmin(group);
|
||||
}
|
||||
|
||||
async update(auth: AuthDto, id: string, dto: GroupAdminUpdateDto): Promise<GroupAdminResponseDto> {
|
||||
await this.findOrFail(id);
|
||||
const updated = await this.groupRepository.update(id, { ...dto, updatedAt: new Date() });
|
||||
return mapGroupAdmin(updated);
|
||||
}
|
||||
|
||||
async delete(auth: AuthDto, id: string): Promise<void> {
|
||||
await this.findOrFail(id);
|
||||
await this.groupRepository.delete(id);
|
||||
}
|
||||
|
||||
async getUsers(auth: AuthDto, id: string): Promise<GroupUserResponseDto[]> {
|
||||
await this.findOrFail(id);
|
||||
const users = await this.groupUserRepository.getAll(id);
|
||||
return users.map((user) => mapGroupUser(user));
|
||||
}
|
||||
|
||||
async addUsers(auth: AuthDto, id: string, { users }: GroupUserCreateAllDto): Promise<GroupUserResponseDto[]> {
|
||||
await this.findOrFail(id);
|
||||
const userIds = users.map(({ userId }) => userId);
|
||||
const groupUsers = await this.groupUserRepository.createAll(id, userIds);
|
||||
return groupUsers.map((groupUser) => mapGroupUser(groupUser));
|
||||
}
|
||||
|
||||
async removeUsers(auth: AuthDto, id: string, dto: GroupUserDeleteAllDto): Promise<void> {
|
||||
await this.findOrFail(id);
|
||||
await this.groupUserRepository.deleteAll(id, dto.userIds);
|
||||
}
|
||||
|
||||
async removeUser(auth: AuthDto, id: string, userId: string): Promise<void> {
|
||||
await this.findOrFail(id);
|
||||
|
||||
const exists = await this.groupUserRepository.get({ groupId: id, userId });
|
||||
if (!exists) {
|
||||
throw new BadRequestException('Group does not include this user');
|
||||
}
|
||||
|
||||
await this.groupUserRepository.delete({ groupId: id, userId });
|
||||
}
|
||||
|
||||
private handleError(error: unknown): never {
|
||||
if ((error as PostgresError).constraint_name === 'group_name_uq') {
|
||||
throw new BadRequestException('Group with this name already exists');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
private async findOrFail(id: string) {
|
||||
const group = await this.groupRepository.get(id);
|
||||
if (!group) {
|
||||
throw new BadRequestException('Group not found');
|
||||
}
|
||||
return group;
|
||||
}
|
||||
}
|
||||
38
server/src/services/group.service.ts
Normal file
38
server/src/services/group.service.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { GroupUserResponseDto, mapGroupUser } from 'src/dtos/group-user.dto';
|
||||
import { GroupResponseDto, mapGroup } from 'src/dtos/group.dto';
|
||||
import { BaseService } from 'src/services/base.service';
|
||||
|
||||
@Injectable()
|
||||
export class GroupService extends BaseService {
|
||||
async search(auth: AuthDto): Promise<GroupResponseDto[]> {
|
||||
const groups = await this.groupRepository.search({ userId: auth.user.id });
|
||||
return groups.map((group) => mapGroup(group));
|
||||
}
|
||||
|
||||
async get(auth: AuthDto, id: string): Promise<GroupResponseDto> {
|
||||
const group = await this.findOrFail({ userId: auth.user.id, groupId: id });
|
||||
return mapGroup(group);
|
||||
}
|
||||
|
||||
async delete(auth: AuthDto, id: string): Promise<void> {
|
||||
await this.findOrFail({ userId: auth.user.id, groupId: id });
|
||||
await this.groupUserRepository.delete({ userId: auth.user.id, groupId: id });
|
||||
}
|
||||
|
||||
async getUsers(auth: AuthDto, id: string): Promise<GroupUserResponseDto[]> {
|
||||
await this.findOrFail({ userId: auth.user.id, groupId: id });
|
||||
const users = await this.groupUserRepository.getAll(id);
|
||||
return users.map((user) => mapGroupUser(user));
|
||||
}
|
||||
|
||||
async findOrFail({ userId, groupId }: { userId: string; groupId: string }): Promise<GroupResponseDto> {
|
||||
const [group] = await this.groupUserRepository.get({ userId, groupId });
|
||||
if (!group) {
|
||||
throw new BadRequestException('Group not found');
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ import { CliService } from 'src/services/cli.service';
|
||||
import { DatabaseService } from 'src/services/database.service';
|
||||
import { DownloadService } from 'src/services/download.service';
|
||||
import { DuplicateService } from 'src/services/duplicate.service';
|
||||
import { GroupAdminService } from 'src/services/group-admin.service';
|
||||
import { GroupService } from 'src/services/group.service';
|
||||
import { JobService } from 'src/services/job.service';
|
||||
import { LibraryService } from 'src/services/library.service';
|
||||
import { MapService } from 'src/services/map.service';
|
||||
@@ -54,6 +56,8 @@ export const services = [
|
||||
DatabaseService,
|
||||
DownloadService,
|
||||
DuplicateService,
|
||||
GroupAdminService,
|
||||
GroupService,
|
||||
JobService,
|
||||
LibraryService,
|
||||
MapService,
|
||||
|
||||
Reference in New Issue
Block a user