Files
Moonlight/Moonlight.Api/Http/Controllers/Admin/ApiKeyController.cs

143 lines
4.4 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Hybrid;
using Moonlight.Api.Database;
using Moonlight.Api.Database.Entities;
using Moonlight.Api.Implementations.ApiKeyScheme;
using Moonlight.Api.Mappers;
using Moonlight.Shared;
using Moonlight.Shared.Http.Requests;
using Moonlight.Shared.Http.Requests.Admin.ApiKeys;
using Moonlight.Shared.Http.Responses;
using Moonlight.Shared.Http.Responses.Admin.ApiKeys;
namespace Moonlight.Api.Http.Controllers.Admin;
[Authorize]
[ApiController]
[Route("api/admin/apiKeys")]
public class ApiKeyController : Controller
{
private readonly DatabaseRepository<ApiKey> KeyRepository;
private readonly HybridCache HybridCache;
public ApiKeyController(DatabaseRepository<ApiKey> keyRepository, HybridCache hybridCache)
{
KeyRepository = keyRepository;
HybridCache = hybridCache;
}
[HttpGet]
[Authorize(Policy = Permissions.ApiKeys.View)]
public async Task<ActionResult<PagedData<ApiKeyDto>>> GetAsync(
[FromQuery] int startIndex,
[FromQuery] int length,
[FromQuery] FilterOptions? filterOptions
)
{
// Validation
if (startIndex < 0)
return Problem("Invalid start index specified", statusCode: 400);
if (length is < 1 or > 100)
return Problem("Invalid length specified");
// Query building
var query = KeyRepository.Query();
// Filters
if (filterOptions != null)
{
foreach (var filterOption in filterOptions.Filters)
{
query = filterOption.Key switch
{
nameof(ApiKey.Name) =>
query.Where(k => EF.Functions.ILike(k.Name, $"%{filterOption.Value}%")),
nameof(ApiKey.Description) =>
query.Where(k => EF.Functions.ILike(k.Description, $"%{filterOption.Value}%")),
_ => query
};
}
}
// Pagination
var data = await query
.OrderBy(k => k.Id)
.ProjectToDto()
.Skip(startIndex)
.Take(length)
.ToArrayAsync();
var total = await query.CountAsync();
return new PagedData<ApiKeyDto>(data, total);
}
[HttpGet("{id:int}")]
[Authorize(Policy = Permissions.ApiKeys.View)]
public async Task<ActionResult<ApiKeyDto>> GetAsync([FromRoute] int id)
{
var key = await KeyRepository
.Query()
.FirstOrDefaultAsync(k => k.Id == id);
if (key == null)
return Problem("No API key with this id found", statusCode: 404);
return ApiKeyMapper.ToDto(key);
}
[HttpPost]
[Authorize(Policy = Permissions.ApiKeys.Create)]
public async Task<ActionResult<ApiKeyDto>> CreateAsync([FromBody] CreateApiKeyDto request)
{
var apiKey = ApiKeyMapper.ToEntity(request);
apiKey.Key = Guid.NewGuid().ToString("N").Substring(0, 32);
var finalKey = await KeyRepository.AddAsync(apiKey);
return ApiKeyMapper.ToDto(finalKey);
}
[HttpPatch("{id:int}")]
[Authorize(Policy = Permissions.ApiKeys.Edit)]
public async Task<ActionResult<ApiKeyDto>> UpdateAsync([FromRoute] int id, [FromBody] UpdateApiKeyDto request)
{
var apiKey = await KeyRepository
.Query()
.FirstOrDefaultAsync(k => k.Id == id);
if (apiKey == null)
return Problem("No API key with this id found", statusCode: 404);
ApiKeyMapper.Merge(apiKey, request);
await KeyRepository.UpdateAsync(apiKey);
await HybridCache.RemoveAsync(string.Format(ApiKeySchemeHandler.CacheKeyFormat, apiKey.Key));
return ApiKeyMapper.ToDto(apiKey);
}
[HttpDelete("{id:int}")]
[Authorize(Policy = Permissions.ApiKeys.Delete)]
public async Task<ActionResult> DeleteAsync([FromRoute] int id)
{
var apiKey = await KeyRepository
.Query()
.FirstOrDefaultAsync(k => k.Id == id);
if (apiKey == null)
return Problem("No API key with this id found", statusCode: 404);
await KeyRepository.RemoveAsync(apiKey);
await HybridCache.RemoveAsync(string.Format(ApiKeySchemeHandler.CacheKeyFormat, apiKey.Key));
return NoContent();
}
}