using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Exceptions; using Kyoo.Abstractions.Models.Permissions; using Microsoft.AspNetCore.Mvc; namespace Kyoo.Core.Api { [ApiController] [ResourceView] public class CrudApi : ControllerBase where T : class, IResource { private readonly IRepository _repository; protected Uri BaseURL { get; } public CrudApi(IRepository repository, Uri baseURL) { _repository = repository; BaseURL = baseURL; } [HttpGet("{id:int}")] [PartialPermission(Kind.Read)] public virtual async Task> Get(int id) { T ret = await _repository.GetOrDefault(id); if (ret == null) return NotFound(); return ret; } [HttpGet("{slug}")] [PartialPermission(Kind.Read)] public virtual async Task> Get(string slug) { T ret = await _repository.GetOrDefault(slug); if (ret == null) return NotFound(); return ret; } [HttpGet("count")] [PartialPermission(Kind.Read)] public virtual async Task> GetCount([FromQuery] Dictionary where) { try { return await _repository.GetCount(ApiHelper.ParseWhere(where)); } catch (ArgumentException ex) { return BadRequest(new { Error = ex.Message }); } } [HttpGet] [PartialPermission(Kind.Read)] public virtual async Task>> GetAll([FromQuery] string sortBy, [FromQuery] int afterID, [FromQuery] Dictionary where, [FromQuery] int limit = 20) { try { ICollection resources = await _repository.GetAll(ApiHelper.ParseWhere(where), new Sort(sortBy), new Pagination(limit, afterID)); return Page(resources, limit); } catch (ArgumentException ex) { return BadRequest(new { Error = ex.Message }); } } protected Page Page(ICollection resources, int limit) where TResult : IResource { return new Page(resources, new Uri(BaseURL, Request.Path), Request.Query.ToDictionary(x => x.Key, x => x.Value.ToString(), StringComparer.InvariantCultureIgnoreCase), limit); } [HttpPost] [PartialPermission(Kind.Create)] public virtual async Task> Create([FromBody] T resource) { try { return await _repository.Create(resource); } catch (ArgumentException ex) { return BadRequest(new { Error = ex.Message }); } catch (DuplicatedItemException) { T existing = await _repository.GetOrDefault(resource.Slug); return Conflict(existing); } } [HttpPut] [PartialPermission(Kind.Write)] public virtual async Task> Edit([FromQuery] bool resetOld, [FromBody] T resource) { try { if (resource.ID > 0) return await _repository.Edit(resource, resetOld); T old = await _repository.Get(resource.Slug); resource.ID = old.ID; return await _repository.Edit(resource, resetOld); } catch (ItemNotFoundException) { return NotFound(); } } [HttpPut("{id:int}")] [PartialPermission(Kind.Write)] public virtual async Task> Edit(int id, [FromQuery] bool resetOld, [FromBody] T resource) { resource.ID = id; try { return await _repository.Edit(resource, resetOld); } catch (ItemNotFoundException) { return NotFound(); } } [HttpPut("{slug}")] [PartialPermission(Kind.Write)] public virtual async Task> Edit(string slug, [FromQuery] bool resetOld, [FromBody] T resource) { try { T old = await _repository.Get(slug); resource.ID = old.ID; return await _repository.Edit(resource, resetOld); } catch (ItemNotFoundException) { return NotFound(); } } [HttpDelete("{id:int}")] [PartialPermission(Kind.Delete)] public virtual async Task Delete(int id) { try { await _repository.Delete(id); } catch (ItemNotFoundException) { return NotFound(); } return Ok(); } [HttpDelete("{slug}")] [PartialPermission(Kind.Delete)] public virtual async Task Delete(string slug) { try { await _repository.Delete(slug); } catch (ItemNotFoundException) { return NotFound(); } return Ok(); } [PartialPermission(Kind.Delete)] public virtual async Task Delete(Dictionary where) { try { await _repository.DeleteAll(ApiHelper.ParseWhere(where)); } catch (ItemNotFoundException) { return NotFound(); } return Ok(); } } }