Guardar y cambiar img al editar productos

This commit is contained in:
2025-08-12 15:58:32 -04:00
parent 8a54bf7138
commit 854b31f594
20 changed files with 162 additions and 50 deletions

View File

@@ -17,7 +17,7 @@ export async function seedProducts(db: NodePgDatabase<typeof schema>) {
status:'PUBLICADO', // PUBLICADO, AGOTADO, BORRADOR
urlImg:'apple.avif',
userId:1,
gallery: ["Pruebas"]
gallery: ["Pruebas.png","Pruebas2.png"]
}
];

View File

@@ -54,13 +54,16 @@ export class AuthController {
@Patch('refresh-token')
//@RequirePermissions('auth:refresh-token')
async refreshToken(@Body() refreshTokenDto: RefreshTokenDto) {
console.log("Refrescando token...");
console.log(refreshTokenDto);
return await this.authService.refreshToken(refreshTokenDto);
}
@Public()
@HttpCode(200)
@Get('test')
async test() {
return 'aplication test success';
}
// @Public()
// @HttpCode(200)
// @Get('test')
// async test() {
// return 'aplication test success';
// }
}

View File

@@ -5,6 +5,12 @@ import { CreateProductDto } from './create-product.dto';
import { IsOptional, IsString } from 'class-validator';
export class UpdateProductDto extends PartialType(CreateProductDto) {
@ApiProperty()
@IsString({
message: 'id must be a number',
})
id: string;
@IsOptional()
title: string;
@@ -25,4 +31,10 @@ export class UpdateProductDto extends PartialType(CreateProductDto) {
@IsOptional()
urlImg: string;
// @ApiProperty()
// @IsString({
// message: 'userId must be a number',
// })
// userId: number;
}

View File

@@ -16,6 +16,9 @@ export class Inventory {
price: string | null;
stock: number | null;
urlImg: string | null;
gallery: string[] | null;
address: string | null;
status: string | null;
}
export class Store {

View File

@@ -1,4 +1,5 @@
import { Controller, Get, Post, Body, Patch, Param, Delete, Query, Req } from '@nestjs/common';
import { Controller, Get, Post, Body, Patch, Param, Delete, Query, Req, UseInterceptors, UploadedFiles } from '@nestjs/common';
import { FilesInterceptor } from '@nestjs/platform-express';
import { InventoryService } from './inventory.service';
import { CreateProductDto } from './dto/create-product.dto';
import { UpdateProductDto } from './dto/update-product.dto';
@@ -62,7 +63,7 @@ export class UsersController {
return { message: 'User created successfully', data };
}
@Patch(':id')
@Patch('/id/:id')
// @Roles('admin')
@ApiOperation({ summary: 'Update a product' })
@ApiResponse({ status: 200, description: 'Product updated successfully.' })
@@ -72,6 +73,27 @@ export class UsersController {
return { message: 'User updated successfully', data };
}
@Patch('/upload')
@ApiOperation({ summary: 'Update a product' })
@ApiResponse({ status: 200, description: 'Product uploaded successfully.'})
@ApiResponse({ status: 404, description: 'Product not found.' })
@ApiResponse({ status: 500, description: 'Internal server error.' })
@UseInterceptors(FilesInterceptor('urlImg'))
async uploadFile(@Req() req: Request, @UploadedFiles() files: Express.Multer.File[], @Body() body: any) {
// Aquí puedes acceder a los campos del formulario
// console.log('Archivos:', files);
const id = Number(req['user'].id);
// console.log(req['user'].id)
// console.log('Otros campos del formulario:', body);
const result = await this.inventoryService.saveImages(files,body,id);
// const result = ['result']
return { data: result };
}
// @Delete(':id')
// @Roles('admin')
// @ApiOperation({ summary: 'Delete a user' })

View File

@@ -8,6 +8,9 @@ import { CreateProductDto } from './dto/create-product.dto';
import { UpdateProductDto } from './dto/update-product.dto';
import { Product, Store, Inventory } from './entities/inventory.entity';
import { PaginationDto } from '../../common/dto/pagination.dto';
// Para guardar la imagen
import { writeFile, mkdir, unlink, rmdir, rm } from 'fs/promises';
import { join } from 'path';
@Injectable()
export class InventoryService {
@@ -29,7 +32,7 @@ export class InventoryService {
like(products.title, `%${search}%`),
like(products.description, `%${search}%`),
), eq(products.userId, id));
}else{
} else {
searchCondition = eq(products.userId, id);
}
@@ -57,7 +60,9 @@ export class InventoryService {
price: products.price,
stock: products.stock,
status: products.status,
urlImg: products.urlImg
urlImg: products.urlImg,
gallery: products.gallery,
userId: products.userId
})
.from(products)
.where(searchCondition)
@@ -92,15 +97,15 @@ export class InventoryService {
or(
like(viewProductsStore.title, `%${search}%`),
like(viewProductsStore.description, `%${search}%`)
),
),
or(eq(viewProductsStore.status, 'PUBLICADO'), eq(viewProductsStore.status, 'AGOTADO'))
)
} else if(search){
} else if (search) {
or(
like(viewProductsStore.title, `%${search}%`),
like(viewProductsStore.description, `%${search}%`)
)
} else if(isStore){
} else if (isStore) {
searchCondition = or(eq(viewProductsStore.status, 'PUBLICADO'), eq(viewProductsStore.status, 'AGOTADO'))
}
@@ -202,14 +207,14 @@ export class InventoryService {
userId: createProductDto.userId
})
.returning();
return newProduct
return newProduct
});
}
async update(id: string, updateProductDto: UpdateProductDto): Promise<Product> {
const productId = parseInt(id);
console.log(updateProductDto);
// console.log(updateProductDto);
// Check if exists
await this.findOne(id);
@@ -229,6 +234,54 @@ export class InventoryService {
// return this.findOne(id);
}
/**
* Guarda una imagen en el directorio de imágenes.
* @param file - El archivo de imagen a guardar.
* @returns La ruta de la imagen guardada.
*/
async saveImages(file: Express.Multer.File[], updateProductDto: UpdateProductDto, id: number): Promise<Product> {
const productId = parseInt(id.toString());
// Construye la ruta al directorio de imágenes.
const picturesPath = join(__dirname, '..', '..', '..', '..', 'web', 'public', 'uploads', 'inventory', id.toString());
// --- NUEVA LÓGICA: Borrar el directorio anterior ---
try {
// Borra el directorio y todos sus contenidos de forma recursiva y forzada.
await rm(picturesPath, { recursive: true, force: true });
} catch (error) {
// Es buena práctica manejar el error, aunque `force: true` lo hace menos probable.
// Podrías registrar el error, pero no detener la ejecución.
console.error(`No se pudo eliminar el directorio ${picturesPath}:`, error);
}
// --- FIN DE LA NUEVA LÓGICA ---
// Crea el directorio si no existe (ya que lo acabamos de borrar o no existía).
await mkdir(picturesPath, { recursive: true });
let gallery: string[] = [];
// Usamos `Promise.all` para manejar las operaciones asíncronas de forma correcta.
await Promise.all(file.map(async (f, index) => {
const fileName = `${index + 1}-${f.originalname}`;
gallery.push(fileName);
const filePath = join(picturesPath, fileName);
await writeFile(filePath, f.buffer);
}));
// Prepare update data
const updateData: any = {};
if (updateProductDto.title) updateData.title = updateProductDto.title;
if (updateProductDto.description) updateData.description = updateProductDto.description;
if (updateProductDto.price) updateData.price = updateProductDto.price;
if (updateProductDto.address) updateData.address = updateProductDto.address;
if (updateProductDto.status) updateData.status = updateProductDto.status;
if (updateProductDto.stock) updateData.stock = updateProductDto.stock;
if (file && file.length > 0) updateData.gallery = gallery;
const [updatedProduct] = await this.drizzle.update(products).set(updateData).where(eq(products.id, productId)).returning();
return updatedProduct;
}
// async remove(id: string): Promise<{ message: string, data: User }> {
// const userId = parseInt(id);

View File

@@ -12,9 +12,7 @@ export class PicturesController {
// Aquí puedes acceder a los campos del formulario
// console.log('Archivos:', files);
// console.log('Otros campos del formulario:', body);
const result = await this.picturesService.saveImages(files);
console.log(result);
return { data: result };
}

View File

@@ -11,6 +11,7 @@ export class PicturesService {
* @returns La ruta de la imagen guardada.
*/
async saveImages(file: Express.Multer.File[]): Promise<string[]> {
// Construye la ruta al directorio de imágenes.
const picturesPath = join(__dirname, '..', '..', '..', '..', 'uploads','pict');
@@ -22,27 +23,19 @@ export class PicturesService {
file.forEach(async (file) => {
count++
// Crea un nombre de archivo único para la imagen.
const fileName = `${Date.now()}-${count}-${file.originalname}`;
images.push(fileName);
// console.log(fileName);
// Construye la ruta completa al archivo de imagen.
const filePath = join(picturesPath, fileName);
// Escribe el archivo de imagen en el disco.
await writeFile(filePath, file.buffer);
});
// Devuelve la ruta de la imagen guardada.
// return [file[0].originalname]
return images;
// // Construye la ruta al directorio de imágenes.
// const picturesPath = join(__dirname, '..', '..', 'pictures');
// // Crea un nombre de archivo único para la imagen.
// const fileName = `${Date.now()}-${file.originalname}`;
// // Construye la ruta completa al archivo de imagen.
// const filePath = join(picturesPath, fileName);
// // Escribe el archivo de imagen en el disco.
// await writeFile(filePath, file.buffer);
// // Devuelve la ruta de la imagen guardada.
// return `/pictures/${fileName}`;
}
}