mirror of
https://github.com/Kareadita/Kavita.git
synced 2026-06-06 06:45:18 -04:00
Progress Overhaul + Profile Page and a LOT more! (#4262)
Co-authored-by: Amelia <77553571+Fesaa@users.noreply.github.com> Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading.Tasks;
|
||||
using API.Constants;
|
||||
using API.Data;
|
||||
@@ -13,9 +12,11 @@ using API.DTOs.Progress;
|
||||
using API.DTOs.Reader;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Entities.Progress;
|
||||
using API.Middleware;
|
||||
using API.Services;
|
||||
using API.Services.Plus;
|
||||
using API.Services.Reading;
|
||||
using API.Services.Tasks.Metadata;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using API.SignalR;
|
||||
@@ -71,25 +72,28 @@ public class ReaderController : BaseApiController
|
||||
/// Returns the PDF for the chapterId.
|
||||
/// </summary>
|
||||
/// <param name="chapterId"></param>
|
||||
/// <param name="apiKey">Auth Key for authentication</param>
|
||||
/// <param name="extractPdf">Converts PDF into images per-page - Used for Mihon mainly</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("pdf")]
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["chapterId", "apiKey"])]
|
||||
[SkipDeviceTracking]
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["chapterId", "apiKey", "extractPdf"])]
|
||||
public async Task<ActionResult> GetPdf(int chapterId, string apiKey, bool extractPdf = false)
|
||||
{
|
||||
if (await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey) == 0) return BadRequest();
|
||||
if (!UserContext.IsAuthenticated) return Unauthorized();
|
||||
var chapter = await _cacheService.Ensure(chapterId, extractPdf);
|
||||
if (chapter == null) return NoContent();
|
||||
|
||||
// Validate the user has access to the PDF
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesForChapter(chapter.Id,
|
||||
await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()));
|
||||
if (series == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "invalid-access"));
|
||||
await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(Username!));
|
||||
if (series == null) return BadRequest(await _localizationService.Translate(UserId, "invalid-access"));
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var path = _cacheService.GetCachedFile(chapter);
|
||||
if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest(await _localizationService.Translate(User.GetUserId(), "pdf-doesnt-exist"));
|
||||
if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path)) return BadRequest(await _localizationService.Translate(UserId, "pdf-doesnt-exist"));
|
||||
|
||||
return PhysicalFile(path, MimeTypeMap.GetMimeType(Path.GetExtension(path)), Path.GetFileName(path), true);
|
||||
}
|
||||
@@ -110,13 +114,14 @@ public class ReaderController : BaseApiController
|
||||
/// <param name="extractPdf">Should Kavita extract pdf into images. Defaults to false.</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("image")]
|
||||
[SkipDeviceTracking]
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["chapterId", "page", "extractPdf", "apiKey"
|
||||
])]
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> GetImage(int chapterId, int page, string apiKey, bool extractPdf = false)
|
||||
{
|
||||
if (page < 0) page = 0;
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByAuthKeyAsync(apiKey);
|
||||
if (userId == 0) return BadRequest();
|
||||
|
||||
try
|
||||
@@ -146,11 +151,12 @@ public class ReaderController : BaseApiController
|
||||
/// <param name="apiKey"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("thumbnail")]
|
||||
[SkipDeviceTracking]
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["chapterId", "pageNum", "apiKey"])]
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> GetThumbnail(int chapterId, int pageNum, string apiKey)
|
||||
{
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByAuthKeyAsync(apiKey);
|
||||
if (userId == 0) return BadRequest();
|
||||
var chapter = await _cacheService.Ensure(chapterId, true);
|
||||
if (chapter == null) return NoContent();
|
||||
@@ -170,11 +176,12 @@ public class ReaderController : BaseApiController
|
||||
/// <remarks>We must use api key as bookmarks could be leaked to other users via the API</remarks>
|
||||
/// <returns></returns>
|
||||
[HttpGet("bookmark-image")]
|
||||
[SkipDeviceTracking]
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["seriesId", "page", "apiKey"])]
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> GetBookmarkImage(int seriesId, string apiKey, int page)
|
||||
{
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByAuthKeyAsync(apiKey);
|
||||
if (userId == 0) return Unauthorized();
|
||||
|
||||
if (page < 0) page = 0;
|
||||
@@ -208,6 +215,7 @@ public class ReaderController : BaseApiController
|
||||
/// <param name="extractPdf"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("file-dimensions")]
|
||||
[SkipDeviceTracking]
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["chapterId", "extractPdf"])]
|
||||
public async Task<ActionResult<IEnumerable<FileDimensionDto>>> GetFileDimensions(int chapterId, bool extractPdf = false)
|
||||
{
|
||||
@@ -235,10 +243,10 @@ public class ReaderController : BaseApiController
|
||||
if (chapter == null) return NoContent();
|
||||
|
||||
var dto = await _unitOfWork.ChapterRepository.GetChapterInfoDtoAsync(chapterId);
|
||||
if (dto == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "perform-scan"));
|
||||
if (dto == null) return BadRequest(await _localizationService.Translate(UserId, "perform-scan"));
|
||||
var mangaFile = chapter.Files.First();
|
||||
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(dto.SeriesId, User.GetUserId());
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(dto.SeriesId, UserId);
|
||||
if (series == null) return Unauthorized();
|
||||
|
||||
var info = new ChapterInfoDto()
|
||||
@@ -280,7 +288,7 @@ public class ReaderController : BaseApiController
|
||||
}
|
||||
else
|
||||
{
|
||||
info.Subtitle = await _localizationService.Translate(User.GetUserId(), "volume-num", info.VolumeNumber);
|
||||
info.Subtitle = await _localizationService.Translate(UserId, "volume-num", info.VolumeNumber);
|
||||
if (!info.ChapterNumber.Equals(Parser.DefaultChapter))
|
||||
{
|
||||
info.Subtitle += " " + ReaderService.FormatChapterName(info.LibraryType, true, true) +
|
||||
@@ -302,7 +310,7 @@ public class ReaderController : BaseApiController
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["seriesId", "includeDimensions"])]
|
||||
public async Task<ActionResult<BookmarkInfoDto>> GetBookmarkInfo(int seriesId, bool includeDimensions = true)
|
||||
{
|
||||
var totalPages = await _cacheService.CacheBookmarkForSeries(User.GetUserId(), seriesId);
|
||||
var totalPages = await _cacheService.CacheBookmarkForSeries(UserId, seriesId);
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId, SeriesIncludes.None);
|
||||
|
||||
var info = new BookmarkInfoDto()
|
||||
@@ -332,7 +340,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("mark-read")]
|
||||
public async Task<ActionResult> MarkRead(MarkReadDto markReadDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
try
|
||||
{
|
||||
@@ -340,10 +348,10 @@ public class ReaderController : BaseApiController
|
||||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), ex.Message));
|
||||
return BadRequest(await _localizationService.Translate(UserId, ex.Message));
|
||||
}
|
||||
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-read-progress"));
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(UserId, "generic-read-progress"));
|
||||
|
||||
BackgroundJob.Enqueue(() => _scrobblingService.ScrobbleReadingUpdate(user.Id, markReadDto.SeriesId));
|
||||
BackgroundJob.Enqueue(() => _unitOfWork.SeriesRepository.ClearOnDeckRemoval(markReadDto.SeriesId, user.Id));
|
||||
@@ -359,11 +367,11 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("mark-unread")]
|
||||
public async Task<ActionResult> MarkUnread(MarkReadDto markReadDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
await _readerService.MarkSeriesAsUnread(user, markReadDto.SeriesId);
|
||||
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-read-progress"));
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(UserId, "generic-read-progress"));
|
||||
|
||||
BackgroundJob.Enqueue(() => _scrobblingService.ScrobbleReadingUpdate(user.Id, markReadDto.SeriesId));
|
||||
return Ok();
|
||||
@@ -377,13 +385,13 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("mark-volume-unread")]
|
||||
public async Task<ActionResult> MarkVolumeAsUnread(MarkVolumeReadDto markVolumeReadDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
|
||||
var chapters = await _unitOfWork.ChapterRepository.GetChaptersAsync(markVolumeReadDto.VolumeId);
|
||||
await _readerService.MarkChaptersAsUnread(user, markVolumeReadDto.SeriesId, chapters);
|
||||
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-read-progress"));
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(UserId, "generic-read-progress"));
|
||||
|
||||
BackgroundJob.Enqueue(() => _scrobblingService.ScrobbleReadingUpdate(user.Id, markVolumeReadDto.SeriesId));
|
||||
return Ok();
|
||||
@@ -397,7 +405,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("mark-volume-read")]
|
||||
public async Task<ActionResult> MarkVolumeAsRead(MarkVolumeReadDto markVolumeReadDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Progress);
|
||||
|
||||
var chapters = await _unitOfWork.ChapterRepository.GetChaptersAsync(markVolumeReadDto.VolumeId);
|
||||
if (user == null) return Unauthorized();
|
||||
@@ -407,13 +415,13 @@ public class ReaderController : BaseApiController
|
||||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), ex.Message));
|
||||
return BadRequest(await _localizationService.Translate(UserId, ex.Message));
|
||||
}
|
||||
await _eventHub.SendMessageAsync(MessageFactory.UserProgressUpdate,
|
||||
MessageFactory.UserProgressUpdateEvent(user.Id, user.UserName!, markVolumeReadDto.SeriesId,
|
||||
markVolumeReadDto.VolumeId, 0, chapters.Sum(c => c.Pages)));
|
||||
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-read-progress"));
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(UserId, "generic-read-progress"));
|
||||
|
||||
BackgroundJob.Enqueue(() => _scrobblingService.ScrobbleReadingUpdate(user.Id, markVolumeReadDto.SeriesId));
|
||||
BackgroundJob.Enqueue(() => _unitOfWork.SeriesRepository.ClearOnDeckRemoval(markVolumeReadDto.SeriesId, user.Id));
|
||||
@@ -429,24 +437,25 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("mark-multiple-read")]
|
||||
public async Task<ActionResult> MarkMultipleAsRead(MarkVolumesReadDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
user.Progresses ??= new List<AppUserProgress>();
|
||||
user.Progresses ??= [];
|
||||
|
||||
var chapterIds = await _unitOfWork.VolumeRepository.GetChapterIdsByVolumeIds(dto.VolumeIds);
|
||||
foreach (var chapterId in dto.ChapterIds)
|
||||
{
|
||||
chapterIds.Add(chapterId);
|
||||
}
|
||||
|
||||
var chapters = await _unitOfWork.ChapterRepository.GetChaptersByIdsAsync(chapterIds);
|
||||
await _readerService.MarkChaptersAsRead(user, dto.SeriesId, chapters.ToList());
|
||||
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-read-progress"));
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(UserId, "generic-read-progress"));
|
||||
|
||||
BackgroundJob.Enqueue(() => _scrobblingService.ScrobbleReadingUpdate(user.Id, dto.SeriesId));
|
||||
BackgroundJob.Enqueue(() => _unitOfWork.SeriesRepository.ClearOnDeckRemoval(dto.SeriesId, user.Id));
|
||||
|
||||
return Ok();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -457,7 +466,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("mark-multiple-unread")]
|
||||
public async Task<ActionResult> MarkMultipleAsUnread(MarkVolumesReadDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
user.Progresses ??= new List<AppUserProgress>();
|
||||
|
||||
@@ -475,7 +484,7 @@ public class ReaderController : BaseApiController
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-read-progress"));
|
||||
return BadRequest(await _localizationService.Translate(UserId, "generic-read-progress"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -486,7 +495,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("mark-multiple-series-read")]
|
||||
public async Task<ActionResult> MarkMultipleSeriesAsRead(MarkMultipleSeriesAsReadDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
user.Progresses ??= new List<AppUserProgress>();
|
||||
|
||||
@@ -496,7 +505,7 @@ public class ReaderController : BaseApiController
|
||||
await _readerService.MarkChaptersAsRead(user, volume.SeriesId, volume.Chapters);
|
||||
}
|
||||
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-read-progress"));
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest(await _localizationService.Translate(UserId, "generic-read-progress"));
|
||||
|
||||
foreach (var sId in dto.SeriesIds)
|
||||
{
|
||||
@@ -514,7 +523,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("mark-multiple-series-unread")]
|
||||
public async Task<ActionResult> MarkMultipleSeriesAsUnread(MarkMultipleSeriesAsReadDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
user.Progresses ??= [];
|
||||
|
||||
@@ -533,7 +542,7 @@ public class ReaderController : BaseApiController
|
||||
return Ok();
|
||||
}
|
||||
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-read-progress"));
|
||||
return BadRequest(await _localizationService.Translate(UserId, "generic-read-progress"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -544,7 +553,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("get-progress")]
|
||||
public async Task<ActionResult<ProgressDto>> GetProgress(int chapterId)
|
||||
{
|
||||
var progress = await _unitOfWork.AppUserProgressRepository.GetUserProgressDtoAsync(chapterId, User.GetUserId());
|
||||
var progress = await _unitOfWork.AppUserProgressRepository.GetUserProgressDtoAsync(chapterId, UserId);
|
||||
_logger.LogDebug("Get Progress for {ChapterId} is {Pages}", chapterId, progress?.PageNum ?? 0);
|
||||
|
||||
if (progress == null) return Ok(new ProgressDto()
|
||||
@@ -565,14 +574,14 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("progress")]
|
||||
public async Task<ActionResult> SaveProgress(ProgressDto progressDto)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var userId = UserId;
|
||||
|
||||
if (!await _readerService.SaveReadingProgress(progressDto, userId))
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(userId, "generic-read-progress"));
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -583,7 +592,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("continue-point")]
|
||||
public async Task<ActionResult<ChapterDto>> GetContinuePoint(int seriesId)
|
||||
{
|
||||
return Ok(await _readerService.GetContinuePoint(seriesId, User.GetUserId()));
|
||||
return Ok(await _readerService.GetContinuePoint(seriesId, UserId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -594,7 +603,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("has-progress")]
|
||||
public async Task<ActionResult<bool>> HasProgress(int seriesId)
|
||||
{
|
||||
return Ok(await _unitOfWork.AppUserProgressRepository.HasAnyProgressOnSeriesAsync(seriesId, User.GetUserId()));
|
||||
return Ok(await _unitOfWork.AppUserProgressRepository.HasAnyProgressOnSeriesAsync(seriesId, UserId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -605,7 +614,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("chapter-bookmarks")]
|
||||
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetBookmarks(int chapterId)
|
||||
{
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForChapter(User.GetUserId(), chapterId));
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForChapter(UserId, chapterId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -616,7 +625,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("all-bookmarks")]
|
||||
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetAllBookmarks(FilterV2Dto filterDto)
|
||||
{
|
||||
return Ok(await _unitOfWork.UserRepository.GetAllBookmarkDtos(User.GetUserId(), filterDto));
|
||||
return Ok(await _unitOfWork.UserRepository.GetAllBookmarkDtos(UserId, filterDto));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -627,9 +636,9 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("remove-bookmarks")]
|
||||
public async Task<ActionResult> RemoveBookmarks(RemoveBookmarkForSeriesDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Bookmarks);
|
||||
if (user == null) return Unauthorized();
|
||||
if (user.Bookmarks == null || user.Bookmarks.Count == 0) return Ok(await _localizationService.Translate(User.GetUserId(), "nothing-to-do"));
|
||||
if (user.Bookmarks == null || user.Bookmarks.Count == 0) return Ok(await _localizationService.Translate(UserId, "nothing-to-do"));
|
||||
|
||||
try
|
||||
{
|
||||
@@ -656,7 +665,7 @@ public class ReaderController : BaseApiController
|
||||
await _unitOfWork.RollbackAsync();
|
||||
}
|
||||
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-clear-bookmarks"));
|
||||
return BadRequest(await _localizationService.Translate(UserId, "generic-clear-bookmarks"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -667,9 +676,9 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("bulk-remove-bookmarks")]
|
||||
public async Task<ActionResult> BulkRemoveBookmarks(BulkRemoveBookmarkForSeriesDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Bookmarks);
|
||||
if (user == null) return Unauthorized();
|
||||
if (user.Bookmarks == null || user.Bookmarks.Count == 0) return Ok(await _localizationService.Translate(User.GetUserId(), "nothing-to-do"));
|
||||
if (user.Bookmarks == null || user.Bookmarks.Count == 0) return Ok(await _localizationService.Translate(UserId, "nothing-to-do"));
|
||||
|
||||
try
|
||||
{
|
||||
@@ -693,7 +702,7 @@ public class ReaderController : BaseApiController
|
||||
await _unitOfWork.RollbackAsync();
|
||||
}
|
||||
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-clear-bookmarks"));
|
||||
return BadRequest(await _localizationService.Translate(UserId, "generic-clear-bookmarks"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -704,7 +713,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("volume-bookmarks")]
|
||||
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetBookmarksForVolume(int volumeId)
|
||||
{
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForVolume(User.GetUserId(), volumeId));
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForVolume(UserId, volumeId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -715,7 +724,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("series-bookmarks")]
|
||||
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetBookmarksForSeries(int seriesId)
|
||||
{
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForSeries(User.GetUserId(), seriesId));
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForSeries(UserId, seriesId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -730,16 +739,16 @@ public class ReaderController : BaseApiController
|
||||
try
|
||||
{
|
||||
// Don't let user save past total pages.
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(),
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!,
|
||||
AppUserIncludes.Bookmarks);
|
||||
if (user == null) return new UnauthorizedResult();
|
||||
|
||||
if (!await _accountService.HasBookmarkPermission(user))
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "bookmark-permission"));
|
||||
return BadRequest(await _localizationService.Translate(UserId, "bookmark-permission"));
|
||||
|
||||
var chapter = await _cacheService.Ensure(bookmarkDto.ChapterId);
|
||||
if (chapter == null || chapter.Files.Count == 0)
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "cache-file-find"));
|
||||
return BadRequest(await _localizationService.Translate(UserId, "cache-file-find"));
|
||||
|
||||
bookmarkDto.Page = _readerService.CapPageToChapter(chapter, bookmarkDto.Page);
|
||||
|
||||
@@ -753,7 +762,7 @@ public class ReaderController : BaseApiController
|
||||
|
||||
|
||||
var chapterEntity = await _unitOfWork.ChapterRepository.GetChapterAsync(bookmarkDto.ChapterId);
|
||||
if (chapterEntity == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "chapter-doesnt-exist"));
|
||||
if (chapterEntity == null) return BadRequest(await _localizationService.Translate(UserId, "chapter-doesnt-exist"));
|
||||
var toc = await _bookService.GenerateTableOfContents(chapterEntity);
|
||||
chapterTitle = BookService.GetChapterTitleFromToC(toc, bookmarkDto.Page);
|
||||
}
|
||||
@@ -769,17 +778,18 @@ public class ReaderController : BaseApiController
|
||||
|
||||
if (string.IsNullOrEmpty(path) || !await _bookmarkService.BookmarkPage(user, bookmarkDto, path))
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "bookmark-save"));
|
||||
return BadRequest(await _localizationService.Translate(UserId, "bookmark-save"));
|
||||
}
|
||||
|
||||
|
||||
BackgroundJob.Enqueue(() => _cacheService.CleanupBookmarkCache(bookmarkDto.SeriesId));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
_logger.LogError(ex, "There was an exception when trying to create a bookmark");
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "bookmark-save"));
|
||||
return BadRequest(await _localizationService.Translate(UserId, "bookmark-save"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,16 +802,23 @@ public class ReaderController : BaseApiController
|
||||
[HttpPost("unbookmark")]
|
||||
public async Task<ActionResult> UnBookmarkPage(BookmarkDto bookmarkDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(Username!, AppUserIncludes.Bookmarks);
|
||||
if (user == null) return new UnauthorizedResult();
|
||||
if (user.Bookmarks == null || user.Bookmarks.Count == 0) return Ok();
|
||||
|
||||
if (!await _accountService.HasBookmarkPermission(user))
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "bookmark-permission"));
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(UserId, "bookmark-permission"));
|
||||
}
|
||||
|
||||
if (!await _bookmarkService.RemoveBookmarkPage(user, bookmarkDto))
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "bookmark-save"));
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(UserId, "bookmark-save"));
|
||||
}
|
||||
|
||||
|
||||
BackgroundJob.Enqueue(() => _cacheService.CleanupBookmarkCache(bookmarkDto.SeriesId));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@@ -819,7 +836,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("next-chapter")]
|
||||
public async Task<ActionResult<int>> GetNextChapter(int seriesId, int volumeId, int currentChapterId)
|
||||
{
|
||||
return await _readerService.GetNextChapterIdAsync(seriesId, volumeId, currentChapterId, User.GetUserId());
|
||||
return Ok(await _readerService.GetNextChapterIdAsync(seriesId, volumeId, currentChapterId, UserId));
|
||||
}
|
||||
|
||||
|
||||
@@ -837,7 +854,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("prev-chapter")]
|
||||
public async Task<ActionResult<int>> GetPreviousChapter(int seriesId, int volumeId, int currentChapterId)
|
||||
{
|
||||
return await _readerService.GetPrevChapterIdAsync(seriesId, volumeId, currentChapterId, User.GetUserId());
|
||||
return Ok(await _readerService.GetPrevChapterIdAsync(seriesId, volumeId, currentChapterId, UserId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -850,8 +867,9 @@ public class ReaderController : BaseApiController
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["seriesId"])]
|
||||
public async Task<ActionResult<HourEstimateRangeDto>> GetEstimateToCompletion(int seriesId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var userId = UserId;
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId);
|
||||
if (series == null) return BadRequest(await _localizationService.Translate(UserId, "series-doesnt-exist"));
|
||||
|
||||
// Get all sum of all chapters with progress that is complete then subtract from series. Multiply by modifiers
|
||||
var progress = await _unitOfWork.AppUserProgressRepository.GetUserProgressForSeriesAsync(seriesId, userId);
|
||||
@@ -862,12 +880,13 @@ public class ReaderController : BaseApiController
|
||||
// Word count
|
||||
var progressCount = chapters.Sum(c => c.WordCount);
|
||||
var wordsLeft = series.WordCount - progressCount;
|
||||
return _readerService.GetTimeEstimate(wordsLeft, 0, true);
|
||||
return ReaderService.GetTimeEstimate(wordsLeft, 0, true);
|
||||
}
|
||||
|
||||
var progressPageCount = progress.Sum(p => p.PagesRead);
|
||||
var pagesLeft = series.Pages - progressPageCount;
|
||||
return _readerService.GetTimeEstimate(0, pagesLeft, false);
|
||||
|
||||
return Ok(ReaderService.GetTimeEstimate(0, pagesLeft, false));
|
||||
}
|
||||
|
||||
|
||||
@@ -882,19 +901,19 @@ public class ReaderController : BaseApiController
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = ["seriesId", "chapterId"])]
|
||||
public async Task<ActionResult<HourEstimateRangeDto>> GetEstimateToCompletionForChapter(int seriesId, int chapterId)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var userId = UserId;
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId);
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterDtoAsync(chapterId, userId);
|
||||
if (series == null || chapter == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-error"));
|
||||
if (series == null || chapter == null) return BadRequest(await _localizationService.Translate(UserId, "generic-error"));
|
||||
|
||||
// Patch in the reading progress
|
||||
await _unitOfWork.ChapterRepository.AddChapterModifiers(User.GetUserId(), chapter);
|
||||
await _unitOfWork.ChapterRepository.AddChapterModifiers(UserId, chapter);
|
||||
|
||||
if (series.Format == MangaFormat.Epub)
|
||||
{
|
||||
// Get the word counts for all the pages
|
||||
var pageCounts = await _bookService.GetWordCountsPerPage(chapter.Files.First().FilePath); // TODO: Cache
|
||||
if (pageCounts == null) return _readerService.GetTimeEstimate(series.WordCount, 0, true);
|
||||
if (pageCounts == null) return ReaderService.GetTimeEstimate(series.WordCount, 0, true);
|
||||
|
||||
// Sum character counts only for pages that have been read
|
||||
var totalCharactersRead = pageCounts
|
||||
@@ -903,11 +922,12 @@ public class ReaderController : BaseApiController
|
||||
|
||||
var progressCount = WordCountAnalyzerService.GetWordCount(totalCharactersRead);
|
||||
var wordsLeft = series.WordCount - progressCount;
|
||||
return _readerService.GetTimeEstimate(wordsLeft, 0, true);
|
||||
return ReaderService.GetTimeEstimate(wordsLeft, 0, true);
|
||||
}
|
||||
|
||||
var pagesLeft = chapter.Pages - chapter.PagesRead;
|
||||
return _readerService.GetTimeEstimate(0, pagesLeft, false);
|
||||
|
||||
return Ok(ReaderService.GetTimeEstimate(0, pagesLeft, false));
|
||||
}
|
||||
|
||||
|
||||
@@ -920,7 +940,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("ptoc")]
|
||||
public ActionResult<IEnumerable<PersonalToCDto>> GetPersonalToC(int chapterId)
|
||||
{
|
||||
return Ok(_unitOfWork.UserTableOfContentRepository.GetPersonalToC(User.GetUserId(), chapterId));
|
||||
return Ok(_unitOfWork.UserTableOfContentRepository.GetPersonalToC(UserId, chapterId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -933,7 +953,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpDelete("ptoc")]
|
||||
public async Task<ActionResult> DeletePersonalToc([FromQuery] int chapterId, [FromQuery] int pageNum, [FromQuery] string title)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var userId = UserId;
|
||||
if (string.IsNullOrWhiteSpace(title)) return BadRequest(await _localizationService.Translate(userId, "name-required"));
|
||||
if (pageNum < 0) return BadRequest(await _localizationService.Translate(userId, "valid-number"));
|
||||
|
||||
@@ -956,7 +976,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> CreatePersonalToC(CreatePersonalToCDto dto)
|
||||
{
|
||||
// Validate there isn't already an existing page title combo?
|
||||
var userId = User.GetUserId();
|
||||
var userId = UserId;
|
||||
if (string.IsNullOrWhiteSpace(dto.Title)) return BadRequest(await _localizationService.Translate(userId, "name-required"));
|
||||
if (dto.PageNumber < 0) return BadRequest(await _localizationService.Translate(userId, "valid-number"));
|
||||
if (await _unitOfWork.UserTableOfContentRepository.IsUnique(userId, dto.ChapterId, dto.PageNumber,
|
||||
@@ -984,6 +1004,7 @@ public class ReaderController : BaseApiController
|
||||
AppUserId = userId
|
||||
});
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@@ -997,7 +1018,7 @@ public class ReaderController : BaseApiController
|
||||
[HttpGet("all-chapter-progress")]
|
||||
public async Task<ActionResult<IEnumerable<FullProgressDto>>> GetProgressForChapter(int chapterId)
|
||||
{
|
||||
var userId = User.IsInRole(PolicyConstants.AdminRole) ? 0 : User.GetUserId();
|
||||
var userId = User.IsInRole(PolicyConstants.AdminRole) ? 0 : UserId;
|
||||
return Ok(await _unitOfWork.AppUserProgressRepository.GetUserProgressForChapter(chapterId, userId));
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user