using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using DBConnection; using DBConnection.Repositories; using DBConnection.Repositories.Interfaces; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Common.Models.DBDomain; using Common.Models.DTO; using Common.Models.DTO.Requests; using Common.Models.DTO.Responses; using WebNovelPortalAPI.Exceptions; using WebNovelPortalAPI.Scrapers; namespace WebNovelPortalAPI.Controllers { [Route("api/[controller]")] [ApiController] [Authorize] public class NovelController : AuthorizedController { private readonly INovelRepository _novelRepository; private readonly IUserRepository _userRepository; private readonly IEnumerable _scrapers; public NovelController(IEnumerable scrapers, INovelRepository novelRepository, IUserRepository userRepository) { _scrapers = scrapers; _novelRepository = novelRepository; _userRepository = userRepository; } private async Task ScrapeNovel(string url) { var scraper = MatchScraper(url); if (scraper == null) { throw new NoMatchingScraperException(url); } var novel = await scraper.ScrapeNovel(url); return novel; } private IScraper? MatchScraper(string novelUrl) { return _scrapers.FirstOrDefault(i => i.MatchesUrl(novelUrl)); } private async Task GetUser() { return await _userRepository.GetIncluded(u => u.Id == UserId); } [HttpGet] [Route("{guid:guid}")] public async Task GetNovel(Guid guid) { var user = await GetUser(); var novel = await _novelRepository.GetNovel(guid); return user.WatchedNovels.FirstOrDefault(un => un.NovelUrl == novel.Url); } [HttpGet] public async Task> GetNovels() { var user = await GetUser(); var novels = user.WatchedNovels.Select(i => i.Novel); (await _novelRepository.GetWhereIncluded(novels)).ToList(); return user.WatchedNovels.ToList(); } [HttpPost] [Route("scrapeNovels")] public async Task ScrapeNovels(ScrapeNovelsRequest request) { var successfulScrapes = new List(); var failures = new Dictionary(); foreach (var novelUrl in request.NovelUrls) { try { successfulScrapes.Add(await ScrapeNovel(novelUrl)); } catch (Exception e) { failures[novelUrl] = e; } } List successfulUploads; try { successfulUploads = (await _novelRepository.UpsertMany(successfulScrapes, true)).ToList(); var user = await GetUser(); await _userRepository.AssignNovelsToUser(user, successfulUploads); } catch (Exception e) { return StatusCode(500, e); } return Ok(new ScrapeNovelsResponse { Failures = failures, SuccessfulNovels = successfulScrapes }); } [HttpPost] [Route("scrapeNovel")] public async Task ScrapeNovel(ScrapeNovelRequest request) { try { var novel = await ScrapeNovel(request.NovelUrl); var dbNovel = await _novelRepository.Upsert(novel, true); var user = await GetUser(); await _userRepository.AssignNovelsToUser(user, new List {novel}); return Ok(dbNovel); } catch (NoMatchingScraperException e) { return BadRequest("Invalid url, no valid scraper configured"); } catch (Exception e) { return StatusCode(500, e); } } [HttpPatch] [Route("updateLastChapterRead")] public async Task UpdateLastChapterRead(Guid novelGuid, int chapter) { var user = await GetUser(); var novel = await _novelRepository.GetNovel(novelGuid); await _userRepository.UpdateLastChapterRead(user, novel, chapter); return Ok(); } } }