feat: Manage Images using Minio Service
This commit is contained in:
parent
33a9dbde36
commit
5e5ecb6cd1
@ -10,6 +10,8 @@ import {
|
||||
ParseIntPipe,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
DefaultValuePipe,
|
||||
BadRequestException,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
||||
import { MerchantService } from './services/merchant.service';
|
||||
@ -32,19 +34,23 @@ export class MerchantController {
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Get all merchants' })
|
||||
@ApiQuery({ name: 'skip', required: false, type: Number })
|
||||
@ApiQuery({ name: 'take', required: false, type: Number })
|
||||
@ApiResponse({ status: 200, description: 'List of merchants' })
|
||||
findAll(
|
||||
@Query('skip') skip?: string,
|
||||
@Query('take') take?: string,
|
||||
@ApiQuery({ name: 'skip', required: false, type: Number, example: 0 })
|
||||
@ApiQuery({ name: 'take', required: false, type: Number, example: 10 })
|
||||
@ApiResponse({ status: 200, description: 'Paginated merchants' })
|
||||
async findAll(
|
||||
@Query('skip', new DefaultValuePipe(0), ParseIntPipe) skip: number,
|
||||
@Query('take', new DefaultValuePipe(10), ParseIntPipe) take: number,
|
||||
) {
|
||||
return this.merchantService.findAll(
|
||||
skip ? parseInt(skip) : 0,
|
||||
take ? parseInt(take) : 10,
|
||||
);
|
||||
|
||||
if (skip < 0) throw new BadRequestException('skip must be >= 0');
|
||||
if (take < 1 || take > 100) {
|
||||
throw new BadRequestException('take must be between 1 and 100');
|
||||
}
|
||||
|
||||
return this.merchantService.findAll(skip, take);
|
||||
}
|
||||
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get merchant by ID' })
|
||||
@ApiParam({ name: 'id', type: Number })
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Injectable, NotFoundException, BadRequestException, ConflictException, Inject } from '@nestjs/common';
|
||||
import { Injectable, NotFoundException, BadRequestException, ConflictException, Inject, InternalServerErrorException } from '@nestjs/common';
|
||||
import { MerchantPartnerWithRelations, MerchantUserWithInfo } from '../entities/merchant.entity';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import type { UserServiceClient } from '../interfaces/user.service.interface';
|
||||
@ -97,23 +97,49 @@ export class MerchantService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all merchants with optional pagination
|
||||
* Find merchants with pagination and total count
|
||||
*/
|
||||
async findAll(skip = 0, take = 10): Promise<MerchantPartnerWithRelations[]> {
|
||||
async findAll(skip = 0, take = 10): Promise<{ items: MerchantPartnerWithRelations[], total: number }> {
|
||||
if (skip < 0) throw new BadRequestException('skip must be >= 0');
|
||||
if (take < 1 || take > 100) throw new BadRequestException('take must be between 1 et 100');
|
||||
|
||||
try {
|
||||
const total = await this.prisma.merchantPartner.count();
|
||||
|
||||
// Ajuster le take si on dépasse le total
|
||||
if (skip >= total) {
|
||||
return { items: [], total };
|
||||
}
|
||||
const remaining = total - skip;
|
||||
const adjustedTake = Math.min(take, remaining);
|
||||
|
||||
const merchants = await this.prisma.merchantPartner.findMany({
|
||||
skip,
|
||||
take,
|
||||
take: adjustedTake,
|
||||
include: {
|
||||
configs: true,
|
||||
merchantUsers: true,
|
||||
technicalContacts: true,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
orderBy: { createdAt: 'desc' }
|
||||
});
|
||||
|
||||
return Promise.all(merchants.map(m => this.enrichMerchantWithUserInfo(m)));
|
||||
const enrichedMerchants = await Promise.all(
|
||||
merchants.map(async merchant => {
|
||||
try {
|
||||
return await this.enrichMerchantWithUserInfo(merchant);
|
||||
} catch (e) {
|
||||
console.error(`⚠️ Error enriching merchant ${merchant.id}:`, e);
|
||||
return merchant;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
return { items: enrichedMerchants, total };
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to fetch merchants:', error);
|
||||
throw new InternalServerErrorException('Failed to fetch merchants');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,17 +212,35 @@ export class MerchantService {
|
||||
* Add user to merchant
|
||||
*/
|
||||
async addUserToMerchant(dto: AddUserToMerchantDto): Promise<MerchantUserWithInfo> {
|
||||
// Check if merchant exists
|
||||
await this.findOne(dto.merchantPartnerId);
|
||||
console.log('🔹 Starting addUserToMerchant process', dto);
|
||||
|
||||
// Validate user exists
|
||||
const userExists = await this.userServiceClient.verifyUserExists(dto.userId);
|
||||
// 1️⃣ Vérifier que le merchant existe
|
||||
let merchant;
|
||||
try {
|
||||
merchant = await this.findOne(dto.merchantPartnerId);
|
||||
console.log(`✅ Merchant exists: ID=${dto.merchantPartnerId}`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Merchant not found: ID=${dto.merchantPartnerId}`, err);
|
||||
throw new BadRequestException(`Merchant with ID ${dto.merchantPartnerId} not found`);
|
||||
}
|
||||
|
||||
// 2️⃣ Vérifier que l'utilisateur existe dans le service utilisateur
|
||||
let userExists: boolean;
|
||||
try {
|
||||
userExists = await this.userServiceClient.verifyUserExists(dto.userId);
|
||||
console.log(`📌 User exists check for ID=${dto.userId}: ${userExists}`);
|
||||
if (!userExists) {
|
||||
throw new BadRequestException(`User with ID ${dto.userId} not found in user service`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`❌ Error verifying user existence: ID=${dto.userId}`, err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Check if user already attached
|
||||
const existing = await this.prisma.merchantUser.findUnique({
|
||||
// 3️⃣ Vérifier si l'utilisateur est déjà attaché au merchant
|
||||
let existing;
|
||||
try {
|
||||
existing = await this.prisma.merchantUser.findUnique({
|
||||
where: {
|
||||
userId_merchantPartnerId: {
|
||||
userId: dto.userId,
|
||||
@ -204,30 +248,55 @@ export class MerchantService {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`📌 Existing association check:`, existing ? 'Exists' : 'Not exists');
|
||||
if (existing) {
|
||||
throw new ConflictException(`User ${dto.userId} is already attached to merchant ${dto.merchantPartnerId}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`❌ Error checking existing merchant user: ID=${dto.userId}`, err);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Create merchant user
|
||||
const merchantUser = await this.prisma.merchantUser.create({
|
||||
// 4️⃣ Créer l'association
|
||||
let merchantUser: MerchantUserWithInfo;
|
||||
try {
|
||||
merchantUser = await this.prisma.merchantUser.create({
|
||||
data: {
|
||||
userId: dto.userId,
|
||||
role: dto.role,
|
||||
merchantPartnerId: dto.merchantPartnerId,
|
||||
},
|
||||
});
|
||||
console.log(`✅ MerchantUser created: ID=${merchantUser.id}, UserID=${dto.userId}, MerchantID=${dto.merchantPartnerId}`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Error creating merchantUser`, err);
|
||||
throw new InternalServerErrorException('Failed to create merchant user');
|
||||
}
|
||||
|
||||
// Emit event
|
||||
// 5️⃣ Émettre l'événement
|
||||
try {
|
||||
this.eventEmitter.emit('merchant.user.attached', {
|
||||
merchantId: dto.merchantPartnerId,
|
||||
userId: dto.userId,
|
||||
role: dto.role,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
console.log(`📣 Event emitted: merchant.user.attached`);
|
||||
} catch (err) {
|
||||
console.warn(`⚠️ Failed to emit event for merchant.user.attached`, err);
|
||||
}
|
||||
|
||||
// Enrich with user info
|
||||
const userInfo = await this.userServiceClient.getUserInfo(dto.userId);
|
||||
// 6️⃣ Récupérer les infos utilisateur enrichies
|
||||
let userInfo;
|
||||
try {
|
||||
userInfo = await this.userServiceClient.getUserInfo(dto.userId);
|
||||
console.log(`📌 User info fetched for ID=${dto.userId}`);
|
||||
} catch (err) {
|
||||
console.error(`❌ Failed to fetch user info, returning merchantUser without enrichment`, err);
|
||||
userInfo = null;
|
||||
}
|
||||
|
||||
// 7️⃣ Retourner l'objet final
|
||||
return {
|
||||
...merchantUser,
|
||||
userInfo,
|
||||
|
||||
@ -148,7 +148,7 @@ export class HttpUserServiceClient implements UserServiceClient {
|
||||
try {
|
||||
const headers = await this.getAuthHeaders();
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.get(`${this.baseUrl}/users/${userId}`, { headers }),
|
||||
this.httpService.get(`${this.baseUrl}/merchant-users/${userId}`, { headers }),
|
||||
);
|
||||
return this.mapToUserInfo(response.data);
|
||||
} catch (error) {
|
||||
@ -174,7 +174,7 @@ export class HttpUserServiceClient implements UserServiceClient {
|
||||
try {
|
||||
const headers = await this.getAuthHeaders();
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.post(`${this.baseUrl}/users/batch`, { userIds }, { headers }),
|
||||
this.httpService.post(`${this.baseUrl}/merchant-users/batch`, { userIds }, { headers }),
|
||||
);
|
||||
return response.data.map(user => this.mapToUserInfo(user));
|
||||
} catch (error) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user