Customized Scheduler + Saved Kavita+ Details (#2644)

This commit is contained in:
Joe Milazzo 2024-01-22 12:10:57 -06:00 committed by GitHub
parent 2092e120c3
commit ad74871623
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 6076 additions and 3370 deletions

View file

@ -13,6 +13,7 @@ using API.Entities.Enums;
using API.Extensions;
using API.Services;
using API.Services.Plus;
using EasyCaching.Core;
using Kavita.Common.Extensions;
using Microsoft.AspNetCore.Mvc;
@ -21,9 +22,12 @@ namespace API.Controllers;
#nullable enable
public class MetadataController(IUnitOfWork unitOfWork, ILocalizationService localizationService, ILicenseService licenseService,
IRatingService ratingService, IReviewService reviewService, IRecommendationService recommendationService, IExternalMetadataService metadataService)
IExternalMetadataService metadataService, IEasyCachingProviderFactory cachingProviderFactory)
: BaseApiController
{
private readonly IEasyCachingProvider _cacheProvider = cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusSeriesDetail);
public const string CacheKey = "kavitaPlusSeriesDetail_";
/// <summary>
/// Fetches genres from the instance
/// </summary>
@ -48,7 +52,7 @@ public class MetadataController(IUnitOfWork unitOfWork, ILocalizationService loc
/// <param name="role">role</param>
/// <returns></returns>
[HttpGet("people-by-role")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Instant, VaryByQueryKeys = new []{"role"})]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Instant, VaryByQueryKeys = ["role"])]
public async Task<ActionResult<IList<PersonDto>>> GetAllPeople(PersonRole? role)
{
return role.HasValue ?
@ -62,7 +66,7 @@ public class MetadataController(IUnitOfWork unitOfWork, ILocalizationService loc
/// <param name="libraryIds">String separated libraryIds or null for all people</param>
/// <returns></returns>
[HttpGet("people")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Instant, VaryByQueryKeys = new []{"libraryIds"})]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Instant, VaryByQueryKeys = ["libraryIds"])]
public async Task<ActionResult<IList<PersonDto>>> GetAllPeople(string? libraryIds)
{
var ids = libraryIds?.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList();
@ -79,7 +83,7 @@ public class MetadataController(IUnitOfWork unitOfWork, ILocalizationService loc
/// <param name="libraryIds">String separated libraryIds or null for all tags</param>
/// <returns></returns>
[HttpGet("tags")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Instant, VaryByQueryKeys = new []{"libraryIds"})]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Instant, VaryByQueryKeys = ["libraryIds"])]
public async Task<ActionResult<IList<TagDto>>> GetAllTags(string? libraryIds)
{
var ids = libraryIds?.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToList();
@ -96,7 +100,7 @@ public class MetadataController(IUnitOfWork unitOfWork, ILocalizationService loc
/// <param name="libraryIds">String separated libraryIds or null for all ratings</param>
/// <remarks>This API is cached for 1 hour, varying by libraryIds</remarks>
/// <returns></returns>
[ResponseCache(CacheProfileName = ResponseCacheProfiles.FiveMinute, VaryByQueryKeys = new [] {"libraryIds"})]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.FiveMinute, VaryByQueryKeys = ["libraryIds"])]
[HttpGet("age-ratings")]
public async Task<ActionResult<IList<AgeRatingDto>>> GetAllAgeRatings(string? libraryIds)
{
@ -184,6 +188,7 @@ public class MetadataController(IUnitOfWork unitOfWork, ILocalizationService loc
/// <summary>
/// Fetches the details needed from Kavita+ for Series Detail page
/// </summary>
/// <remarks>This will hit upstream K+ if the data in local db is 2 weeks old</remarks>
/// <param name="seriesId"></param>
/// <returns></returns>
[HttpGet("series-detail-plus")]
@ -195,7 +200,32 @@ public class MetadataController(IUnitOfWork unitOfWork, ILocalizationService loc
return Ok(null);
}
return Ok(await metadataService.GetSeriesDetail(User.GetUserId(), seriesId));
var user = await unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId());
if (user == null) return Unauthorized();
var userReviews = (await unitOfWork.UserRepository.GetUserRatingDtosForSeriesAsync(seriesId, user.Id))
.Where(r => !string.IsNullOrEmpty(r.Body))
.OrderByDescending(review => review.Username.Equals(user.UserName) ? 1 : 0)
.ToList();
var cacheKey = CacheKey + seriesId + "_" + user.Id;
var results = await _cacheProvider.GetAsync<SeriesDetailPlusDto>(cacheKey);
if (results.HasValue)
{
var cachedResult = results.Value;
userReviews.AddRange(cachedResult.Reviews);
cachedResult.Reviews = ReviewService.SelectSpectrumOfReviews(userReviews);
return cachedResult;
}
var ret = await metadataService.GetSeriesDetail(user.Id, seriesId);
if (ret == null) return Ok(null);
userReviews.AddRange(ret.Reviews);
ret.Reviews = ReviewService.SelectSpectrumOfReviews(userReviews);
await _cacheProvider.SetAsync(cacheKey, ret, TimeSpan.FromHours(24));
return Ok(ret);
}
}

