using System.ComponentModel.DataAnnotations; using DysonNetwork.Sphere.Publisher; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DysonNetwork.Sphere.Connection.WebReader; [Authorize] [ApiController] [Route("/publishers/{pubName}/feeds")] public class WebFeedController(WebFeedService webFeed, PublisherService ps) : ControllerBase { public record WebFeedRequest( [MaxLength(8192)] string? Url, [MaxLength(4096)] string? Title, [MaxLength(8192)] string? Description, WebFeedConfig? Config ); [HttpGet] public async Task ListFeeds([FromRoute] string pubName) { var publisher = await ps.GetPublisherByName(pubName); if (publisher is null) return NotFound(); var feeds = await webFeed.GetFeedsByPublisherAsync(publisher.Id); return Ok(feeds); } [HttpGet("{id:guid}")] public async Task GetFeed([FromRoute] string pubName, Guid id) { var publisher = await ps.GetPublisherByName(pubName); if (publisher is null) return NotFound(); var feed = await webFeed.GetFeedAsync(id, publisherId: publisher.Id); if (feed == null) return NotFound(); return Ok(feed); } [HttpPost] [Authorize] public async Task CreateWebFeed([FromRoute] string pubName, [FromBody] WebFeedRequest request) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); if (string.IsNullOrWhiteSpace(request.Url) || string.IsNullOrWhiteSpace(request.Title)) return BadRequest("Url and title are required"); var publisher = await ps.GetPublisherByName(pubName); if (publisher is null) return NotFound(); if (!await ps.IsMemberWithRole(publisher.Id, currentUser.Id, PublisherMemberRole.Editor)) return StatusCode(403, "You must be an editor of the publisher to create a web feed"); var feed = await webFeed.CreateWebFeedAsync(publisher, request); return Ok(feed); } [HttpPatch("{id:guid}")] [Authorize] public async Task UpdateFeed([FromRoute] string pubName, Guid id, [FromBody] WebFeedRequest request) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); var publisher = await ps.GetPublisherByName(pubName); if (publisher is null) return NotFound(); if (!await ps.IsMemberWithRole(publisher.Id, currentUser.Id, PublisherMemberRole.Editor)) return StatusCode(403, "You must be an editor of the publisher to update a web feed"); var feed = await webFeed.GetFeedAsync(id, publisherId: publisher.Id); if (feed == null) return NotFound(); feed = await webFeed.UpdateFeedAsync(feed, request); return Ok(feed); } [HttpDelete("{id:guid}")] [Authorize] public async Task DeleteFeed([FromRoute] string pubName, Guid id) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); var publisher = await ps.GetPublisherByName(pubName); if (publisher is null) return NotFound(); if (!await ps.IsMemberWithRole(publisher.Id, currentUser.Id, PublisherMemberRole.Editor)) return StatusCode(403, "You must be an editor of the publisher to delete a web feed"); var feed = await webFeed.GetFeedAsync(id, publisherId: publisher.Id); if (feed == null) return NotFound(); var result = await webFeed.DeleteFeedAsync(id); if (!result) return NotFound(); return NoContent(); } [HttpPost("{id:guid}/scrap")] [Authorize] public async Task Scrap([FromRoute] string pubName, Guid id) { if (HttpContext.Items["CurrentUser"] is not Account.Account currentUser) return Unauthorized(); var publisher = await ps.GetPublisherByName(pubName); if (publisher is null) return NotFound(); if (!await ps.IsMemberWithRole(publisher.Id, currentUser.Id, PublisherMemberRole.Editor)) return StatusCode(403, "You must be an editor of the publisher to scrape a web feed"); var feed = await webFeed.GetFeedAsync(id, publisherId: publisher.Id); if (feed == null) { return NotFound(); } await webFeed.ScrapeFeedAsync(feed); return Ok(); } }