158 lines
5.2 KiB
C#
158 lines
5.2 KiB
C#
using System.ComponentModel.DataAnnotations;
|
|
using DysonNetwork.Shared.Proto;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using NodaTime;
|
|
|
|
namespace DysonNetwork.Drive.Storage;
|
|
|
|
[ApiController]
|
|
[Route("/api/bundles")]
|
|
public class BundleController(AppDatabase db) : ControllerBase
|
|
{
|
|
public class BundleRequest
|
|
{
|
|
[MaxLength(1024)] public string? Slug { get; set; }
|
|
[MaxLength(1024)] public string? Name { get; set; }
|
|
[MaxLength(8192)] public string? Description { get; set; }
|
|
[MaxLength(256)] public string? Passcode { get; set; }
|
|
|
|
public Instant? ExpiredAt { get; set; }
|
|
}
|
|
|
|
[HttpGet("{id:guid}")]
|
|
[Authorize]
|
|
public async Task<ActionResult<FileBundle>> GetBundle([FromRoute] Guid id, [FromQuery] string? passcode)
|
|
{
|
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
|
var accountId = Guid.Parse(currentUser.Id);
|
|
|
|
var bundle = await db.Bundles
|
|
.Where(e => e.Id == id)
|
|
.Where(e => e.AccountId == accountId)
|
|
.Include(e => e.Files)
|
|
.FirstOrDefaultAsync();
|
|
if (bundle is null) return NotFound();
|
|
if (!bundle.VerifyPasscode(passcode)) return Forbid();
|
|
|
|
return Ok(bundle);
|
|
}
|
|
|
|
[HttpGet("me")]
|
|
[Authorize]
|
|
public async Task<ActionResult<List<FileBundle>>> ListBundles(
|
|
[FromQuery] string? term,
|
|
[FromQuery] int offset = 0,
|
|
[FromQuery] int take = 20
|
|
)
|
|
{
|
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
|
var accountId = Guid.Parse(currentUser.Id);
|
|
|
|
var query = db.Bundles
|
|
.Where(e => e.AccountId == accountId)
|
|
.OrderByDescending(e => e.CreatedAt)
|
|
.AsQueryable();
|
|
if (!string.IsNullOrEmpty(term))
|
|
query = query.Where(e => EF.Functions.ILike(e.Name, $"%{term}%"));
|
|
|
|
var total = await query.CountAsync();
|
|
Response.Headers.Append("X-Total", total.ToString());
|
|
|
|
var bundles = await query
|
|
.Skip(offset)
|
|
.Take(take)
|
|
.ToListAsync();
|
|
|
|
return Ok(bundles);
|
|
}
|
|
|
|
[HttpPost]
|
|
[Authorize]
|
|
public async Task<ActionResult<FileBundle>> CreateBundle([FromBody] BundleRequest request)
|
|
{
|
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
|
var accountId = Guid.Parse(currentUser.Id);
|
|
|
|
if (currentUser.PerkSubscription is null && !string.IsNullOrEmpty(request.Slug))
|
|
return StatusCode(403, "You must have a subscription to create a bundle with a custom slug");
|
|
if (string.IsNullOrEmpty(request.Slug))
|
|
request.Slug = Guid.NewGuid().ToString("N")[..6];
|
|
if (string.IsNullOrEmpty(request.Name))
|
|
request.Name = "Unnamed Bundle";
|
|
|
|
var bundle = new FileBundle
|
|
{
|
|
Slug = request.Slug,
|
|
Name = request.Name,
|
|
Description = request.Description,
|
|
Passcode = request.Passcode,
|
|
ExpiredAt = request.ExpiredAt,
|
|
AccountId = accountId
|
|
}.HashPasscode();
|
|
|
|
db.Bundles.Add(bundle);
|
|
await db.SaveChangesAsync();
|
|
|
|
return Ok(bundle);
|
|
}
|
|
|
|
[HttpPut("{id:guid}")]
|
|
[Authorize]
|
|
public async Task<ActionResult<FileBundle>> UpdateBundle([FromRoute] Guid id, [FromBody] BundleRequest request)
|
|
{
|
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
|
var accountId = Guid.Parse(currentUser.Id);
|
|
|
|
var bundle = await db.Bundles
|
|
.Where(e => e.Id == id)
|
|
.Where(e => e.AccountId == accountId)
|
|
.FirstOrDefaultAsync();
|
|
if (bundle is null) return NotFound();
|
|
|
|
if (request.Slug != null && request.Slug != bundle.Slug)
|
|
{
|
|
if (currentUser.PerkSubscription is null)
|
|
return StatusCode(403, "You must have a subscription to change the slug of a bundle");
|
|
bundle.Slug = request.Slug;
|
|
}
|
|
|
|
if (request.Name != null) bundle.Name = request.Name;
|
|
if (request.Description != null) bundle.Description = request.Description;
|
|
if (request.ExpiredAt != null) bundle.ExpiredAt = request.ExpiredAt;
|
|
|
|
if (request.Passcode != null)
|
|
{
|
|
bundle.Passcode = request.Passcode;
|
|
bundle = bundle.HashPasscode();
|
|
}
|
|
|
|
await db.SaveChangesAsync();
|
|
|
|
return Ok(bundle);
|
|
}
|
|
|
|
[HttpDelete("{id:guid}")]
|
|
[Authorize]
|
|
public async Task<ActionResult> DeleteBundle([FromRoute] Guid id)
|
|
{
|
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized();
|
|
var accountId = Guid.Parse(currentUser.Id);
|
|
|
|
var bundle = await db.Bundles
|
|
.Where(e => e.Id == id)
|
|
.Where(e => e.AccountId == accountId)
|
|
.FirstOrDefaultAsync();
|
|
if (bundle is null) return NotFound();
|
|
|
|
db.Bundles.Remove(bundle);
|
|
await db.SaveChangesAsync();
|
|
|
|
await db.Files
|
|
.Where(e => e.BundleId == id)
|
|
.ExecuteUpdateAsync(s => s.SetProperty(e => e.IsMarkedRecycle, true));
|
|
|
|
return NoContent();
|
|
}
|
|
} |