View file

@ -20,38 +20,12 @@ namespace API.Controllers;
/// </summary>
public class RatingController : BaseApiController
{
private readonly ILicenseService _licenseService;
private readonly IRatingService _ratingService;
private readonly ILogger<RatingController> _logger;
private readonly IUnitOfWork _unitOfWork;
private readonly IEasyCachingProvider _cacheProvider;
public const string CacheKey = "rating_";
public RatingController(ILicenseService licenseService, IRatingService ratingService,
ILogger<RatingController> logger, IEasyCachingProviderFactory cachingProviderFactory, IUnitOfWork unitOfWork)
public RatingController(IUnitOfWork unitOfWork)
{
_licenseService = licenseService;
_ratingService = ratingService;
_logger = logger;
_unitOfWork = unitOfWork;
_cacheProvider = cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusRatings);
}
/// <summary>
/// Get the external ratings for a given series
/// </summary>
/// <param name="seriesId"></param>
/// <returns></returns>
[HttpGet]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.KavitaPlus, VaryByQueryKeys = ["seriesId"])]
public async Task<ActionResult<IEnumerable<RatingDto>>> GetRating(int seriesId)
{
if (!await _licenseService.HasActiveLicense())
{
return Ok(Enumerable.Empty<RatingDto>());
}
return Ok(await _ratingService.GetRatings(seriesId));
}
[HttpGet("overall")]

View file

