From 0a4bd23d308fb9e37d0b18c77ba1a879141921dd Mon Sep 17 00:00:00 2001 From: JustAnyone Date: Mon, 6 Oct 2025 16:58:13 +0300 Subject: [PATCH] Document post endpoints --- .../Posts/Comments/Create a post comment.bru | 6 +- .../Posts/Comments/Delete post comment.bru | 6 +- .../Comments/Update specific post comment.bru | 6 +- Bruno/Seed/Create accounts/Login as admin.bru | 23 +++++ .../Seed/Create accounts/Login as normal.bru | 2 +- .../Create accounts/Register normal user.bru | 2 +- .../Controllers/PostController.cs | 89 +++++++++++++++++-- 7 files changed, 111 insertions(+), 23 deletions(-) create mode 100644 Bruno/Seed/Create accounts/Login as admin.bru diff --git a/Bruno/Endpoints/Posts/Comments/Create a post comment.bru b/Bruno/Endpoints/Posts/Comments/Create a post comment.bru index f3a515b..32ed171 100644 --- a/Bruno/Endpoints/Posts/Comments/Create a post comment.bru +++ b/Bruno/Endpoints/Posts/Comments/Create a post comment.bru @@ -7,11 +7,7 @@ meta { post { url: {{baseUrl}}/api/posts/1/comments body: json - auth: bearer -} - -auth:bearer { - token: {{accessToken}} + auth: inherit } body:json { diff --git a/Bruno/Endpoints/Posts/Comments/Delete post comment.bru b/Bruno/Endpoints/Posts/Comments/Delete post comment.bru index 8e7f11d..1e1ac4b 100644 --- a/Bruno/Endpoints/Posts/Comments/Delete post comment.bru +++ b/Bruno/Endpoints/Posts/Comments/Delete post comment.bru @@ -7,9 +7,5 @@ meta { delete { url: {{baseUrl}}/api/posts/1/comments/1 body: none - auth: bearer -} - -auth:bearer { - token: {{accessToken}} + auth: inherit } diff --git a/Bruno/Endpoints/Posts/Comments/Update specific post comment.bru b/Bruno/Endpoints/Posts/Comments/Update specific post comment.bru index 44f4d7b..d5609f2 100644 --- a/Bruno/Endpoints/Posts/Comments/Update specific post comment.bru +++ b/Bruno/Endpoints/Posts/Comments/Update specific post comment.bru @@ -7,11 +7,7 @@ meta { patch { url: {{baseUrl}}/api/posts/1/comments/1 body: json - auth: bearer -} - -auth:bearer { - token: {{accessToken}} + auth: inherit } body:json { diff --git a/Bruno/Seed/Create accounts/Login as admin.bru b/Bruno/Seed/Create accounts/Login as admin.bru new file mode 100644 index 0000000..ae926ca --- /dev/null +++ b/Bruno/Seed/Create accounts/Login as admin.bru @@ -0,0 +1,23 @@ +meta { + name: Login as admin + type: http + seq: 5 +} + +post { + url: {{baseUrl}}/api/auth/login + body: json + auth: none +} + +body:json { + { + "email": "admin@localhost", + "password": "ChangeMe123#" + } +} + +vars:post-response { + accessToken: res.body.accessToken + refreshToken: res.body.refreshToken +} diff --git a/Bruno/Seed/Create accounts/Login as normal.bru b/Bruno/Seed/Create accounts/Login as normal.bru index bd20487..3ba4854 100644 --- a/Bruno/Seed/Create accounts/Login as normal.bru +++ b/Bruno/Seed/Create accounts/Login as normal.bru @@ -7,7 +7,7 @@ meta { post { url: {{baseUrl}}/api/auth/login body: json - auth: inherit + auth: none } body:json { diff --git a/Bruno/Seed/Create accounts/Register normal user.bru b/Bruno/Seed/Create accounts/Register normal user.bru index 60e1870..b9c3061 100644 --- a/Bruno/Seed/Create accounts/Register normal user.bru +++ b/Bruno/Seed/Create accounts/Register normal user.bru @@ -7,7 +7,7 @@ meta { post { url: {{baseUrl}}/api/auth/register body: json - auth: inherit + auth: none } body:json { diff --git a/T120B165-ImgBoard/Controllers/PostController.cs b/T120B165-ImgBoard/Controllers/PostController.cs index 28c4ff8..6e26089 100644 --- a/T120B165-ImgBoard/Controllers/PostController.cs +++ b/T120B165-ImgBoard/Controllers/PostController.cs @@ -109,11 +109,20 @@ public class PostController( return tags; } + /// + /// Begins the creation process of a new post. + /// + /// Post metadata + /// Returns post metadata + /// If request is malformed + /// If authentication is missing + /// If authorization is missing [HttpPost] - [Authorize] + [Authorize(Roles = UserRoles.Regular)] [ProducesResponseType(StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] - [ProducesResponseType(StatusCodes.Status409Conflict)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task> Create(CreatePostDto dto) { var userId = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; @@ -143,7 +152,27 @@ public class PostController( PostDto.FromPost(created.Post, fileUrl)); } + /// + /// Uploads a file chunk of the associated post. + /// + /// Associated post + /// ID of file being uploaded + /// If file chunk was accepted + /// If file was successfully uploaded + /// If request is malformed + /// If authentication is missing + /// If authorization is missing + /// If post or file is not found + /// If finished upload mime does not match provided [HttpPatch("{postId:int}/files/{fileId:int}")] + [Authorize(Roles = UserRoles.Regular)] + [ProducesResponseType(StatusCodes.Status202Accepted)] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status415UnsupportedMediaType)] public async Task PatchFileContent(int postId, int fileId) { var post = await postService.GetById(postId, includeUnfinished: true); @@ -151,11 +180,14 @@ public class PostController( var fileRecord = await fileService.GetFileById(fileId); if (fileRecord == null) return NotFound(); + + // If not the resource owner + var userId = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; + if (userId != post.Author.Id) Forbid(); if (fileRecord.FinishedDate != null) return Problem(statusCode: StatusCodes.Status400BadRequest, detail: "File was already uploaded."); - // Parse the Content-Range Header // Example: Content-Range: bytes 0-1048575/5242880 @@ -214,7 +246,18 @@ public class PostController( return NoContent(); } + /// + /// Get the specified file content of the associated post. + /// + /// Associated post ID + /// File ID + /// The file content + /// If request is malformed + /// If post or file is not found [HttpGet("{postId:int}/files/{fileId:int}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetFileContent(int postId, int fileId) { var post = await postService.GetById(postId, includeUnfinished: true); @@ -242,6 +285,13 @@ public class PostController( return File(stream, fileRecord.ContentType, fileRecord.OriginalFileName); } + /// + /// Get the specified post. + /// + /// Post ID + /// The post content + /// If request is malformed + /// If post is not found [HttpGet("{id:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] @@ -256,6 +306,13 @@ public class PostController( return Ok(PostDto.FromPost(entry, fileUrl)); } + /// + /// Get a paginated list of posts. + /// + /// Query to filter posts by tags. Use +tag-name to require a tag, -tag-name to exclude a tag. + /// The page number. + /// The paginated list + /// If request is malformed [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] @@ -272,11 +329,21 @@ public class PostController( return Ok(new PagedList(newItems, list.CurrentPage, list.PageSize, list.TotalCount)); } - - [Authorize] + /// + /// Delete specified post. + /// + /// Post ID + /// If deleted successfully + /// If request is malformed + /// If authentication is missing + /// If authorization is missing + /// If post is not found + [Authorize(Roles = UserRoles.Regular)] [HttpDelete("{id:int}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task Delete(int id) { @@ -302,7 +369,17 @@ public class PostController( return NoContent(); } - [Authorize] + /// + /// Update specified post. + /// + /// Post ID + /// Post edit data + /// New post data + /// If request is malformed + /// If authentication is missing + /// If authorization is missing + /// If post is not found + [Authorize(Roles = UserRoles.Regular)] [HttpPatch("{id:int}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)]