diff options
author | crupest <crupest@outlook.com> | 2020-08-21 21:25:33 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-08-21 21:25:33 +0800 |
commit | 53888df71f7580bf169dfab3d13d313cf96d26df (patch) | |
tree | 6317f1debad6d58ddad04f8767f447e5ae34556d | |
parent | 6fa82cabf2eebec572d23ff49a650e04128d2514 (diff) | |
download | timeline-53888df71f7580bf169dfab3d13d313cf96d26df.tar.gz timeline-53888df71f7580bf169dfab3d13d313cf96d26df.tar.bz2 timeline-53888df71f7580bf169dfab3d13d313cf96d26df.zip |
...
-rw-r--r-- | Timeline/Controllers/TimelineController.cs | 48 | ||||
-rw-r--r-- | Timeline/Controllers/TokenController.cs | 10 | ||||
-rw-r--r-- | Timeline/Controllers/UserAvatarController.cs | 8 | ||||
-rw-r--r-- | Timeline/Controllers/UserController.cs | 39 | ||||
-rw-r--r-- | Timeline/Startup.cs | 2 | ||||
-rw-r--r-- | Timeline/Swagger/ApiConvention.cs | 15 | ||||
-rw-r--r-- | Timeline/Swagger/DefaultDescriptionOperationProcessor.cs | 39 | ||||
-rw-r--r-- | Timeline/Timeline.csproj | 1 |
8 files changed, 86 insertions, 76 deletions
diff --git a/Timeline/Controllers/TimelineController.cs b/Timeline/Controllers/TimelineController.cs index b376bce5..43178ac6 100644 --- a/Timeline/Controllers/TimelineController.cs +++ b/Timeline/Controllers/TimelineController.cs @@ -49,8 +49,7 @@ namespace Timeline.Controllers /// <param name="relate">A username. If set, only timelines related to the user will return.</param>
/// <param name="relateType">Specify the relation type, may be 'own' or 'join'. If not set, both type will return.</param>
/// <param name="visibility">"Private" or "Register" or "Public". If set, only timelines whose visibility is specified one will return.</param>
- /// <response code="200">Succeeded to get timelines.</response>
- /// <response code="400">Model is invalid. Or user specified by "relate" param does not exist.</response>
+ /// <returns>The timeline list.</returns>
[HttpGet("timelines")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
@@ -117,9 +116,7 @@ namespace Timeline.Controllers /// <param name="checkUniqueId">A unique id. If specified and if-modified-since is also specified, the timeline info will return when unique id is not the specified one even if it is not modified.</param>
/// <param name="queryIfModifiedSince">Same effect as If-Modified-Since header and take precedence than it.</param>
/// <param name="headerIfModifiedSince">If specified, will return 304 if not modified.</param>
- /// <response code="200">Succeeded to get timeline info.</response>
- /// <response code="304">Timeline not change.</response>
- /// <response code="404">Timeline does not exist.</response>
+ /// <returns>The timeline info.</returns>
[HttpGet("timelines/{name}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status304NotModified)]
@@ -171,14 +168,12 @@ namespace Timeline.Controllers }
/// <summary>
- /// Get posts of a timeline. You need to have permission.
+ /// Get posts of a timeline.
/// </summary>
/// <param name="name">The name of the timeline.</param>
/// <param name="modifiedSince">If set, only posts modified since the time will return.</param>
/// <param name="includeDeleted">If set to true, deleted post will also return.</param>
- /// <response code="200">Succeeded to get posts.</response>
- /// <response code="403">You have no permission.</response>
- /// <response code="404">The timeline does not exist.</response>
+ /// <returns>The post list.</returns>
[HttpGet("timelines/{name}/posts")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
@@ -197,16 +192,12 @@ namespace Timeline.Controllers }
/// <summary>
- /// Get the data of a post. Usually a image post. You need to have permission.
+ /// Get the data of a post. Usually a image post.
/// </summary>
/// <param name="name">Timeline name.</param>
/// <param name="id">The id of the post.</param>
/// <param name="ifNoneMatch">If-None-Match header.</param>
- /// <response code="200">Succeeded to get data.</response>
- /// <response code="304">Data not changed.</response>
- /// <response code="400">Error code is 11040502 if post has no data.</response>
- /// <response code="403">You have no permission.</response>
- /// <response code="404">Timeline or post does not exist.</response>
+ /// <returns>The data.</returns>
[HttpGet("timelines/{name}/posts/{id}/data")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status304NotModified)]
@@ -240,15 +231,11 @@ namespace Timeline.Controllers }
/// <summary>
- /// Create a new post. You need to have permission.
+ /// Create a new post.
/// </summary>
/// <param name="name">Timeline name.</param>
/// <param name="body"></param>
/// <returns>Info of new post.</returns>
- /// <response code="200">Succeeded to create post and return info of new post.</response>
- /// <response code="400">Body model is invalid.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You have no permission.</response>
[HttpPost("timelines/{name}/posts")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -316,9 +303,7 @@ namespace Timeline.Controllers /// </summary>
/// <param name="name">Timeline name.</param>
/// <param name="id">Post id.</param>
- /// <response code="200">Succeeded to delete post. Or post does not exist.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You have no permission.</response>
+ /// <returns>Info of deletion.</returns>
[HttpDelete("timelines/{name}/posts/{id}")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -347,9 +332,6 @@ namespace Timeline.Controllers /// <param name="name">Timeline name.</param>
/// <param name="body"></param>
/// <returns>The new info.</returns>
- /// <response code="200">Succeeded to change properties of timeline. Return the new info.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You have no permission.</response>
[HttpPatch("timelines/{name}")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -372,10 +354,6 @@ namespace Timeline.Controllers /// </summary>
/// <param name="name">Timeline name.</param>
/// <param name="member">The new member's username.</param>
- /// <response code="200">Succeeded.</response>
- /// <response code="400">User does not exist.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You have no permission.</response>
[HttpPut("timelines/{name}/members/{member}")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -405,9 +383,6 @@ namespace Timeline.Controllers /// </summary>
/// <param name="name">Timeline name.</param>
/// <param name="member">The member's username.</param>
- /// <response code="200">Succeeded. Or the user is not a member.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You have no permission.</response>
[HttpDelete("timelines/{name}/members/{member}")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -436,9 +411,6 @@ namespace Timeline.Controllers /// </summary>
/// <param name="body"></param>
/// <returns>Info of new timeline.</returns>
- /// <response code="200">Succeeded and return info of new timeline.</response>
- /// <response code="400">Timeline name is conflict.</response>
- /// <response code="401">You have not logged in.</response>
[HttpPost("timelines")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
@@ -464,9 +436,7 @@ namespace Timeline.Controllers /// Delete a timeline.
/// </summary>
/// <param name="name">Timeline name.</param>
- /// <response code="200">Succeeded. Or timeline does not exist.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You have no permission.</response>
+ /// <returns>Info of deletion.</returns>
[HttpDelete("timelines/{name}")]
[Authorize]
[ProducesResponseType(StatusCodes.Status200OK)]
diff --git a/Timeline/Controllers/TokenController.cs b/Timeline/Controllers/TokenController.cs index 7792b318..8f2ca600 100644 --- a/Timeline/Controllers/TokenController.cs +++ b/Timeline/Controllers/TokenController.cs @@ -40,11 +40,10 @@ namespace Timeline.Controllers /// <summary>
/// Create a new token for a user.
/// </summary>
- /// <response code="200">Succeed to create token.</response>
- /// <response code="400">Error code is 11010101 if user does not exist or password is wrong.</response>
+ /// <returns>Result of token creation.</returns>
[HttpPost("create")]
[AllowAnonymous]
- [ProducesResponseType(typeof(CreateTokenResponse), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<CreateTokenResponse>> Create([FromBody] CreateTokenRequest request)
{
@@ -91,11 +90,10 @@ namespace Timeline.Controllers /// <summary>
/// Verify a token.
/// </summary>
- /// <response code="200">Token is valid.</response>
- /// <response code="400">Error code is 11010201 if token is of bad format (it may not be created by this server). Error code is 11010202 if user does not exist. Error code is 11010203 if token is of old version (user may have changed password). Error code is 11010204 if token is expired.</response>
+ /// <returns>Result of token verification.</returns>
[HttpPost("verify")]
[AllowAnonymous]
- [ProducesResponseType(typeof(VerifyTokenResponse), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<ActionResult<VerifyTokenResponse>> Verify([FromBody] VerifyTokenRequest request)
{
diff --git a/Timeline/Controllers/UserAvatarController.cs b/Timeline/Controllers/UserAvatarController.cs index 3d3bc983..52e87df2 100644 --- a/Timeline/Controllers/UserAvatarController.cs +++ b/Timeline/Controllers/UserAvatarController.cs @@ -42,9 +42,7 @@ namespace Timeline.Controllers /// </summary>
/// <param name="username">Username of the user to get avatar of.</param>
/// <param name="ifNoneMatch">If-None-Match header.</param>
- /// <response code="200">Succeeded to get the avatar.</response>
- /// <response code="304">The avatar does not change.</response>
- /// <response code="404">The user does not exist.</response>
+ /// <returns>Avatar data.</returns>
[HttpGet("users/{username}/avatar")]
[ProducesResponseType(typeof(byte[]), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status304NotModified)]
@@ -74,10 +72,6 @@ namespace Timeline.Controllers /// Set avatar of a user. You have to be administrator to change other's.
/// </summary>
/// <param name="username">Username of the user to set avatar of.</param>
- /// <response code="200">Succeeded to set avatar.</response>
- /// <response code="400">Error code is 10010001 if user does not exist. Or avatar is of bad format.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You are not administrator.</response>
[HttpPut("users/{username}/avatar")]
[Authorize]
[RequireContentType, RequireContentLength]
diff --git a/Timeline/Controllers/UserController.cs b/Timeline/Controllers/UserController.cs index fa2d37d8..02c09aab 100644 --- a/Timeline/Controllers/UserController.cs +++ b/Timeline/Controllers/UserController.cs @@ -43,9 +43,9 @@ namespace Timeline.Controllers /// <summary>
/// Get all users.
/// </summary>
- /// <response code="200">The user list.</response>
+ /// <returns>All user list.</returns>
[HttpGet("users")]
- [ProducesResponseType(typeof(UserInfo[]), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<UserInfo[]>> List()
{
var users = await _userService.GetUsers();
@@ -54,12 +54,13 @@ namespace Timeline.Controllers }
/// <summary>
- /// Get a user info.
+ /// Get a user's info.
/// </summary>
/// <param name="username">Username of the user.</param>
- /// <response code="200">The user info.</response>
+ /// <returns>User info.</returns>
[HttpGet("users/{username}")]
- [ProducesResponseType(typeof(UserInfo), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<UserInfo>> Get([FromRoute][Username] string username)
{
try
@@ -75,16 +76,14 @@ namespace Timeline.Controllers }
/// <summary>
- /// Change a user's property. You have to be administrator in some condition.
+ /// Change a user's property.
/// </summary>
/// <param name="body"></param>
/// <param name="username">Username of the user to change.</param>
- /// <response code="200">Succeed to change the user and return the new user info.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You are not administrator.</response>
- /// <response code="404">The user to change does not exist.</response>
+ /// <returns>The new user info.</returns>
[HttpPatch("users/{username}"), Authorize]
- [ProducesResponseType(typeof(UserInfo), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
@@ -134,11 +133,9 @@ namespace Timeline.Controllers /// Delete a user and all his related data. You have to be administrator.
/// </summary>
/// <param name="username">Username of the user to delete.</param>
- /// <response code="200">Succeeded to delete or the user does not exist.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You are not administrator.</response>
+ /// <returns>Info of deletion.</returns>
[HttpDelete("users/{username}"), AdminAuthorize]
- [ProducesResponseType(typeof(CommonDeleteResponse), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<CommonDeleteResponse>> Delete([FromRoute][Username] string username)
@@ -153,12 +150,9 @@ namespace Timeline.Controllers /// <summary>
/// Create a new user. You have to be administrator.
/// </summary>
- /// <response code="200">Succeeded to create a new user and return his user info.</response>
- /// <response code="400">Error code is 11020101 if a user with given username already exists.</response>
- /// <response code="401">You have not logged in.</response>
- /// <response code="403">You are not administrator.</response>
+ /// <returns>The new user's info.</returns>
[HttpPost("userop/createuser"), AdminAuthorize]
- [ProducesResponseType(typeof(UserInfo), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
@@ -178,11 +172,8 @@ namespace Timeline.Controllers /// <summary>
/// Change password with old password.
/// </summary>
- /// <response code="200">Succeeded to change password.</response>
- /// <response code="400">Error code is 11020201 if old password is wrong.</response>
- /// <response code="401">You have not logged in.</response>
[HttpPost("userop/changepassword"), Authorize]
- [ProducesResponseType(typeof(void), StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult> ChangePassword([FromBody] ChangePasswordRequest request)
diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs index 3e5dd24d..960bbc2c 100644 --- a/Timeline/Startup.cs +++ b/Timeline/Startup.cs @@ -20,6 +20,7 @@ using Timeline.Helpers; using Timeline.Models.Converters;
using Timeline.Routes;
using Timeline.Services;
+using Timeline.Swagger;
namespace Timeline
{
@@ -112,6 +113,7 @@ namespace Timeline Description = "Type into the textbox: Bearer {your JWT token}."
}));
document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("JWT"));
+ document.OperationProcessors.Add(new DefaultDescriptionOperationProcessor());
});
if (!disableFrontEnd)
diff --git a/Timeline/Swagger/ApiConvention.cs b/Timeline/Swagger/ApiConvention.cs new file mode 100644 index 00000000..dbf0b2fe --- /dev/null +++ b/Timeline/Swagger/ApiConvention.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Mvc;
+
+[assembly: ApiConventionType(typeof(Timeline.Controllers.ApiConvention))]
+
+namespace Timeline.Controllers
+{
+ // There is some bug if nullable is enable. So disable it.
+#nullable disable
+ /// <summary>
+ /// My api convention.
+ /// </summary>
+ public static class ApiConvention
+ {
+ }
+}
diff --git a/Timeline/Swagger/DefaultDescriptionOperationProcessor.cs b/Timeline/Swagger/DefaultDescriptionOperationProcessor.cs new file mode 100644 index 00000000..4967cc6a --- /dev/null +++ b/Timeline/Swagger/DefaultDescriptionOperationProcessor.cs @@ -0,0 +1,39 @@ +using NSwag.Generation.Processors;
+using NSwag.Generation.Processors.Contexts;
+using System.Collections.Generic;
+
+namespace Timeline.Swagger
+{
+ /// <summary>
+ /// Swagger operation processor that adds default description to response.
+ /// </summary>
+ public class DefaultDescriptionOperationProcessor : IOperationProcessor
+ {
+ private readonly Dictionary<string, string> defaultDescriptionMap = new Dictionary<string, string>
+ {
+ ["200"] = "Succeeded to perform the operation.",
+ ["304"] = "Item does not change.",
+ ["400"] = "See code and message for error info.",
+ ["401"] = "You need to log in to perform this operation.",
+ ["403"] = "You have no permission to perform the operation.",
+ ["404"] = "Item does not exist. See code and message for error info."
+ };
+
+ /// <inheritdoc/>
+ public bool Process(OperationProcessorContext context)
+ {
+ var responses = context.OperationDescription.Operation.Responses;
+
+ foreach (var (httpStatusCode, res) in responses)
+ {
+ if (!string.IsNullOrEmpty(res.Description)) continue;
+ if (defaultDescriptionMap.ContainsKey(httpStatusCode))
+ {
+ res.Description = defaultDescriptionMap[httpStatusCode];
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/Timeline/Timeline.csproj b/Timeline/Timeline.csproj index 5c2f7adf..5fc69fc8 100644 --- a/Timeline/Timeline.csproj +++ b/Timeline/Timeline.csproj @@ -17,6 +17,7 @@ <Version>0.3.0</Version>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
+ <IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
</PropertyGroup>
<ItemGroup>
|