@ -1,19 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using API.Constants;
using System.Threading.Tasks;
using API.Data;
using API.DTOs;
using API.DTOs.Recommendation;
using API.Extensions;
using API.Helpers;
using API.Services;
using API.Services.Plus;
using EasyCaching.Core;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
namespace API.Controllers;
@ -22,56 +12,14 @@ namespace API.Controllers;
public class RecommendedController : BaseApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly IRecommendationService _recommendationService;
private readonly ILicenseService _licenseService;
private readonly ILocalizationService _localizationService;
private readonly IEasyCachingProvider _cacheProvider;
public const string CacheKey = "recommendation_";
public RecommendedController(IUnitOfWork unitOfWork, IRecommendationService recommendationService,
ILicenseService licenseService, IEasyCachingProviderFactory cachingProviderFactory,
ILocalizationService localizationService)
public RecommendedController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_recommendationService = recommendationService;
_licenseService = licenseService;
_localizationService = localizationService;
_cacheProvider = cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusRecommendations);
}
/// <summary>
/// For Kavita+ users, this will return recommendations on the server.
/// </summary>
/// <param name="seriesId"></param>
/// <returns></returns>
[HttpGet("recommendations")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.KavitaPlus, VaryByQueryKeys = new []{"seriesId"})]
public async Task<ActionResult<RecommendationDto>> GetRecommendations(int seriesId)
{
var userId = User.GetUserId();
if (!await _licenseService.HasActiveLicense())
{
return Ok(new RecommendationDto());
}
if (!await _unitOfWork.UserRepository.HasAccessToSeries(userId, seriesId))
{
return BadRequest(await _localizationService.Translate(User.GetUserId(), "series-restricted"));
}
var cacheKey = $"{CacheKey}-{seriesId}-{userId}";
var results = await _cacheProvider.GetAsync<RecommendationDto>(cacheKey);
if (results.HasValue)
{
return Ok(results.Value);
}
var ret = await _recommendationService.GetRecommendationsForSeries(userId, seriesId);
await _cacheProvider.SetAsync(cacheKey, ret, TimeSpan.FromHours(10));
return Ok(ret);
}
/// <summary>
/// Quick Reads are series that should be readable in less than 10 in total and are not Ongoing in release.
/// </summary>
@ -79,7 +27,7 @@ public class RecommendedController : BaseApiController
/// <param name="userParams">Pagination</param>
/// <returns></returns>
[HttpGet("quick-reads")]
public async Task<ActionResult<PagedList<SeriesDto>>> GetQuickReads(int libraryId, [FromQuery] UserParams userParams)
public async Task<ActionResult<PagedList<SeriesDto>>> GetQuickReads(int libraryId, [FromQuery] UserParams? userParams)
{
userParams ??= UserParams.Default;
var series = await _unitOfWork.SeriesRepository.GetQuickReads(User.GetUserId(), libraryId, userParams);
@ -95,7 +43,7 @@ public class RecommendedController : BaseApiController
/// <param name="userParams"></param>
/// <returns></returns>
[HttpGet("quick-catchup-reads")]
public async Task<ActionResult<PagedList<SeriesDto>>> GetQuickCatchupReads(int libraryId, [FromQuery] UserParams userParams)
public async Task<ActionResult<PagedList<SeriesDto>>> GetQuickCatchupReads(int libraryId, [FromQuery] UserParams? userParams)
{
userParams ??= UserParams.Default;
var series = await _unitOfWork.SeriesRepository.GetQuickCatchupReads(User.GetUserId(), libraryId, userParams);
@ -111,7 +59,7 @@ public class RecommendedController : BaseApiController
/// <param name="userParams">Pagination</param>
/// <returns></returns>
[HttpGet("highly-rated")]
public async Task<ActionResult<PagedList<SeriesDto>>> GetHighlyRated(int libraryId, [FromQuery] UserParams userParams)
public async Task<ActionResult<PagedList<SeriesDto>>> GetHighlyRated(int libraryId, [FromQuery] UserParams? userParams)
{
var userId = User.GetUserId();
userParams ??= UserParams.Default;
@ -129,7 +77,7 @@ public class RecommendedController : BaseApiController
/// <param name="userParams">Pagination</param>
/// <returns></returns>
[HttpGet("more-in")]
public async Task<ActionResult<PagedList<SeriesDto>>> GetMoreIn(int libraryId, int genreId, [FromQuery] UserParams userParams)
public async Task<ActionResult<PagedList<SeriesDto>>> GetMoreIn(int libraryId, int genreId, [FromQuery] UserParams? userParams)
{
var userId = User.GetUserId();
@ -148,7 +96,7 @@ public class RecommendedController : BaseApiController
/// <param name="userParams">Pagination</param>
/// <returns></returns>
[HttpGet("rediscover")]
public async Task<ActionResult<PagedList<SeriesDto>>> GetRediscover(int libraryId, [FromQuery] UserParams userParams)
public async Task<ActionResult<PagedList<SeriesDto>>> GetRediscover(int libraryId, [FromQuery] UserParams? userParams)
{
userParams ??= UserParams.Default;
var series = await _unitOfWork.SeriesRepository.GetRediscover(User.GetUserId(), libraryId, userParams);

View file

@ -1,20 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq;
using System.Threading.Tasks;
using API.Constants;
using API.Data;
using API.Data.Repositories;
using API.DTOs.SeriesDetail;
using API.Extensions;
using API.Helpers.Builders;
using API.Services;
using API.Services.Plus;
using AutoMapper;
using EasyCaching.Core;
using Hangfire;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace API.Controllers;
@ -22,41 +16,19 @@ namespace API.Controllers;
public class ReviewController : BaseApiController
{
private readonly ILogger<ReviewController> _logger;
private readonly IUnitOfWork _unitOfWork;
private readonly ILicenseService _licenseService;
private readonly IMapper _mapper;
private readonly IReviewService _reviewService;
private readonly IScrobblingService _scrobblingService;
private readonly IEasyCachingProvider _cacheProvider;
public const string CacheKey = "review_";
public ReviewController(ILogger<ReviewController> logger, IUnitOfWork unitOfWork, ILicenseService licenseService,
IMapper mapper, IReviewService reviewService, IScrobblingService scrobblingService,
IEasyCachingProviderFactory cachingProviderFactory)
public ReviewController(IUnitOfWork unitOfWork,
IMapper mapper, IScrobblingService scrobblingService)
{
_logger = logger;
_unitOfWork = unitOfWork;
_licenseService = licenseService;
_mapper = mapper;
_reviewService = reviewService;
_scrobblingService = scrobblingService;
_cacheProvider = cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusReviews);
}
/// <summary>
/// Fetches reviews from the server for a given series
/// </summary>
/// <param name="seriesId"></param>
[HttpGet]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.KavitaPlus, VaryByQueryKeys = ["seriesId"])]
public async Task<ActionResult<IEnumerable<UserReviewDto>>> GetReviews(int seriesId)
{
return Ok(await _reviewService.GetReviewsForSeries(User.GetUserId(), seriesId));
}
/// <summary>
/// Updates the review for a given series
/// </summary>

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using API.Constants;
using API.Data;
@ -39,16 +38,14 @@ public class SeriesController : BaseApiController
private readonly ILicenseService _licenseService;
private readonly ILocalizationService _localizationService;
private readonly IExternalMetadataService _externalMetadataService;
private readonly IEasyCachingProvider _ratingCacheProvider;
private readonly IEasyCachingProvider _reviewCacheProvider;
private readonly IEasyCachingProvider _recommendationCacheProvider;
private readonly IEasyCachingProvider _externalSeriesCacheProvider;
private const string CacheKey = "recommendation_";
private const string CacheKey = "externalSeriesData_";
public SeriesController(ILogger<SeriesController> logger, ITaskScheduler taskScheduler, IUnitOfWork unitOfWork,
ISeriesService seriesService, ILicenseService licenseService,
IEasyCachingProviderFactory cachingProviderFactory, ILocalizationService localizationService, IExternalMetadataService externalMetadataService)
IEasyCachingProviderFactory cachingProviderFactory, ILocalizationService localizationService,
IExternalMetadataService externalMetadataService)
{
_logger = logger;
_taskScheduler = taskScheduler;
@ -58,9 +55,6 @@ public class SeriesController : BaseApiController
_localizationService = localizationService;
_externalMetadataService = externalMetadataService;
_ratingCacheProvider = cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusRatings);
_reviewCacheProvider = cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusReviews);
_recommendationCacheProvider = cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusRecommendations);
_externalSeriesCacheProvider = cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusExternalSeries);
}
@ -451,19 +445,6 @@ public class SeriesController : BaseApiController
if (!await _seriesService.UpdateSeriesMetadata(updateSeriesMetadataDto))
return BadRequest(await _localizationService.Translate(User.GetUserId(), "update-metadata-fail"));
if (await _licenseService.HasActiveLicense())
{
_logger.LogDebug("Clearing cache as series weblinks may have changed");
await _reviewCacheProvider.RemoveAsync(ReviewController.CacheKey + updateSeriesMetadataDto.SeriesMetadata.SeriesId);
await _ratingCacheProvider.RemoveAsync(RatingController.CacheKey + updateSeriesMetadataDto.SeriesMetadata.SeriesId);
var allUsers = (await _unitOfWork.UserRepository.GetAllUsersAsync()).Select(s => s.Id);
foreach (var userId in allUsers)
{
await _recommendationCacheProvider.RemoveAsync(RecommendedController.CacheKey + $"{updateSeriesMetadataDto.SeriesMetadata.SeriesId}-{userId}");
}
}
return Ok(await _localizationService.Translate(User.GetUserId(), "series-updated"));
}
@ -605,7 +586,7 @@ public class SeriesController : BaseApiController
await _externalSeriesCacheProvider.SetAsync(cacheKey, ret, TimeSpan.FromMinutes(15));
return Ok(ret);
}
catch (Exception ex)
catch (Exception)
{
return BadRequest("Unable to load External Series details");
}

