streamflix-api / src /shared /modules /upload /google-drive /google-drive.controller.ts
Akshar2325
feat(discord-logger): implement api request and response logging
d201b18
Raw
History Blame
4.55 kB
import {
Controller,
Post,
Delete,
Get,
Res,
UploadedFile,
UseInterceptors,
Query,
BadRequestException,
HttpStatus,
HttpCode,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import {
ApiTags,
ApiOperation,
ApiConsumes,
ApiBody,
ApiQuery,
ApiExcludeEndpoint,
} from '@nestjs/swagger';
import type { Response } from 'express';
import { GoogleDriveService } from './google-drive.service';
import { FileTypeEnum } from './enums/file-type.enum';
import { LogToDiscord } from 'src/shared/decorators/log-to-discord.decorator';
@ApiTags('Upload: Google Drive Storage')
@Controller('google-drive')
@LogToDiscord()
export class GoogleDriveController {
constructor(private readonly googleDriveService: GoogleDriveService) {}
@Get('oauth2/authorize')
@ApiExcludeEndpoint()
async getAuthUrl() {
return this.googleDriveService.getAuthorizationUrl();
}
@Get('oauth2callback')
@ApiExcludeEndpoint()
async oauth2Callback(@Query('code') code: string, @Res() res: Response) {
const result = await this.googleDriveService.handleOAuthCallback(code);
return res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Authorization ${result.success ? 'Success' : 'Failed'}</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
.success { background: #d4edda; border: 1px solid #c3e6cb; padding: 20px; border-radius: 5px; }
.error { background: #f8d7da; border: 1px solid #f5c6cb; padding: 20px; border-radius: 5px; }
code { color: #e83e8c; }
h1 { color: #28a745; }
.warning { background: #fff3cd; border: 1px solid #ffc107; padding: 15px; margin: 20px 0; border-radius: 5px; }
</style>
</head>
<body>
<div class="${result.success ? 'success' : 'error'}">
<h1>${result.success ? '✅ Authorization Successful!' : '❌ Authorization Failed'}</h1>
<p>${result.success ? 'Your Google account has been authorized.' : result.error}</p>
</div>
${
result.success
? `
<h2>🔑 Your Refresh Token:</h2>
<div class="code-block">
<code>${result.refreshToken}</code>
</div>
<div class="warning">
<h3>⚠️ IMPORTANT: Save this refresh token!</h3>
<p>Add to your <code>.env</code> file:</p>
<div class="code-block">
<code>GOOGLE_OAUTH2_REFRESH_TOKEN="${result.refreshToken}"</code>
</div>
</div>
<h3>🚀 Next Steps:</h3>
<ol>
<li>Copy the refresh token above</li>
<li>Add it to your <code>.env</code> file</li>
<li>Restart your application</li>
<li>Try uploading a file!</li>
</ol>
`
: `<p><a href="/google-drive/oauth2/authorize">Try again</a></p>`
}
</body>
</html>
`);
}
@Post('upload')
@ApiOperation({ summary: 'Upload file to Google Drive' })
@ApiConsumes('multipart/form-data')
@ApiQuery({ name: 'fileType', enum: FileTypeEnum, required: false })
@ApiQuery({
name: 'customFilename',
required: false,
description: 'Custom filename (optional)',
})
@ApiBody({
schema: {
type: 'object',
properties: {
file: {
type: 'string',
format: 'binary',
},
},
},
})
@UseInterceptors(FileInterceptor('file'))
async uploadFile(
@UploadedFile() file: any,
@Query('fileType') fileType?: FileTypeEnum,
@Query('customFilename') customFilename?: string,
) {
if (!file) {
throw new BadRequestException('No file uploaded');
}
return this.googleDriveService.uploadFile({
fileBuffer: file.buffer,
filename: file.originalname,
fileType: fileType || FileTypeEnum.IMAGE,
customFilename: customFilename,
mimetype: file.mimetype,
});
}
@Delete('by-url')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Delete file by public URL' })
@ApiQuery({
name: 'url',
required: true,
description:
'Public URL of the file to delete (e.g., https://drive.google.com/uc?id=FILE_ID)',
type: 'string',
})
async deleteFileByUrl(@Query('url') url: string) {
if (!url) {
throw new BadRequestException('URL is required');
}
return this.googleDriveService.handleFileDelete(url);
}
}