From 2ed657caf281cc6d3c1fc1e940efb5bbca5ab57d Mon Sep 17 00:00:00 2001 From: evenegas Date: Wed, 7 Jan 2026 12:10:45 -0600 Subject: [PATCH] se agrego drive correctamente --- src/app.module.ts | 5 +- src/drive/drive.controller.ts | 87 ++++++++++++++++++++++++++++++++++ src/drive/drive.module.ts | 5 +- src/drive/drive.service.ts | 88 +++++++++++++++++++++-------------- 4 files changed, 146 insertions(+), 39 deletions(-) create mode 100644 src/drive/drive.controller.ts diff --git a/src/app.module.ts b/src/app.module.ts index 30da5ea..2e44f72 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -15,6 +15,7 @@ import { StatusModule } from './status/status.module'; import { TipoUsuarioModule } from './tipo-usuario/tipo-usuario.module'; import { UsuarioModule } from './usuario/usuario.module'; import { AuthModule } from './auth/auth.module'; +import { DriveModule } from './drive/drive.module'; @Module({ imports: [ @@ -57,8 +58,10 @@ import { AuthModule } from './auth/auth.module'; TipoUsuarioModule, UsuarioModule, + + DriveModule, ], controllers: [AppController], providers: [AppService], }) -export class AppModule {} +export class AppModule { } diff --git a/src/drive/drive.controller.ts b/src/drive/drive.controller.ts new file mode 100644 index 0000000..2a91124 --- /dev/null +++ b/src/drive/drive.controller.ts @@ -0,0 +1,87 @@ +// src/drive/drive.controller.ts +import { + BadRequestException, + Body, + Controller, + Delete, + Get, + Param, + Post, + Query, +} from '@nestjs/common'; +import { DriveService } from './drive.service'; +import * as fs from 'fs'; + +@Controller('drive-test') +export class DriveController { + constructor(private readonly driveService: DriveService) { } + + // ✅ Listar archivos/carpetas + @Get('list') + async list(@Query('pageToken') pageToken?: string) { + return this.driveService.list(pageToken || ''); + } + + // ✅ Crear carpeta dentro de CARPETA + @Post('mkdir') + async createFolder(@Body('name') name: string) { + if (!name) { + throw new BadRequestException('El nombre es obligatorio'); + } + const folderId = await this.driveService.mkDir(name); + return { folderId }; + } + + // ✅ Obtener carpeta (buscar o crear) + @Get('folder/:numeroCuenta') + async getOrCreateFolder( + @Param('numeroCuenta') numeroCuenta: string, + ) { + const folderId = await this.driveService.folder(numeroCuenta); + return { folderId }; + } + + // ✅ Subir archivo (archivo dummy para pruebas) + @Post('upload') + async uploadFile( + @Body('parent') parent: string, + ) { + if (!parent) { + throw new BadRequestException('Parent es obligatorio'); + } + + // Archivo temporal para prueba + const tempPath = './temp-test.txt'; + fs.writeFileSync(tempPath, 'Archivo de prueba DriveService'); + + const fileId = await this.driveService.uploadFile( + tempPath, + 'test-drive.txt', + 'text/plain', + parent, + ); + + return { fileId }; + } + + // ✅ Mover archivo (update) + @Post('update') + async updateFile( + @Body('fileId') fileId: string, + @Body('addParents') addParents: string, + @Body('removeParents') removeParents: string, + ) { + if (!fileId || !addParents || !removeParents) { + throw new BadRequestException('Datos incompletos'); + } + + return this.driveService.update(fileId, addParents, removeParents); + } + + // ✅ Eliminar archivo + @Delete('delete/:fileId') + async deleteFile(@Param('fileId') fileId: string) { + await this.driveService.deleteFile(fileId); + return { message: 'Archivo eliminado correctamente' }; + } +} diff --git a/src/drive/drive.module.ts b/src/drive/drive.module.ts index faaad0c..5753458 100644 --- a/src/drive/drive.module.ts +++ b/src/drive/drive.module.ts @@ -1,9 +1,10 @@ -// src/drive/drive.module.ts import { Module } from '@nestjs/common'; import { DriveService } from './drive.service'; +import { DriveController } from './drive.controller'; @Module({ + controllers: [DriveController], providers: [DriveService], exports: [DriveService], }) -export class DriveModule {} +export class DriveModule { } diff --git a/src/drive/drive.service.ts b/src/drive/drive.service.ts index 02196d9..e40acc9 100644 --- a/src/drive/drive.service.ts +++ b/src/drive/drive.service.ts @@ -1,27 +1,28 @@ // src/drive/drive.service.ts -import { BadRequestException, Injectable, InternalServerErrorException } from '@nestjs/common'; +import { + BadRequestException, + Injectable, + InternalServerErrorException, +} from '@nestjs/common'; import { google } from 'googleapis'; import * as fs from 'fs'; -import * as path from 'path'; -import { error } from 'console'; @Injectable() export class DriveService { - private SCOPES = ['https://www.googleapis.com/auth/drive']; + private SCOPES = ['https://www.googleapis.com/auth/drive.file']; private loadCredentials() { try { - const credenciales = JSON.parse( - fs.readFileSync(path.resolve(process.cwd(), 'cred.json'), 'utf8'), + const oAuth2Client = new google.auth.OAuth2( + process.env.CLIENT_ID, + process.env.CLIENT_SECRET, ); - credenciales.private_key = credenciales.private_key.replace(/\\n/g, '\n'); - - return new google.auth.JWT({ - email: credenciales.client_email, - key: credenciales.private_key, - scopes: this.SCOPES, + oAuth2Client.setCredentials({ + refresh_token: process.env.REFRESH_TOKEN, }); + + return oAuth2Client; } catch (err) { throw new InternalServerErrorException( 'Error al cargar credenciales de Google Drive', @@ -30,14 +31,14 @@ export class DriveService { } async list(pageToken = '') { - const authClient = await this.loadCredentials(); + const authClient = this.loadCredentials(); const drive = google.drive({ version: 'v3', auth: authClient }); try { const res = await drive.files.list({ corpora: 'user', - supportsTeamDrives: true, - includeTeamDriveItems: true, + supportsAllDrives: true, + includeItemsFromAllDrives: true, spaces: 'drive', pageSize: 1000, pageToken, @@ -53,9 +54,12 @@ export class DriveService { async deleteFile(fileId: string) { if (fileId === process.env.CARPETA) { - throw new Error('No se puede eliminar este archivo/carpeta.'); + throw new BadRequestException( + 'No se puede eliminar este archivo/carpeta.', + ); } - const authClient = await this.loadCredentials(); + + const authClient = this.loadCredentials(); const drive = google.drive({ version: 'v3', auth: authClient }); try { @@ -67,14 +71,20 @@ export class DriveService { } } - async uploadFile(filePath: string, name: string, mimeType: string, parent: string) { - const authClient = await this.loadCredentials(); + async uploadFile( + filePath: string, + name: string, + mimeType: string, + parent: string, + ) { + const authClient = this.loadCredentials(); const drive = google.drive({ version: 'v3', auth: authClient }); const requestBody = { name, parents: [parent], }; + const media = { mimeType, body: fs.createReadStream(filePath), @@ -85,9 +95,11 @@ export class DriveService { requestBody, media, fields: 'id', + supportsAllDrives: true, }); + fs.unlinkSync(filePath); - return res.data.id; + return res.data.id!; } catch (err) { throw new InternalServerErrorException( 'Error al subir archivo: ' + err.message, @@ -96,37 +108,35 @@ export class DriveService { } async mkDir(name: string): Promise { - const authClient = await this.loadCredentials(); - const drive = google.drive({ version: 'v3', auth: authClient }); - - if (!name) { throw new BadRequestException('Nombre de carpeta inválido'); } if (!process.env.CARPETA) { - throw new Error() + throw new InternalServerErrorException('CARPETA no configurada'); } + const authClient = this.loadCredentials(); + const drive = google.drive({ version: 'v3', auth: authClient }); + const requestBody = { name, mimeType: 'application/vnd.google-apps.folder', parents: [process.env.CARPETA], }; - try { const res = await drive.files.create({ requestBody, fields: 'id', + supportsAllDrives: true, }); if (!res.data.id) { - throw new Error() + throw new Error('No se pudo crear la carpeta'); } return res.data.id; - } catch (err) { throw new InternalServerErrorException( 'Error al crear carpeta: ' + err.message, @@ -135,7 +145,7 @@ export class DriveService { } async update(fileId: string, addParents: string, removeParents: string) { - const authClient = await this.loadCredentials(); + const authClient = this.loadCredentials(); const drive = google.drive({ version: 'v3', auth: authClient }); try { @@ -143,6 +153,7 @@ export class DriveService { fileId, addParents, removeParents, + supportsAllDrives: true, }); return res.data; } catch (err) { @@ -153,17 +164,23 @@ export class DriveService { } async folder(numeroCuenta: string): Promise { - const authClient = await this.loadCredentials(); + if (!process.env.CARPETA) { + throw new InternalServerErrorException('CARPETA no configurada'); + } + + const authClient = this.loadCredentials(); const drive = google.drive({ version: 'v3', auth: authClient }); const res = await drive.files.list({ q: ` - mimeType='application/vnd.google-apps.folder' - and name='${numeroCuenta}' - and '${process.env.CARPETA}' in parents - and trashed=false - `, + mimeType='application/vnd.google-apps.folder' + and name='${numeroCuenta}' + and '${process.env.CARPETA}' in parents + and trashed=false + `, fields: 'files(id, name)', + supportsAllDrives: true, + includeItemsFromAllDrives: true, }); if (res.data.files?.length) { @@ -172,5 +189,4 @@ export class DriveService { return this.mkDir(numeroCuenta); } - }