UI Updates + New Events (#806)
* Implemented ability to see downloads users are performing on the events widget. * Fixed a bug where version update task was calling wrong code * Fixed a bug where when checking for updates, the event wouldn't be pushed to server with correct name. Added update check to the event widget rather than opening a modal on the user. * Relaxed password requirements to only be 6-32 characters and inform user on register form about the requirements * Removed a ton of duplicate logic for series cards where the logic was already defined in action service * Fixed OPDS total items giving a rounded number rather than total items. * Fixed off by one issue on OPDS pagination
This commit is contained in:
parent
69bd087697
commit
e248cf7579
16 changed files with 147 additions and 89 deletions
|
@ -11,9 +11,11 @@ using API.Extensions;
|
|||
using API.Interfaces;
|
||||
using API.Interfaces.Services;
|
||||
using API.Services;
|
||||
using API.SignalR;
|
||||
using Kavita.Common;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace API.Controllers
|
||||
{
|
||||
|
@ -25,16 +27,19 @@ namespace API.Controllers
|
|||
private readonly IDirectoryService _directoryService;
|
||||
private readonly ICacheService _cacheService;
|
||||
private readonly IDownloadService _downloadService;
|
||||
private readonly IHubContext<MessageHub> _messageHub;
|
||||
private readonly NumericComparer _numericComparer;
|
||||
private const string DefaultContentType = "application/octet-stream";
|
||||
|
||||
public DownloadController(IUnitOfWork unitOfWork, IArchiveService archiveService, IDirectoryService directoryService, ICacheService cacheService, IDownloadService downloadService)
|
||||
public DownloadController(IUnitOfWork unitOfWork, IArchiveService archiveService, IDirectoryService directoryService,
|
||||
ICacheService cacheService, IDownloadService downloadService, IHubContext<MessageHub> messageHub)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_archiveService = archiveService;
|
||||
_directoryService = directoryService;
|
||||
_cacheService = cacheService;
|
||||
_downloadService = downloadService;
|
||||
_messageHub = messageHub;
|
||||
_numericComparer = new NumericComparer();
|
||||
}
|
||||
|
||||
|
@ -67,13 +72,7 @@ namespace API.Controllers
|
|||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId);
|
||||
try
|
||||
{
|
||||
if (files.Count == 1)
|
||||
{
|
||||
return await GetFirstFileDownload(files);
|
||||
}
|
||||
var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath),
|
||||
$"download_{User.GetUsername()}_v{volumeId}");
|
||||
return File(fileBytes, DefaultContentType, $"{series.Name} - Volume {volume.Number}.zip");
|
||||
return await DownloadFiles(files, $"download_{User.GetUsername()}_v{volumeId}", $"{series.Name} - Volume {volume.Number}.zip");
|
||||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
|
@ -96,13 +95,7 @@ namespace API.Controllers
|
|||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId);
|
||||
try
|
||||
{
|
||||
if (files.Count == 1)
|
||||
{
|
||||
return await GetFirstFileDownload(files);
|
||||
}
|
||||
var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath),
|
||||
$"download_{User.GetUsername()}_c{chapterId}");
|
||||
return File(fileBytes, DefaultContentType, $"{series.Name} - Chapter {chapter.Number}.zip");
|
||||
return await DownloadFiles(files, $"download_{User.GetUsername()}_c{chapterId}", $"{series.Name} - Chapter {chapter.Number}.zip");
|
||||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
|
@ -110,6 +103,21 @@ namespace API.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
private async Task<ActionResult> DownloadFiles(ICollection<MangaFile> files, string tempFolder, string downloadName)
|
||||
{
|
||||
await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress,
|
||||
MessageFactory.DownloadProgressEvent(User.GetUsername(), Path.GetFileNameWithoutExtension(downloadName), 0F));
|
||||
if (files.Count == 1)
|
||||
{
|
||||
return await GetFirstFileDownload(files);
|
||||
}
|
||||
var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath),
|
||||
tempFolder);
|
||||
await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress,
|
||||
MessageFactory.DownloadProgressEvent(User.GetUsername(), Path.GetFileNameWithoutExtension(downloadName), 1F));
|
||||
return File(fileBytes, DefaultContentType, downloadName);
|
||||
}
|
||||
|
||||
[HttpGet("series")]
|
||||
public async Task<ActionResult> DownloadSeries(int seriesId)
|
||||
{
|
||||
|
@ -117,13 +125,7 @@ namespace API.Controllers
|
|||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);
|
||||
try
|
||||
{
|
||||
if (files.Count == 1)
|
||||
{
|
||||
return await GetFirstFileDownload(files);
|
||||
}
|
||||
var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath),
|
||||
$"download_{User.GetUsername()}_s{seriesId}");
|
||||
return File(fileBytes, DefaultContentType, $"{series.Name}.zip");
|
||||
return await DownloadFiles(files, $"download_{User.GetUsername()}_s{seriesId}", $"{series.Name}.zip");
|
||||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
|
@ -187,5 +189,6 @@ namespace API.Controllers
|
|||
DirectoryService.ClearAndDeleteDirectory(fullExtractPath);
|
||||
return File(fileBytes, DefaultContentType, $"{series.Name} - Bookmarks.zip");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -583,7 +583,7 @@ namespace API.Controllers
|
|||
feed.Links.Add(CreateLink(FeedLinkRelation.Prev, FeedLinkType.AtomNavigation, url + "pageNumber=" + (pageNumber - 1)));
|
||||
}
|
||||
|
||||
if (pageNumber + 1 < list.TotalPages)
|
||||
if (pageNumber + 1 <= list.TotalPages)
|
||||
{
|
||||
feed.Links.Add(CreateLink(FeedLinkRelation.Next, FeedLinkType.AtomNavigation, url + "pageNumber=" + (pageNumber + 1)));
|
||||
}
|
||||
|
@ -596,7 +596,7 @@ namespace API.Controllers
|
|||
}
|
||||
|
||||
|
||||
feed.Total = list.TotalPages * list.PageSize;
|
||||
feed.Total = list.TotalCount;
|
||||
feed.ItemsPerPage = list.PageSize;
|
||||
feed.StartIndex = (Math.Max(list.CurrentPage - 1, 0) * list.PageSize) + 1;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,13 @@ namespace API.Extensions
|
|||
{
|
||||
services.AddIdentityCore<AppUser>(opt =>
|
||||
{
|
||||
// Change password / signin requirements here
|
||||
opt.Password.RequireNonAlphanumeric = false;
|
||||
opt.Password.RequireDigit = false;
|
||||
opt.Password.RequireDigit = false;
|
||||
opt.Password.RequireLowercase = false;
|
||||
opt.Password.RequireUppercase = false;
|
||||
opt.Password.RequireNonAlphanumeric = false;
|
||||
opt.Password.RequiredLength = 6;
|
||||
})
|
||||
.AddRoles<AppRole>()
|
||||
.AddRoleManager<RoleManager<AppRole>>()
|
||||
|
|
|
@ -120,7 +120,7 @@ namespace API.Services
|
|||
{
|
||||
_logger.LogInformation("Scheduling Auto-Update tasks");
|
||||
// Schedule update check between noon and 6pm local time
|
||||
RecurringJob.AddOrUpdate("check-updates", () => _versionUpdaterService.CheckForUpdate(), Cron.Daily(Rnd.Next(12, 18)), TimeZoneInfo.Local);
|
||||
RecurringJob.AddOrUpdate("check-updates", () => CheckForUpdate(), Cron.Daily(Rnd.Next(12, 18)), TimeZoneInfo.Local);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
|
|
@ -86,10 +86,6 @@ namespace API.Services.Tasks
|
|||
return CreateDto(update);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<UpdateNotificationDto>> GetAllReleases()
|
||||
{
|
||||
var updates = await GetGithubReleases();
|
||||
|
@ -140,13 +136,7 @@ namespace API.Services.Tasks
|
|||
|
||||
private async Task SendEvent(UpdateNotificationDto update, IReadOnlyList<string> admins)
|
||||
{
|
||||
var connections = new List<string>();
|
||||
foreach (var admin in admins)
|
||||
{
|
||||
connections.AddRange(await _tracker.GetConnectionsForUser(admin));
|
||||
}
|
||||
|
||||
await _messageHub.Clients.Users(admins).SendAsync(SignalREvents.UpdateVersion, MessageFactory.UpdateVersionEvent(update));
|
||||
await _messageHub.Clients.Users(admins).SendAsync(SignalREvents.UpdateAvailable, MessageFactory.UpdateVersionEvent(update));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ namespace API.SignalR
|
|||
{
|
||||
return new SignalRMessage
|
||||
{
|
||||
Name = SignalREvents.UpdateVersion,
|
||||
Name = SignalREvents.UpdateAvailable,
|
||||
Body = update
|
||||
};
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ namespace API.SignalR
|
|||
{
|
||||
return new SignalRMessage
|
||||
{
|
||||
Name = SignalREvents.UpdateVersion,
|
||||
Name = SignalREvents.UpdateAvailable,
|
||||
Body = new
|
||||
{
|
||||
TagId = tagId,
|
||||
|
@ -147,5 +147,19 @@ namespace API.SignalR
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static SignalRMessage DownloadProgressEvent(string username, string downloadName, float progress)
|
||||
{
|
||||
return new SignalRMessage()
|
||||
{
|
||||
Name = SignalREvents.DownloadProgress,
|
||||
Body = new
|
||||
{
|
||||
UserName = username,
|
||||
DownloadName = downloadName,
|
||||
Progress = progress
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{
|
||||
public static class SignalREvents
|
||||
{
|
||||
public const string UpdateVersion = "UpdateVersion";
|
||||
public const string UpdateAvailable = "UpdateAvailable";
|
||||
public const string ScanSeries = "ScanSeries";
|
||||
/// <summary>
|
||||
/// Event during Refresh Metadata for cover image change
|
||||
|
@ -27,5 +27,10 @@
|
|||
/// Event sent out during cleaning up temp and cache folders
|
||||
/// </summary>
|
||||
public const string CleanupProgress = "CleanupProgress";
|
||||
/// <summary>
|
||||
/// Event sent out during downloading of files
|
||||
/// </summary>
|
||||
public const string DownloadProgress = "DownloadProgress";
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue