UX Overhaul Part 2 (#3112)
Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
parent
0247bc5012
commit
3d8aa2ad24
192 changed files with 14808 additions and 1874 deletions
|
|
@ -1,20 +1,40 @@
|
|||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using API.SignalR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Nager.ArticleNumber;
|
||||
|
||||
namespace API.Controllers;
|
||||
|
||||
public class ChapterController : BaseApiController
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly IEventHub _eventHub;
|
||||
|
||||
public ChapterController(IUnitOfWork unitOfWork)
|
||||
public ChapterController(IUnitOfWork unitOfWork, ILocalizationService localizationService, IEventHub eventHub)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_localizationService = localizationService;
|
||||
_eventHub = eventHub;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single chapter
|
||||
/// </summary>
|
||||
/// <param name="chapterId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<ChapterDto>> GetChapter(int chapterId)
|
||||
{
|
||||
|
|
@ -25,5 +45,234 @@ public class ChapterController : BaseApiController
|
|||
return Ok(chapter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a Chapter
|
||||
/// </summary>
|
||||
/// <param name="chapterId"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize(Policy = "RequireAdminRole")]
|
||||
[HttpDelete]
|
||||
public async Task<ActionResult<bool>> DeleteChapter(int chapterId)
|
||||
{
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(chapterId);
|
||||
if (chapter == null)
|
||||
return BadRequest(_localizationService.Translate(User.GetUserId(), "chapter-doesnt-exist"));
|
||||
|
||||
var vol = (await _unitOfWork.VolumeRepository.GetVolumeAsync(chapter.VolumeId))!;
|
||||
_unitOfWork.ChapterRepository.Remove(chapter);
|
||||
|
||||
if (await _unitOfWork.CommitAsync())
|
||||
{
|
||||
await _eventHub.SendMessageAsync(MessageFactory.ChapterRemoved, MessageFactory.ChapterRemovedEvent(chapter.Id, vol.SeriesId), false);
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update chapter metadata
|
||||
/// </summary>
|
||||
/// <param name="dto"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize(Policy = "RequireAdminRole")]
|
||||
[HttpPost("update")]
|
||||
public async Task<ActionResult> UpdateChapterMetadata(UpdateChapterDto dto)
|
||||
{
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(dto.Id, ChapterIncludes.People | ChapterIncludes.Genres | ChapterIncludes.Tags);
|
||||
if (chapter == null)
|
||||
return BadRequest(_localizationService.Translate(User.GetUserId(), "chapter-doesnt-exist"));
|
||||
|
||||
if (chapter.AgeRating != dto.AgeRating)
|
||||
{
|
||||
chapter.AgeRating = dto.AgeRating;
|
||||
}
|
||||
|
||||
|
||||
if (chapter.Summary != dto.Summary.Trim())
|
||||
{
|
||||
chapter.Summary = dto.Summary.Trim();
|
||||
}
|
||||
|
||||
if (chapter.Language != dto.Language)
|
||||
{
|
||||
chapter.Language = dto.Language ?? string.Empty;
|
||||
}
|
||||
|
||||
if (chapter.SortOrder.IsNot(dto.SortOrder))
|
||||
{
|
||||
chapter.SortOrder = dto.SortOrder; // TODO: Figure out validation
|
||||
}
|
||||
|
||||
if (chapter.TitleName != dto.TitleName)
|
||||
{
|
||||
chapter.TitleName = dto.TitleName;
|
||||
}
|
||||
|
||||
if (chapter.ReleaseDate != dto.ReleaseDate)
|
||||
{
|
||||
chapter.ReleaseDate = dto.ReleaseDate;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(dto.ISBN) && ArticleNumberHelper.IsValidIsbn10(dto.ISBN) ||
|
||||
ArticleNumberHelper.IsValidIsbn13(dto.ISBN))
|
||||
{
|
||||
chapter.ISBN = dto.ISBN;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(dto.WebLinks))
|
||||
{
|
||||
chapter.WebLinks = string.Empty;
|
||||
} else
|
||||
{
|
||||
chapter.WebLinks = string.Join(',', dto.WebLinks
|
||||
.Split(',')
|
||||
.Where(s => !string.IsNullOrEmpty(s))
|
||||
.Select(s => s.Trim())!
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#region Genres
|
||||
if (dto.Genres != null &&
|
||||
dto.Genres.Count != 0)
|
||||
{
|
||||
var allGenres = (await _unitOfWork.GenreRepository.GetAllGenresByNamesAsync(dto.Genres.Select(t => Parser.Normalize(t.Title)))).ToList();
|
||||
chapter.Genres ??= new List<Genre>();
|
||||
GenreHelper.UpdateGenreList(dto.Genres, chapter, allGenres, genre =>
|
||||
{
|
||||
chapter.Genres.Add(genre);
|
||||
}, () => chapter.GenresLocked = true);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Tags
|
||||
if (dto.Tags is {Count: > 0})
|
||||
{
|
||||
var allTags = (await _unitOfWork.TagRepository
|
||||
.GetAllTagsByNameAsync(dto.Tags.Select(t => Parser.Normalize(t.Title))))
|
||||
.ToList();
|
||||
chapter.Tags ??= new List<Tag>();
|
||||
TagHelper.UpdateTagList(dto.Tags, chapter, allTags, tag =>
|
||||
{
|
||||
chapter.Tags.Add(tag);
|
||||
}, () => chapter.TagsLocked = true);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region People
|
||||
if (PersonHelper.HasAnyPeople(dto))
|
||||
{
|
||||
void HandleAddPerson(Person person)
|
||||
{
|
||||
PersonHelper.AddPersonIfNotExists(chapter.People, person);
|
||||
}
|
||||
|
||||
chapter.People ??= new List<Person>();
|
||||
var allWriters = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Writer,
|
||||
dto.Writers.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Writer, dto.Writers, chapter, allWriters.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.WriterLocked = true);
|
||||
|
||||
var allCharacters = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Character,
|
||||
dto.Characters.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Character, dto.Characters, chapter, allCharacters.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.CharacterLocked = true);
|
||||
|
||||
var allColorists = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Colorist,
|
||||
dto.Colorists.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Colorist, dto.Colorists, chapter, allColorists.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.ColoristLocked = true);
|
||||
|
||||
var allEditors = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Editor,
|
||||
dto.Editors.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Editor, dto.Editors, chapter, allEditors.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.EditorLocked = true);
|
||||
|
||||
var allInkers = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Inker,
|
||||
dto.Inkers.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Inker, dto.Inkers, chapter, allInkers.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.InkerLocked = true);
|
||||
|
||||
var allLetterers = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Letterer,
|
||||
dto.Letterers.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Letterer, dto.Letterers, chapter, allLetterers.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.LettererLocked = true);
|
||||
|
||||
var allPencillers = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Penciller,
|
||||
dto.Pencillers.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Penciller, dto.Pencillers, chapter, allPencillers.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.PencillerLocked = true);
|
||||
|
||||
var allPublishers = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Publisher,
|
||||
dto.Publishers.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Publisher, dto.Publishers, chapter, allPublishers.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.PublisherLocked = true);
|
||||
|
||||
var allImprints = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Imprint,
|
||||
dto.Imprints.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Imprint, dto.Imprints, chapter, allImprints.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.ImprintLocked = true);
|
||||
|
||||
var allTeams = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Team,
|
||||
dto.Imprints.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Team, dto.Teams, chapter, allTeams.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.TeamLocked = true);
|
||||
|
||||
var allLocations = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Location,
|
||||
dto.Imprints.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Location, dto.Locations, chapter, allLocations.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.LocationLocked = true);
|
||||
|
||||
var allTranslators = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.Translator,
|
||||
dto.Translators.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.Translator, dto.Translators, chapter, allTranslators.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.TranslatorLocked = true);
|
||||
|
||||
var allCoverArtists = await _unitOfWork.PersonRepository.GetAllPeopleByRoleAndNames(PersonRole.CoverArtist,
|
||||
dto.CoverArtists.Select(p => Parser.Normalize(p.Name)));
|
||||
PersonHelper.UpdatePeopleList(PersonRole.CoverArtist, dto.CoverArtists, chapter, allCoverArtists.AsReadOnly(),
|
||||
HandleAddPerson, () => chapter.CoverArtistLocked = true);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Locks
|
||||
chapter.AgeRatingLocked = dto.AgeRatingLocked;
|
||||
chapter.LanguageLocked = dto.LanguageLocked;
|
||||
chapter.TitleNameLocked = dto.TitleNameLocked;
|
||||
chapter.SortOrderLocked = dto.SortOrderLocked;
|
||||
chapter.GenresLocked = dto.GenresLocked;
|
||||
chapter.TagsLocked = dto.TagsLocked;
|
||||
chapter.CharacterLocked = dto.CharacterLocked;
|
||||
chapter.ColoristLocked = dto.ColoristLocked;
|
||||
chapter.EditorLocked = dto.EditorLocked;
|
||||
chapter.InkerLocked = dto.InkerLocked;
|
||||
chapter.ImprintLocked = dto.ImprintLocked;
|
||||
chapter.LettererLocked = dto.LettererLocked;
|
||||
chapter.PencillerLocked = dto.PencillerLocked;
|
||||
chapter.PublisherLocked = dto.PublisherLocked;
|
||||
chapter.TranslatorLocked = dto.TranslatorLocked;
|
||||
chapter.CoverArtistLocked = dto.CoverArtistLocked;
|
||||
chapter.WriterLocked = dto.WriterLocked;
|
||||
chapter.SummaryLocked = dto.SummaryLocked;
|
||||
chapter.ISBNLocked = dto.ISBNLocked;
|
||||
chapter.ReleaseDateLocked = dto.ReleaseDateLocked;
|
||||
#endregion
|
||||
|
||||
|
||||
if (!_unitOfWork.HasChanges())
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// TODO: Emit a ChapterMetadataUpdate out
|
||||
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class ReadingListController : BaseApiController
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all Reading Lists the user has access to that have a series within it.
|
||||
/// Returns all Reading Lists the user has access to that the given series within it.
|
||||
/// </summary>
|
||||
/// <param name="seriesId"></param>
|
||||
/// <returns></returns>
|
||||
|
|
@ -74,6 +74,18 @@ public class ReadingListController : BaseApiController
|
|||
seriesId, true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all Reading Lists the user has access to that has the given chapter within it.
|
||||
/// </summary>
|
||||
/// <param name="chapterId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("lists-for-chapter")]
|
||||
public async Task<ActionResult<IEnumerable<ReadingListDto>>> GetListsForChapter(int chapterId)
|
||||
{
|
||||
return Ok(await _unitOfWork.ReadingListRepository.GetReadingListDtosForChapterAndUserAsync(User.GetUserId(),
|
||||
chapterId, true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches all reading list items for a given list including rich metadata around series, volume, chapters, and progress
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Constants;
|
||||
using API.Data;
|
||||
|
|
@ -92,28 +93,36 @@ public class UploadController : BaseApiController
|
|||
{
|
||||
// Check if Url is non empty, request the image and place in temp, then ask image service to handle it.
|
||||
// See if we can do this all in memory without touching underlying system
|
||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "url-required"));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(uploadFileDto.Id);
|
||||
|
||||
if (series == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "series-doesnt-exist"));
|
||||
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetSeriesFormat(uploadFileDto.Id)}");
|
||||
|
||||
var filePath = string.Empty;
|
||||
var lockState = false;
|
||||
if (!string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetSeriesFormat(uploadFileDto.Id)}");
|
||||
lockState = uploadFileDto.LockCover;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
series.CoverImage = filePath;
|
||||
series.CoverImageLocked = true;
|
||||
series.CoverImageLocked = lockState;
|
||||
_imageService.UpdateColorScape(series);
|
||||
_unitOfWork.SeriesRepository.Update(series);
|
||||
}
|
||||
|
||||
if (_unitOfWork.HasChanges())
|
||||
{
|
||||
// Refresh covers
|
||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
_taskScheduler.RefreshSeriesMetadata(series.LibraryId, series.Id, true);
|
||||
}
|
||||
|
||||
await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate,
|
||||
MessageFactory.CoverUpdateEvent(series.Id, MessageFactoryEntityTypes.Series), false);
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
|
@ -142,25 +151,24 @@ public class UploadController : BaseApiController
|
|||
{
|
||||
// Check if Url is non empty, request the image and place in temp, then ask image service to handle it.
|
||||
// See if we can do this all in memory without touching underlying system
|
||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "url-required"));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var tag = await _unitOfWork.CollectionTagRepository.GetCollectionAsync(uploadFileDto.Id);
|
||||
if (tag == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "collection-doesnt-exist"));
|
||||
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetCollectionTagFormat(uploadFileDto.Id)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
var filePath = string.Empty;
|
||||
var lockState = false;
|
||||
if (!string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
tag.CoverImage = filePath;
|
||||
tag.CoverImageLocked = true;
|
||||
_imageService.UpdateColorScape(tag);
|
||||
_unitOfWork.CollectionTagRepository.Update(tag);
|
||||
filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetCollectionTagFormat(uploadFileDto.Id)}");
|
||||
lockState = uploadFileDto.LockCover;
|
||||
}
|
||||
|
||||
tag.CoverImage = filePath;
|
||||
tag.CoverImageLocked = lockState;
|
||||
_imageService.UpdateColorScape(tag);
|
||||
_unitOfWork.CollectionTagRepository.Update(tag);
|
||||
|
||||
if (_unitOfWork.HasChanges())
|
||||
{
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
|
@ -189,30 +197,31 @@ public class UploadController : BaseApiController
|
|||
[HttpPost("reading-list")]
|
||||
public async Task<ActionResult> UploadReadingListCoverImageFromUrl(UploadFileDto uploadFileDto)
|
||||
{
|
||||
// Check if Url is non empty, request the image and place in temp, then ask image service to handle it.
|
||||
// Check if Url is non-empty, request the image and place in temp, then ask image service to handle it.
|
||||
// See if we can do this all in memory without touching underlying system
|
||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "url-required"));
|
||||
}
|
||||
|
||||
if (_readingListService.UserHasReadingListAccess(uploadFileDto.Id, User.GetUsername()) == null)
|
||||
if (await _readingListService.UserHasReadingListAccess(uploadFileDto.Id, User.GetUsername()) == null)
|
||||
return Unauthorized(await _localizationService.Translate(User.GetUserId(), "access-denied"));
|
||||
|
||||
try
|
||||
{
|
||||
var readingList = await _unitOfWork.ReadingListRepository.GetReadingListByIdAsync(uploadFileDto.Id);
|
||||
if (readingList == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "reading-list-doesnt-exist"));
|
||||
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetReadingListFormat(uploadFileDto.Id)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
|
||||
var filePath = string.Empty;
|
||||
var lockState = false;
|
||||
if (!string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
readingList.CoverImage = filePath;
|
||||
readingList.CoverImageLocked = true;
|
||||
_imageService.UpdateColorScape(readingList);
|
||||
_unitOfWork.ReadingListRepository.Update(readingList);
|
||||
filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetReadingListFormat(uploadFileDto.Id)}");
|
||||
lockState = uploadFileDto.LockCover;
|
||||
}
|
||||
|
||||
|
||||
readingList.CoverImage = filePath;
|
||||
readingList.CoverImageLocked = lockState;
|
||||
_imageService.UpdateColorScape(readingList);
|
||||
_unitOfWork.ReadingListRepository.Update(readingList);
|
||||
|
||||
if (_unitOfWork.HasChanges())
|
||||
{
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
|
@ -253,33 +262,42 @@ public class UploadController : BaseApiController
|
|||
{
|
||||
// Check if Url is non empty, request the image and place in temp, then ask image service to handle it.
|
||||
// See if we can do this all in memory without touching underlying system
|
||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "url-required"));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(uploadFileDto.Id);
|
||||
if (chapter == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "chapter-doesnt-exist"));
|
||||
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetChapterFormat(uploadFileDto.Id, chapter.VolumeId)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
var filePath = string.Empty;
|
||||
var lockState = false;
|
||||
if (!string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
chapter.CoverImage = filePath;
|
||||
chapter.CoverImageLocked = true;
|
||||
_unitOfWork.ChapterRepository.Update(chapter);
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(chapter.VolumeId);
|
||||
if (volume != null)
|
||||
{
|
||||
volume.CoverImage = chapter.CoverImage;
|
||||
_unitOfWork.VolumeRepository.Update(volume);
|
||||
}
|
||||
filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetChapterFormat(uploadFileDto.Id, chapter.VolumeId)}");
|
||||
lockState = uploadFileDto.LockCover;
|
||||
}
|
||||
|
||||
chapter.CoverImage = filePath;
|
||||
chapter.CoverImageLocked = lockState;
|
||||
_unitOfWork.ChapterRepository.Update(chapter);
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(chapter.VolumeId);
|
||||
if (volume != null)
|
||||
{
|
||||
volume.CoverImage = chapter.CoverImage;
|
||||
volume.CoverImageLocked = lockState;
|
||||
_unitOfWork.VolumeRepository.Update(volume);
|
||||
}
|
||||
|
||||
if (_unitOfWork.HasChanges())
|
||||
{
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
// Refresh covers
|
||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
var series = (await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume!.SeriesId))!;
|
||||
_taskScheduler.RefreshSeriesMetadata(series.LibraryId, series.Id, true);
|
||||
}
|
||||
|
||||
|
||||
await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate,
|
||||
MessageFactory.CoverUpdateEvent(chapter.VolumeId, MessageFactoryEntityTypes.Volume), false);
|
||||
await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate,
|
||||
|
|
@ -310,11 +328,6 @@ public class UploadController : BaseApiController
|
|||
{
|
||||
// Check if Url is non empty, request the image and place in temp, then ask image service to handle it.
|
||||
// See if we can do this all in memory without touching underlying system
|
||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "url-required"));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(uploadFileDto.Id, VolumeIncludes.Chapters);
|
||||
|
|
@ -323,24 +336,37 @@ public class UploadController : BaseApiController
|
|||
// Find the first chapter of the volume
|
||||
var chapter = volume.Chapters[0];
|
||||
|
||||
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetChapterFormat(chapter.Id, uploadFileDto.Id)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
var filePath = string.Empty;
|
||||
var lockState = false;
|
||||
if (!string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
chapter.CoverImage = filePath;
|
||||
chapter.CoverImageLocked = true;
|
||||
_imageService.UpdateColorScape(chapter);
|
||||
_unitOfWork.ChapterRepository.Update(chapter);
|
||||
|
||||
volume.CoverImage = chapter.CoverImage;
|
||||
_imageService.UpdateColorScape(volume);
|
||||
_unitOfWork.VolumeRepository.Update(volume);
|
||||
filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetChapterFormat(chapter.Id, uploadFileDto.Id)}");
|
||||
lockState = uploadFileDto.LockCover;
|
||||
}
|
||||
|
||||
|
||||
chapter.CoverImage = filePath;
|
||||
chapter.CoverImageLocked = lockState;
|
||||
_imageService.UpdateColorScape(chapter);
|
||||
_unitOfWork.ChapterRepository.Update(chapter);
|
||||
|
||||
volume.CoverImage = chapter.CoverImage;
|
||||
volume.CoverImageLocked = lockState;
|
||||
_imageService.UpdateColorScape(volume);
|
||||
_unitOfWork.VolumeRepository.Update(volume);
|
||||
|
||||
if (_unitOfWork.HasChanges())
|
||||
{
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
// Refresh covers
|
||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
var series = (await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId))!;
|
||||
_taskScheduler.RefreshSeriesMetadata(series.LibraryId, series.Id, true);
|
||||
}
|
||||
|
||||
|
||||
await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate,
|
||||
MessageFactory.CoverUpdateEvent(chapter.VolumeId, MessageFactoryEntityTypes.Volume), false);
|
||||
await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate,
|
||||
|
|
@ -426,6 +452,7 @@ public class UploadController : BaseApiController
|
|||
/// <returns></returns>
|
||||
[Authorize(Policy = "RequireAdminRole")]
|
||||
[HttpPost("reset-chapter-lock")]
|
||||
[Obsolete("Use LockCover in UploadFileDto")]
|
||||
public async Task<ActionResult> ResetChapterLock(UploadFileDto uploadFileDto)
|
||||
{
|
||||
try
|
||||
|
|
@ -461,4 +488,6 @@ public class UploadController : BaseApiController
|
|||
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "reset-chapter-lock"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
54
API/Controllers/VolumeController.cs
Normal file
54
API/Controllers/VolumeController.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs;
|
||||
using API.Extensions;
|
||||
using API.Services;
|
||||
using API.SignalR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace API.Controllers;
|
||||
|
||||
public class VolumeController : BaseApiController
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly IEventHub _eventHub;
|
||||
|
||||
public VolumeController(IUnitOfWork unitOfWork, ILocalizationService localizationService, IEventHub eventHub)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_localizationService = localizationService;
|
||||
_eventHub = eventHub;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<VolumeDto>> GetVolume(int volumeId)
|
||||
{
|
||||
var volume =
|
||||
await _unitOfWork.VolumeRepository.GetVolumeDtoAsync(volumeId, User.GetUserId());
|
||||
|
||||
return Ok(volume);
|
||||
}
|
||||
|
||||
[Authorize(Policy = "RequireAdminRole")]
|
||||
[HttpDelete]
|
||||
public async Task<ActionResult<bool>> DeleteVolume(int volumeId)
|
||||
{
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(volumeId,
|
||||
VolumeIncludes.Chapters | VolumeIncludes.People | VolumeIncludes.Tags);
|
||||
if (volume == null)
|
||||
return BadRequest(_localizationService.Translate(User.GetUserId(), "chapter-doesnt-exist"));
|
||||
|
||||
_unitOfWork.VolumeRepository.Remove(volume);
|
||||
|
||||
if (await _unitOfWork.CommitAsync())
|
||||
{
|
||||
await _eventHub.SendMessageAsync(MessageFactory.VolumeRemoved, MessageFactory.VolumeRemovedEvent(volume.Id, volume.SeriesId), false);
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue