All files / src/modules/media media.controller.ts

100% Statements 32/32
64% Branches 16/25
100% Functions 4/4
100% Lines 30/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 8612x                           12x 12x 12x 12x 12x 12x 12x 12x       12x 14x               12x         3x 1x   2x 1x     1x 1x             1x               12x 2x 2x 1x 1x   1x 1x               12x       1x 1x 1x    
import {
  Controller,
  Post,
  UseGuards,
  UseInterceptors,
  UploadedFile,
  Body,
  Get,
  Param,
  Res,
  BadRequestException,
  Req,
  Delete,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { MediaService } from '@app/modules/media/media.service';
import { JwtAuthGuard } from '@app/common/guards/jwt-auth.guard';
import { RolesGuard } from '@app/common/guards/roles.guard';
import { Roles } from '@app/common/decorators/roles.decorator';
import { Response, Request } from 'express';
import { UploadMediaDto } from '@app/modules/media/dto/upload-media.dto';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
 
@ApiTags('Media')
@Controller('media')
export class MediaController {
  constructor(private readonly mediaService: MediaService) {}
 
  @Post()
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('AGENT')
  @UseInterceptors(FileInterceptor('file'))
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Upload media', description: 'Roles: AGENT. Multipart form with file + body.' })
  async upload(
    @UploadedFile() file: any,
    @Body() body: UploadMediaDto,
    @Req() req: Request,
  ) {
    if (!file) {
      throw new BadRequestException('File is required');
    }
    if (!body.type) {
      throw new BadRequestException('Media type is required');
    }
 
    const user = (req as any).user;
    const media = await this.mediaService.uploadMedia(
      file,
      body.type,
      user?.id ?? null,
      body.listingId,
    );
 
    return {
      id: media.id,
      originalUrl: await this.mediaService.getPublicUrl(media.storageKey),
    };
  }
 
  @Get(':id')
  @ApiOperation({ summary: 'Redirect to media public URL' })
  async redirect(@Param('id') id: string, @Res() res: Response) {
    const media = await this.mediaService.findById(Number(id));
    if (!media) {
      res.status(404).send('Not found');
      return;
    }
    const url = await this.mediaService.getPublicUrl(media.storageKey);
    res.redirect(302, url);
  }
 
  @Delete(':id')
  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('AGENT', 'ADMIN')
  @ApiBearerAuth()
  @ApiOperation({ summary: 'Soft-delete media', description: 'Roles: AGENT or ADMIN.' })
  async remove(
    @Param('id') id: string,
    @Req() req: Request,
  ) {
    const user = (req as any).user;
    await this.mediaService.softDelete(Number(id), user?.id, user?.role === 'ADMIN');
    return { status: 'deleted' };
  }
}