Ncto 141 add image upload on project settings#19
Conversation
…ttings and public routes
There was a problem hiding this comment.
Pull request overview
Adds backend support for uploading project/user images to S3 and retrieving their CDN URLs, including new unauthenticated (“public”) endpoints intended for published projects and user profile pictures.
Changes:
- Tightens image upload validation (max size + MIME type) for project images and user profile pictures.
- Updates project image retrieval to return a CDN URL payload and adds new public endpoints to fetch CDN URLs for published project images and user profile pictures.
- Extends Swagger/OpenAPI documentation to reflect new endpoints and updated response shapes.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| swagger.json | Updates OpenAPI docs for image upload validation/errors, changes project image GET response, and adds new public image URL endpoints + schema. |
| src/swagger.app.module.ts | Registers PublicController in the Swagger-only module for documentation generation. |
| src/routes/user/user.controller.ts | Adds image MIME validation and sets uploaded profile pictures to public-read. |
| src/routes/public/public.module.ts | Introduces a new module wiring Prisma + S3 for the public routes. |
| src/routes/public/public.controller.ts | Adds public endpoints to fetch CDN URLs for published project images and user profile pictures. |
| src/routes/public/dto/image-url-response.dto.ts | Adds a DTO for { url } responses. |
| src/routes/project/project.controller.ts | Adds collaborator guard for upload/get image, validates MIME type, switches GET image response to { url }, and sets uploaded project images to public-read. |
| src/app.module.ts | Registers PublicModule in the main app module. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @ApiResponse({ | ||
| status: 200, | ||
| description: "Signed cookies and CDN resource URL", | ||
| type: SignedCdnResourceDto | ||
| description: "CDN URL for the project image", | ||
| schema: { | ||
| type: "object", | ||
| properties: { | ||
| url: { type: "string", example: "https://cdn.example.com/projects/42/image" } | ||
| } | ||
| } | ||
| }) | ||
| @ApiResponse({ status: 403, description: "Forbidden" }) | ||
| @ApiResponse({ status: 404, description: "Image not found" }) | ||
| async getProjectImage( | ||
| @Param("id", ParseIntPipe) id: number, | ||
| @Res() res: Response | ||
| ): Promise<void> { | ||
| @Param("id", ParseIntPipe) id: number | ||
| ): Promise<{ url: string }> { |
| const project = await this.prismaService.project.findUnique({ | ||
| where: { id }, | ||
| select: { id: true, status: true } | ||
| }); | ||
|
|
||
| if (!project) { | ||
| throw new NotFoundException(`Project with ID ${id} not found`); | ||
| } | ||
|
|
||
| if (project.status !== "COMPLETED") { | ||
| throw new NotFoundException( | ||
| `Project with ID ${id} is not published` | ||
| ); | ||
| } |
There was a problem hiding this comment.
Good suggestion from Copilot
| throw new NotFoundException(`User with ID ${id} not found`); | ||
| } | ||
|
|
||
| const key = `users/${id}/profile`; | ||
| const exists = await this.s3Service.fileExists(key); | ||
| if (!exists) { | ||
| throw new NotFoundException("Profile picture not found"); |
| originalName: file.originalname | ||
| } | ||
| }); | ||
| await this.s3Service.setObjectPublicRead(key); |
swagger.json
Outdated
| "type": "object", | ||
| "properties": { | ||
| "url": { | ||
| "type": "string", | ||
| "example": "https://cdn.example.com/projects/42/image" | ||
| } | ||
| } |
| originalName: file.originalname | ||
| } | ||
| }); | ||
| await this.s3Service.setObjectPublicRead(key); |
| originalName: file.originalname | ||
| } | ||
| }); | ||
| await this.s3Service.setObjectPublicRead(key); |
There was a problem hiding this comment.
Ehh we can ignore this
There was a problem hiding this comment.
not really otherwise we cannot have access to the ressource with the cdn
| const project = await this.prismaService.project.findUnique({ | ||
| where: { id }, | ||
| select: { id: true, status: true } | ||
| }); | ||
|
|
||
| if (!project) { | ||
| throw new NotFoundException(`Project with ID ${id} not found`); | ||
| } | ||
|
|
||
| if (project.status !== "COMPLETED") { | ||
| throw new NotFoundException( | ||
| `Project with ID ${id} is not published` | ||
| ); | ||
| } |
There was a problem hiding this comment.
Good suggestion from Copilot
| const key = `projects/${id}/image`; | ||
| const exists = await this.s3Service.fileExists(key); | ||
| if (!exists) { | ||
| throw new NotFoundException("Project image not found"); |
There was a problem hiding this comment.
Should be here a NoContentException (if it exists?)
There was a problem hiding this comment.
I believe the routes should be moved to their respective controllers over creating a new controller.
There was a problem hiding this comment.
Put this in routes/common/dto/...
…roject and user images
…rol and metadata handling
Jira ticket
https://naucto.atlassian.net/browse/NCTO-141
What does your MR do ?
Linked to frontend PR, this will add the way to upload images on the S3 then will be able to laod then using the cdn urls, currently it's implemented on ongoing projects and published projects.
The backend adds the apis to be able to upload and get the images of user profiles or projects
How to test it
Open a project and in the project settings you can now upload an image for this project
Screenshot
Notes