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:
Joseph Milazzo 2021-11-29 14:19:36 -06:00 committed by GitHub
parent 69bd087697
commit e248cf7579
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 147 additions and 89 deletions

View file

@ -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");
}
}
}

View file

@ -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;
}

View file

@ -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>>()

View file

@ -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

View file

@ -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));
}

View file

@ -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
}
};
}
}
}

View file

@ -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";
}
}