| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- import { Injectable, NotFoundException, Inject, forwardRef } from '@nestjs/common';
- import { I18nService } from '../i18n/i18n.service';
- import { InjectRepository } from '@nestjs/typeorm';
- import { Repository } from 'typeorm';
- import { KnowledgeGroup } from './knowledge-group.entity';
- import { KnowledgeBase } from '../knowledge-base/knowledge-base.entity';
- import { KnowledgeBaseService } from '../knowledge-base/knowledge-base.service';
- export interface CreateGroupDto {
- name: string;
- description?: string;
- color?: string;
- }
- export interface UpdateGroupDto {
- name?: string;
- description?: string;
- color?: string;
- }
- export interface GroupWithFileCount {
- id: string;
- name: string;
- description?: string;
- color: string;
- fileCount: number;
- createdAt: Date;
- }
- @Injectable()
- export class KnowledgeGroupService {
- constructor(
- @InjectRepository(KnowledgeGroup)
- private groupRepository: Repository<KnowledgeGroup>,
- @InjectRepository(KnowledgeBase)
- private knowledgeBaseRepository: Repository<KnowledgeBase>,
- @Inject(forwardRef(() => KnowledgeBaseService))
- private knowledgeBaseService: KnowledgeBaseService,
- private i18nService: I18nService,
- ) { }
- async findAll(userId: string, tenantId: string): Promise<GroupWithFileCount[]> {
- // Return all groups for the tenant
- const groups = await this.groupRepository
- .createQueryBuilder('group')
- .leftJoin('group.knowledgeBases', 'kb')
- .where('group.tenantId = :tenantId', { tenantId })
- .addSelect('COUNT(kb.id)', 'fileCount')
- .groupBy('group.id')
- .orderBy('group.createdAt', 'DESC')
- .getRawAndEntities();
- return groups.entities.map((group, index) => ({
- id: group.id,
- name: group.name,
- description: group.description,
- color: group.color,
- fileCount: parseInt(groups.raw[index].fileCount) || 0,
- createdAt: group.createdAt,
- }));
- }
- async findOne(id: string, userId: string, tenantId: string): Promise<KnowledgeGroup> {
- // Restrict group to tenant
- const group = await this.groupRepository.findOne({
- where: { id, tenantId },
- relations: ['knowledgeBases'],
- });
- if (!group) {
- throw new NotFoundException(this.i18nService.getMessage('groupNotFound'));
- }
- return group;
- }
- async create(userId: string, tenantId: string, createGroupDto: CreateGroupDto): Promise<KnowledgeGroup> {
- const group = this.groupRepository.create({
- ...createGroupDto,
- tenantId,
- });
- return await this.groupRepository.save(group);
- }
- async update(id: string, userId: string, tenantId: string, updateGroupDto: UpdateGroupDto): Promise<KnowledgeGroup> {
- // Update group within the tenant
- const group = await this.groupRepository.findOne({
- where: { id, tenantId },
- });
- if (!group) {
- throw new NotFoundException(this.i18nService.getMessage('groupNotFound'));
- }
- Object.assign(group, updateGroupDto);
- return await this.groupRepository.save(group);
- }
- async remove(id: string, userId: string, tenantId: string): Promise<void> {
- // Remove group within the tenant
- const group = await this.groupRepository.findOne({
- where: { id, tenantId },
- });
- if (!group) {
- throw new NotFoundException(this.i18nService.getMessage('groupNotFound'));
- }
- // Find all files associated with this group (without user restriction)
- const files = await this.knowledgeBaseRepository
- .createQueryBuilder('kb')
- .innerJoin('kb.groups', 'group')
- .where('group.id = :groupId', { groupId: id })
- .select('kb.id')
- .getMany();
- // Delete each file
- for (const file of files) {
- try {
- // We need to get the file's owner to delete it properly
- const fullFile = await this.knowledgeBaseRepository.findOne({
- where: { id: file.id },
- select: ['id', 'userId', 'tenantId'] // Get the owner of the file
- });
- if (fullFile) {
- await this.knowledgeBaseService.deleteFile(fullFile.id, fullFile.userId, fullFile.tenantId as string);
- }
- } catch (error) {
- console.error(`Failed to delete file ${file.id} when deleting group ${id}`, error);
- }
- }
- // Delete notes in this group - call the findAll method with groupId parameter only
- // We'll fetch notes for the group without userId restriction
- // For this, we'll call the note service differently
- // Actually, we need to think about this carefully
- // Notes belong to users, so we can't remove notes from other users' groups
- // We'll just remove the group from the association
- // Or fetch notes by groupId only (need to modify note service)
- // Since note service is user-restricted, let's only handle file removal
- // and leave note management to users individually
- // Delete the group itself
- await this.groupRepository.remove(group);
- }
- async getGroupFiles(groupId: string, userId: string, tenantId: string): Promise<KnowledgeBase[]> {
- const group = await this.groupRepository.findOne({
- where: { id: groupId, tenantId },
- relations: ['knowledgeBases'],
- });
- if (!group) {
- throw new NotFoundException(this.i18nService.getMessage('groupNotFound'));
- }
- return group.knowledgeBases;
- }
- async addFilesToGroup(fileId: string, groupIds: string[], userId: string, tenantId: string): Promise<void> {
- const file = await this.knowledgeBaseRepository.findOne({
- where: { id: fileId, userId, tenantId },
- relations: ['groups'],
- });
- if (!file) {
- throw new NotFoundException(this.i18nService.getMessage('fileNotFound'));
- }
- // Load all groups by ID without user restriction
- const groups = await this.groupRepository.findByIds(groupIds);
- const validGroups = groups.filter(g => g.tenantId === tenantId);
- if (validGroups.length !== groupIds.length) {
- throw new NotFoundException(this.i18nService.getMessage('someGroupsNotFound'));
- }
- file.groups = validGroups;
- await this.knowledgeBaseRepository.save(file);
- }
- async removeFileFromGroup(fileId: string, groupId: string, userId: string, tenantId: string): Promise<void> {
- const file = await this.knowledgeBaseRepository.findOne({
- where: { id: fileId, userId, tenantId },
- relations: ['groups'],
- });
- if (!file) {
- throw new NotFoundException(this.i18nService.getMessage('fileNotFound'));
- }
- file.groups = file.groups.filter(group => group.id !== groupId);
- await this.knowledgeBaseRepository.save(file);
- }
- async getFileIdsByGroups(groupIds: string[], userId: string, tenantId: string): Promise<string[]> {
- if (!groupIds || groupIds.length === 0) {
- return [];
- }
- const result = await this.knowledgeBaseRepository
- .createQueryBuilder('kb')
- .innerJoin('kb.groups', 'group')
- .where('group.id IN (:...groupIds)', { groupIds })
- .andWhere('kb.tenantId = :tenantId', { tenantId })
- .select('DISTINCT kb.id', 'id')
- .getRawMany();
- return result.map(row => row.id);
- }
- }
|