// server/src/model-config/model-config.service.ts import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ModelConfig } from './model-config.entity'; import { CreateModelConfigDto } from './dto/create-model-config.dto'; import { UpdateModelConfigDto } from './dto/update-model-config.dto'; import { User } from '../user/user.entity'; @Injectable() export class ModelConfigService { constructor( @InjectRepository(ModelConfig) private modelConfigRepository: Repository, ) { } async create( userId: string, tenantId: string, createModelConfigDto: CreateModelConfigDto, ): Promise { const modelConfig = this.modelConfigRepository.create({ ...createModelConfigDto, userId, tenantId, }); return this.modelConfigRepository.save(modelConfig); } async findAll(userId: string, tenantId: string): Promise { return this.modelConfigRepository.createQueryBuilder('model') .where('model.tenantId = :tenantId OR model.tenantId IS NULL', { tenantId }) .getMany(); } async findOne(id: string, userId: string, tenantId: string): Promise { const modelConfig = await this.modelConfigRepository.createQueryBuilder('model') .where('model.id = :id', { id }) .andWhere('(model.tenantId = :tenantId OR model.tenantId IS NULL)', { tenantId }) .getOne(); if (!modelConfig) { throw new NotFoundException( `ModelConfig with ID "${id}" not found.`, ); } return modelConfig; } async findByType(userId: string, tenantId: string, type: string): Promise { return this.modelConfigRepository.createQueryBuilder('model') .where('model.type = :type', { type }) .andWhere('(model.tenantId = :tenantId OR model.tenantId IS NULL)', { tenantId }) .getMany(); } async update( userId: string, tenantId: string, id: string, updateModelConfigDto: UpdateModelConfigDto, ): Promise { const modelConfig = await this.findOne(id, userId, tenantId); if (!modelConfig) { throw new NotFoundException( `ModelConfig with ID "${id}" not found.`, ); } // Only allow updating if it belongs to the tenant, or if it's a global admin (not fully implemented, so we check tenantId) if (modelConfig.tenantId && modelConfig.tenantId !== tenantId) { throw new ForbiddenException('Cannot update models from another tenant'); } // Update the model const updated = this.modelConfigRepository.merge( modelConfig, updateModelConfigDto, ); return this.modelConfigRepository.save(updated); } async remove(userId: string, tenantId: string, id: string): Promise { // Only allow removing if it exists and accessible in current tenant context const model = await this.findOne(id, userId, tenantId); if (model.tenantId && model.tenantId !== tenantId) { throw new ForbiddenException('Cannot delete models from another tenant'); } const result = await this.modelConfigRepository.delete({ id }); if (result.affected === 0) { throw new NotFoundException(`ModelConfig with ID "${id}" not found.`); } } /** * 指定されたモデルをデフォルトに設定 */ async setDefault(userId: string, tenantId: string, id: string): Promise { const modelConfig = await this.findOne(id, userId, tenantId); // 同じタイプの他のモデルのデフォルトフラグをクリア (現在のテナント内またはglobal) // 厳密には、現在のテナントのIsDefault設定といった方が正しいですが、シンプルにするため全体のIsDefaultを操作します await this.modelConfigRepository .createQueryBuilder() .update(ModelConfig) .set({ isDefault: false }) .where('type = :type', { type: modelConfig.type }) .andWhere('(tenantId = :tenantId OR tenantId IS NULL)', { tenantId }) .execute(); modelConfig.isDefault = true; return this.modelConfigRepository.save(modelConfig); } /** * 指定されたタイプのデフォルトモデルを取得 * テナント固有のデフォルトを優先、なければグローバル */ async findDefaultByType(tenantId: string, type: string): Promise { const models = await this.modelConfigRepository.createQueryBuilder('model') .where('model.type = :type', { type }) .andWhere('model.isDefault = :isDefault', { isDefault: true }) .andWhere('model.isEnabled = :isEnabled', { isEnabled: true }) .andWhere('(model.tenantId = :tenantId OR model.tenantId IS NULL)', { tenantId }) .orderBy('model.tenantId', 'DESC') // Null will be last in most DBs, or we can fetch all and rank in JS .getMany(); // Prefer tenant specific model over global const tenantModel = models.find(m => m.tenantId === tenantId); return tenantModel || models[0] || null; } }