View file

@ -264,13 +264,9 @@ public class ServerController : BaseApiController
public async Task<ActionResult> BustReviewAndRecCache()
{
_logger.LogInformation("Busting Kavita+ Cache");
var provider = _cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusReviews);
var provider = _cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusExternalSeries);
await provider.FlushAsync();
provider = _cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusRecommendations);
await provider.FlushAsync();
provider = _cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusRatings);
await provider.FlushAsync();
provider = _cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusExternalSeries);
provider = _cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.KavitaPlusSeriesDetail);
await provider.FlushAsync();
return Ok();
}

View file

@ -14,7 +14,8 @@ using API.Logging;
using API.Services;
using API.Services.Tasks.Scanner;
using AutoMapper;
using Flurl.Http;
using Cronos;
using Hangfire;
using Kavita.Common;
using Kavita.Common.EnvironmentInfo;
using Kavita.Common.Extensions;
@ -59,6 +60,10 @@ public class SettingsController : BaseApiController
return Ok(settingsDto.BaseUrl);
}
/// <summary>
/// Returns the server settings
/// </summary>
/// <returns></returns>
[Authorize(Policy = "RequireAdminRole")]
[HttpGet]
public async Task<ActionResult<ServerSettingDto>> GetSettings()
@ -161,7 +166,8 @@ public class SettingsController : BaseApiController
if (!updateSettingsDto.BookmarksDirectory.EndsWith("bookmarks") &&
!updateSettingsDto.BookmarksDirectory.EndsWith("bookmarks/"))
{
bookmarkDirectory = _directoryService.FileSystem.Path.Join(updateSettingsDto.BookmarksDirectory, "bookmarks");
bookmarkDirectory =
_directoryService.FileSystem.Path.Join(updateSettingsDto.BookmarksDirectory, "bookmarks");
}
if (string.IsNullOrEmpty(updateSettingsDto.BookmarksDirectory))
@ -171,42 +177,29 @@ public class SettingsController : BaseApiController
foreach (var setting in currentSettings)
{
if (setting.Key == ServerSettingKey.TaskBackup && updateSettingsDto.TaskBackup != setting.Value)
{
setting.Value = updateSettingsDto.TaskBackup;
_unitOfWork.SettingsRepository.Update(setting);
}
UpdateSchedulingSettings(setting, updateSettingsDto);
if (setting.Key == ServerSettingKey.TaskScan && updateSettingsDto.TaskScan != setting.Value)
{
setting.Value = updateSettingsDto.TaskScan;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.OnDeckProgressDays && updateSettingsDto.OnDeckProgressDays + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.OnDeckProgressDays &&
updateSettingsDto.OnDeckProgressDays + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.OnDeckProgressDays + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.OnDeckUpdateDays && updateSettingsDto.OnDeckUpdateDays + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.OnDeckUpdateDays &&
updateSettingsDto.OnDeckUpdateDays + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.OnDeckUpdateDays + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.CoverImageSize && updateSettingsDto.CoverImageSize + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.CoverImageSize &&
updateSettingsDto.CoverImageSize + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.CoverImageSize + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.TaskScan && updateSettingsDto.TaskScan != setting.Value)
{
setting.Value = updateSettingsDto.TaskScan;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.Port && updateSettingsDto.Port + string.Empty != setting.Value)
{
if (OsInfo.IsDocker) continue;
@ -216,7 +209,8 @@ public class SettingsController : BaseApiController
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.CacheSize && updateSettingsDto.CacheSize + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.CacheSize &&
updateSettingsDto.CacheSize + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.CacheSize + string.Empty;
// CacheSize is managed in appSetting.json
@ -232,10 +226,13 @@ public class SettingsController : BaseApiController
{
if (OsInfo.IsDocker) continue;
// Validate IP addresses
foreach (var ipAddress in updateSettingsDto.IpAddresses.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries))
foreach (var ipAddress in updateSettingsDto.IpAddresses.Split(',',
StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries))
{
if (!IPAddress.TryParse(ipAddress.Trim(), out _)) {
return BadRequest(await _localizationService.Translate(User.GetUserId(), "ip-address-invalid", ipAddress));
if (!IPAddress.TryParse(ipAddress.Trim(), out _))
{
return BadRequest(await _localizationService.Translate(User.GetUserId(), "ip-address-invalid",
ipAddress));
}
}
@ -258,20 +255,23 @@ public class SettingsController : BaseApiController
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.LoggingLevel && updateSettingsDto.LoggingLevel + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.LoggingLevel &&
updateSettingsDto.LoggingLevel + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.LoggingLevel + string.Empty;
LogLevelOptions.SwitchLogLevel(updateSettingsDto.LoggingLevel);
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EnableOpds && updateSettingsDto.EnableOpds + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EnableOpds &&
updateSettingsDto.EnableOpds + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.EnableOpds + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EncodeMediaAs && updateSettingsDto.EncodeMediaAs + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EncodeMediaAs &&
updateSettingsDto.EncodeMediaAs + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.EncodeMediaAs + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
@ -289,7 +289,8 @@ public class SettingsController : BaseApiController
// Validate new directory can be used
if (!await _directoryService.CheckWriteAccess(bookmarkDirectory))
{
return BadRequest(await _localizationService.Translate(User.GetUserId(), "bookmark-dir-permissions"));
return BadRequest(
await _localizationService.Translate(User.GetUserId(), "bookmark-dir-permissions"));
}
originalBookmarkDirectory = setting.Value;
@ -300,7 +301,8 @@ public class SettingsController : BaseApiController
}
if (setting.Key == ServerSettingKey.AllowStatCollection && updateSettingsDto.AllowStatCollection + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.AllowStatCollection &&
updateSettingsDto.AllowStatCollection + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.AllowStatCollection + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
@ -314,27 +316,32 @@ public class SettingsController : BaseApiController
}
}
if (setting.Key == ServerSettingKey.TotalBackups && updateSettingsDto.TotalBackups + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.TotalBackups &&
updateSettingsDto.TotalBackups + string.Empty != setting.Value)
{
if (updateSettingsDto.TotalBackups > 30 || updateSettingsDto.TotalBackups < 1)
{
return BadRequest(await _localizationService.Translate(User.GetUserId(), "total-backups"));
}
setting.Value = updateSettingsDto.TotalBackups + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.TotalLogs && updateSettingsDto.TotalLogs + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.TotalLogs &&
updateSettingsDto.TotalLogs + string.Empty != setting.Value)
{
if (updateSettingsDto.TotalLogs > 30 || updateSettingsDto.TotalLogs < 1)
{
return BadRequest(await _localizationService.Translate(User.GetUserId(), "total-logs"));
}
setting.Value = updateSettingsDto.TotalLogs + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EnableFolderWatching && updateSettingsDto.EnableFolderWatching + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EnableFolderWatching &&
updateSettingsDto.EnableFolderWatching + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.EnableFolderWatching + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
@ -376,63 +383,97 @@ public class SettingsController : BaseApiController
return Ok(updateSettingsDto);
}
private void UpdateSchedulingSettings(ServerSetting setting, ServerSettingDto updateSettingsDto)
{
if (setting.Key == ServerSettingKey.TaskBackup && updateSettingsDto.TaskBackup != setting.Value)
{
setting.Value = updateSettingsDto.TaskBackup;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.TaskScan && updateSettingsDto.TaskScan != setting.Value)
{
setting.Value = updateSettingsDto.TaskScan;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.TaskCleanup && updateSettingsDto.TaskCleanup != setting.Value)
{
setting.Value = updateSettingsDto.TaskCleanup;
_unitOfWork.SettingsRepository.Update(setting);
}
}
private void UpdateEmailSettings(ServerSetting setting, ServerSettingDto updateSettingsDto)
{
if (setting.Key == ServerSettingKey.EmailHost && updateSettingsDto.SmtpConfig.Host + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EmailHost &&
updateSettingsDto.SmtpConfig.Host + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.SmtpConfig.Host + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EmailPort && updateSettingsDto.SmtpConfig.Port + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EmailPort &&
updateSettingsDto.SmtpConfig.Port + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.SmtpConfig.Port + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EmailAuthPassword && updateSettingsDto.SmtpConfig.Password + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EmailAuthPassword &&
updateSettingsDto.SmtpConfig.Password + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.SmtpConfig.Password + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EmailAuthUserName && updateSettingsDto.SmtpConfig.UserName + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EmailAuthUserName &&
updateSettingsDto.SmtpConfig.UserName + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.SmtpConfig.UserName + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EmailSenderAddress && updateSettingsDto.SmtpConfig.SenderAddress + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EmailSenderAddress &&
updateSettingsDto.SmtpConfig.SenderAddress + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.SmtpConfig.SenderAddress + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EmailSenderDisplayName && updateSettingsDto.SmtpConfig.SenderDisplayName + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EmailSenderDisplayName &&
updateSettingsDto.SmtpConfig.SenderDisplayName + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.SmtpConfig.SenderDisplayName + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EmailSizeLimit && updateSettingsDto.SmtpConfig.SizeLimit + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EmailSizeLimit &&
updateSettingsDto.SmtpConfig.SizeLimit + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.SmtpConfig.SizeLimit + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EmailEnableSsl && updateSettingsDto.SmtpConfig.EnableSsl + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EmailEnableSsl &&
updateSettingsDto.SmtpConfig.EnableSsl + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.SmtpConfig.EnableSsl + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
if (setting.Key == ServerSettingKey.EmailCustomizedTemplates && updateSettingsDto.SmtpConfig.CustomizedTemplates + string.Empty != setting.Value)
if (setting.Key == ServerSettingKey.EmailCustomizedTemplates &&
updateSettingsDto.SmtpConfig.CustomizedTemplates + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.SmtpConfig.CustomizedTemplates + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}
}
/// <summary>
/// All values allowed for Task Scheduling APIs. A custom cron job is not included. Disabled is not applicable for Cleanup.
/// </summary>
/// <returns></returns>
[Authorize(Policy = "RequireAdminRole")]
[HttpGet("task-frequencies")]
public ActionResult<IEnumerable<string>> GetTaskFrequencies()
@ -451,7 +492,7 @@ public class SettingsController : BaseApiController
[HttpGet("log-levels")]
public ActionResult<IEnumerable<string>> GetLogLevels()
{
return Ok(new [] {"Trace", "Debug", "Information", "Warning", "Critical"});
return Ok(new[] {"Trace", "Debug", "Information", "Warning", "Critical"});
}
[HttpGet("opds-enabled")]
@ -460,4 +501,16 @@ public class SettingsController : BaseApiController
var settingsDto = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
return Ok(settingsDto.EnableOpds);
}
/// <summary>
/// Is the cron expression valid for Kavita's scheduler
/// </summary>
/// <param name="cronExpression"></param>
/// <returns></returns>
[HttpGet("is-valid-cron")]
public ActionResult<bool> IsValidCron(string cronExpression)
{
// NOTE: This must match Hangfire's underlying cron system. Hangfire is unique
return Ok(CronHelper.IsValidCron(cronExpression));
}
}