mirror of
https://git.v0l.io/Kieran/void.cat.git
synced 2025-04-10 01:49:03 +02:00
Add swagger and docs
This commit is contained in:
parent
22877e214b
commit
d7d092bc63
3
.gitignore
vendored
3
.gitignore
vendored
@ -15,4 +15,5 @@ out/
|
||||
sw.js
|
||||
.DS_Store
|
||||
.idea/
|
||||
appsettings.*.json
|
||||
appsettings.*.json
|
||||
VoidCat.xml
|
@ -20,6 +20,11 @@ public class AdminController : Controller
|
||||
_fileInfo = fileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all files in the system
|
||||
/// </summary>
|
||||
/// <param name="request">Page request</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route("file")]
|
||||
public async Task<RenderedResults<PublicVoidFile>> ListFiles([FromBody] PagedRequest request)
|
||||
@ -27,6 +32,10 @@ public class AdminController : Controller
|
||||
return await (await _fileStore.ListFiles(request)).GetResults();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a file from the system
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the file to delete</param>
|
||||
[HttpDelete]
|
||||
[Route("file/{id}")]
|
||||
public async Task DeleteFile([FromRoute] string id)
|
||||
@ -36,6 +45,11 @@ public class AdminController : Controller
|
||||
await _fileInfo.Delete(gid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List all users in the system
|
||||
/// </summary>
|
||||
/// <param name="request">Page request</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route("user")]
|
||||
public async Task<RenderedResults<PrivateVoidUser>> ListUsers([FromBody] PagedRequest request)
|
||||
|
@ -22,6 +22,11 @@ public class AuthController : Controller
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Login to a user account
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route("login")]
|
||||
public async Task<LoginResponse> Login([FromBody] LoginRequest req)
|
||||
@ -45,6 +50,11 @@ public class AuthController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a new account
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route("register")]
|
||||
public async Task<LoginResponse> Register([FromBody] LoginRequest req)
|
||||
|
@ -31,6 +31,10 @@ public class DownloadController : Controller
|
||||
return SetupDownload(gid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download a specific file by Id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
[ResponseCache(Location = ResponseCacheLocation.Any, Duration = 86400)]
|
||||
[HttpGet]
|
||||
[Route("{id}")]
|
||||
|
@ -16,6 +16,11 @@ namespace VoidCat.Controllers
|
||||
_fileStore = fileStore;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Return system info
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[ResponseCache(Location = ResponseCacheLocation.Any, Duration = 60)]
|
||||
public async Task<GlobalStats> GetGlobalStats()
|
||||
@ -33,6 +38,11 @@ namespace VoidCat.Controllers
|
||||
return new(bw, bytes, count, BuildInfo.GetBuildInfo());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get stats for a specific file
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route("{id}")]
|
||||
public async Task<FileStats> GetFileStats([FromRoute] string id)
|
||||
|
@ -27,6 +27,20 @@ namespace VoidCat.Controllers
|
||||
_fileInfo = fileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Primary upload endpoint
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Additional optional headers can be included to provide details about the file being uploaded:
|
||||
///
|
||||
/// `V-Content-Type` - Sets the `mimeType` of the file and is used on the preview page to display the file.
|
||||
/// `V-Filename` - Sets the filename of the file.
|
||||
/// `V-Description` - Sets the description of the file.
|
||||
/// `V-Full-Digest` - Include a SHA256 hash of the entire file for verification purposes.
|
||||
/// `V-Digest` - A SHA256 hash of the data you are sending in this request.
|
||||
/// </remarks>
|
||||
/// <param name="cli">True if you want to return only the url of the file in the response</param>
|
||||
/// <returns>Returns <see cref="UploadResult"/></returns>
|
||||
[HttpPost]
|
||||
[DisableRequestSizeLimit]
|
||||
[DisableFormValueModelBinding]
|
||||
@ -67,6 +81,18 @@ namespace VoidCat.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append data onto a file
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This endpoint is mainly used to bypass file upload limits enforced by CloudFlare.
|
||||
/// Clients should split their uploads into segments, upload the first segment to the regular
|
||||
/// upload endpoint, use the `editSecret` to append data to the file.
|
||||
///
|
||||
/// Set the edit secret in the header `V-EditSecret` otherwise you will not be able to append data.
|
||||
/// </remarks>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[DisableRequestSizeLimit]
|
||||
[DisableFormValueModelBinding]
|
||||
@ -97,6 +123,11 @@ namespace VoidCat.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return information about a specific file
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route("{id}")]
|
||||
public ValueTask<PublicVoidFile?> GetInfo([FromRoute] string id)
|
||||
@ -104,6 +135,11 @@ namespace VoidCat.Controllers
|
||||
return _fileInfo.Get(id.FromBase58Guid());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a paywall order to pay
|
||||
/// </summary>
|
||||
/// <param name="id">File id</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route("{id}/paywall")]
|
||||
public async ValueTask<PaywallOrder?> CreateOrder([FromRoute] string id)
|
||||
@ -116,6 +152,12 @@ namespace VoidCat.Controllers
|
||||
return await provider.CreateOrder(file!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the status of an order
|
||||
/// </summary>
|
||||
/// <param name="id">File id</param>
|
||||
/// <param name="order">Order id</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route("{id}/paywall/{order:guid}")]
|
||||
public async ValueTask<PaywallOrder?> GetOrderStatus([FromRoute] string id, [FromRoute] Guid order)
|
||||
@ -127,6 +169,12 @@ namespace VoidCat.Controllers
|
||||
return await provider.GetOrderStatus(order);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the paywall config
|
||||
/// </summary>
|
||||
/// <param name="id">File id</param>
|
||||
/// <param name="req">Requested config to set on the file</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route("{id}/paywall")]
|
||||
public async Task<IActionResult> SetPaywallConfig([FromRoute] string id, [FromBody] SetPaywallConfigRequest req)
|
||||
|
@ -18,13 +18,23 @@ public class UserController : Controller
|
||||
_emailVerification = emailVerification;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return user profile
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You do not need to be logged in to return a user profile if their profile is set to public.
|
||||
///
|
||||
/// You may also use `me` as the `id` to get the logged in users profile.
|
||||
/// </remarks>
|
||||
/// <param name="id">User id to load</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetUser([FromRoute] string id)
|
||||
{
|
||||
var loggedUser = HttpContext.GetUserId();
|
||||
var isMe = id.Equals("me", StringComparison.InvariantCultureIgnoreCase);
|
||||
if (isMe && !loggedUser.HasValue) return Unauthorized();
|
||||
|
||||
|
||||
var requestedId = isMe ? loggedUser!.Value : id.FromBase58Guid();
|
||||
if (loggedUser == requestedId)
|
||||
{
|
||||
@ -39,6 +49,13 @@ public class UserController : Controller
|
||||
return Json(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update profile settings
|
||||
/// </summary>
|
||||
///
|
||||
/// <param name="id">User id</param>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> UpdateUser([FromRoute] string id, [FromBody] PublicVoidUser user)
|
||||
{
|
||||
@ -51,6 +68,16 @@ public class UserController : Controller
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a list of files which the user has uploaded
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will return files if the profile has public uploads set on their profile.
|
||||
/// Otherwise you can return your own uploaded files if you are logged in.
|
||||
/// </remarks>
|
||||
/// <param name="id">User id</param>
|
||||
/// <param name="request">Page request</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route("files")]
|
||||
public async Task<IActionResult> ListUserFiles([FromRoute] string id,
|
||||
@ -71,6 +98,11 @@ public class UserController : Controller
|
||||
return Json(await results.GetResults());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a verification code for a specific user
|
||||
/// </summary>
|
||||
/// <param name="id">User id to send code for</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Route("verify")]
|
||||
public async Task<IActionResult> SendVerificationCode([FromRoute] string id)
|
||||
@ -85,6 +117,12 @@ public class UserController : Controller
|
||||
return Accepted();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Confirm email verification code
|
||||
/// </summary>
|
||||
/// <param name="id">User id to verify</param>
|
||||
/// <param name="code">Verification code to check</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Route("verify")]
|
||||
public async Task<IActionResult> VerifyCode([FromRoute] string id, [FromBody] string code)
|
||||
|
@ -1,5 +1,8 @@
|
||||
namespace VoidCat.Model.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// Specified file was not found
|
||||
/// </summary>
|
||||
public class VoidFileNotFoundException : Exception
|
||||
{
|
||||
public VoidFileNotFoundException(Guid id)
|
||||
|
17
VoidCat/Model/Exceptions/VoidInvalidIdException.cs
Normal file
17
VoidCat/Model/Exceptions/VoidInvalidIdException.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace VoidCat.Model.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// Specified id was not in the correct format
|
||||
/// </summary>
|
||||
public class VoidInvalidIdException : Exception
|
||||
{
|
||||
public VoidInvalidIdException(string id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The id in question
|
||||
/// </summary>
|
||||
public string Id { get; }
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
namespace VoidCat.Model.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// Operation is not allowed
|
||||
/// </summary>
|
||||
public class VoidNotAllowedException : Exception
|
||||
{
|
||||
public VoidNotAllowedException(string message) : base(message)
|
||||
|
@ -1,10 +1,10 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Amazon;
|
||||
using Amazon.Runtime;
|
||||
using Amazon.S3;
|
||||
using VoidCat.Model.Exceptions;
|
||||
|
||||
namespace VoidCat.Model;
|
||||
|
||||
@ -42,7 +42,9 @@ public static class Extensions
|
||||
public static Guid FromBase58Guid(this string base58)
|
||||
{
|
||||
var enc = new NBitcoin.DataEncoders.Base58Encoder();
|
||||
return new Guid(enc.DecodeData(base58));
|
||||
var guidBytes = enc.DecodeData(base58);
|
||||
if (guidBytes.Length != 16) throw new VoidInvalidIdException(base58);
|
||||
return new Guid(guidBytes);
|
||||
}
|
||||
|
||||
public static string ToBase58(this Guid id)
|
||||
|
@ -1,6 +1,8 @@
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Prometheus;
|
||||
using StackExchange.Redis;
|
||||
@ -48,6 +50,32 @@ if (useRedis)
|
||||
}
|
||||
|
||||
services.AddHttpClient();
|
||||
services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
In = ParameterLocation.Header,
|
||||
Description = "Please insert JWT with Bearer into field",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.ApiKey
|
||||
});
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
new string[] { }
|
||||
}
|
||||
});
|
||||
var path = Path.Combine(AppContext.BaseDirectory, $"{Assembly.GetExecutingAssembly().GetName().Name}.xml");
|
||||
c.IncludeXmlComments(path);
|
||||
});
|
||||
services.AddCors(opt =>
|
||||
{
|
||||
opt.AddDefaultPolicy(p =>
|
||||
@ -76,7 +104,10 @@ services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
};
|
||||
});
|
||||
|
||||
services.AddAuthorization((opt) => { opt.AddPolicy(Policies.RequireAdmin, (auth) => { auth.RequireRole(Roles.Admin); }); });
|
||||
services.AddAuthorization((opt) =>
|
||||
{
|
||||
opt.AddPolicy(Policies.RequireAdmin, (auth) => { auth.RequireRole(Roles.Admin); });
|
||||
});
|
||||
|
||||
// void.cat services
|
||||
//
|
||||
@ -135,6 +166,8 @@ app.UseStaticFiles();
|
||||
|
||||
app.UseRouting();
|
||||
app.UseCors();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
@ -148,4 +181,4 @@ app.UseEndpoints(ep =>
|
||||
#endif
|
||||
});
|
||||
|
||||
app.Run();
|
||||
app.Run();
|
@ -86,9 +86,12 @@ public class UserStore : IUserStore
|
||||
var oldUser = await Get<InternalVoidUser>(newUser.Id);
|
||||
if (oldUser == null) return;
|
||||
|
||||
//retain flags
|
||||
var isEmailVerified = oldUser.Flags.HasFlag(VoidUserFlags.EmailVerified);
|
||||
|
||||
// update only a few props
|
||||
oldUser.Avatar = newUser.Avatar;
|
||||
oldUser.Flags = newUser.Flags;
|
||||
oldUser.Flags = newUser.Flags | (isEmailVerified ? VoidUserFlags.EmailVerified : 0);
|
||||
oldUser.DisplayName = newUser.DisplayName;
|
||||
|
||||
await Set(newUser.Id, oldUser);
|
||||
|
@ -9,6 +9,7 @@
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
|
||||
<HostSPA>True</HostSPA>
|
||||
<DefineConstants Condition="'$(HostSPA)' == 'True'">$(DefineConstants);HostSPA</DefineConstants>
|
||||
<DocumentationFile>$(AssemblyName).xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
Loading…
x
Reference in New Issue
Block a user