using System; using System.Threading.Tasks; using API.Constants; using API.Data; using API.DTOs.KavitaPlus.License; using API.Entities.Enums; using API.Extensions; using API.Services; using API.Services.Plus; using EasyCaching.Core; using Hangfire; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using TaskScheduler = API.Services.TaskScheduler; namespace API.Controllers; #nullable enable public class LicenseController( IUnitOfWork unitOfWork, ILogger logger, ILicenseService licenseService, ILocalizationService localizationService, ITaskScheduler taskScheduler, IEasyCachingProviderFactory cachingProviderFactory) : BaseApiController { /// /// Checks if the user's license is valid or not /// /// [HttpGet("valid-license")] [ResponseCache(CacheProfileName = ResponseCacheProfiles.LicenseCache)] public async Task> HasValidLicense(bool forceCheck = false) { var result = await licenseService.HasActiveLicense(forceCheck); var licenseInfoProvider = cachingProviderFactory.GetCachingProvider(EasyCacheProfiles.License); var cacheValue = await licenseInfoProvider.GetAsync(LicenseService.CacheKey); if (result && !cacheValue.IsNull && !cacheValue.Value) { await taskScheduler.ScheduleKavitaPlusTasks(); } return Ok(result); } /// /// Has any license registered with the instance. Does not check Kavita+ API /// /// [Authorize("RequireAdminRole")] [HttpGet("has-license")] [ResponseCache(CacheProfileName = ResponseCacheProfiles.LicenseCache)] public async Task> HasLicense() { return Ok(!string.IsNullOrEmpty( (await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.LicenseKey)).Value)); } /// /// Asks Kavita+ for the latest license info /// /// Force checking the API and skip the 8 hour cache /// [Authorize("RequireAdminRole")] [HttpGet("info")] [ResponseCache(CacheProfileName = ResponseCacheProfiles.LicenseCache)] public async Task> GetLicenseInfo(bool forceCheck = false) { try { return Ok(await licenseService.GetLicenseInfo(forceCheck)); } catch (Exception) { return Ok(null); } } /// /// Remove the Kavita+ License on the Server /// /// [Authorize("RequireAdminRole")] [HttpDelete] [ResponseCache(CacheProfileName = ResponseCacheProfiles.LicenseCache)] public async Task RemoveLicense() { logger.LogInformation("Removing license on file for Server"); var setting = await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.LicenseKey); setting.Value = null; unitOfWork.SettingsRepository.Update(setting); await unitOfWork.CommitAsync(); TaskScheduler.RemoveKavitaPlusTasks(); return Ok(); } [Authorize("RequireAdminRole")] [HttpPost("reset")] public async Task ResetLicense(UpdateLicenseDto dto) { logger.LogInformation("Resetting license on file for Server"); if (await licenseService.ResetLicense(dto.License, dto.Email)) { await taskScheduler.ScheduleKavitaPlusTasks(); return Ok(); } return BadRequest(localizationService.Translate(User.GetUserId(), "unable-to-reset-k+")); } /// /// Updates server license /// /// Caches the result /// [Authorize("RequireAdminRole")] [HttpPost] public async Task UpdateLicense(UpdateLicenseDto dto) { try { await licenseService.AddLicense(dto.License.Trim(), dto.Email.Trim(), dto.DiscordId); await taskScheduler.ScheduleKavitaPlusTasks(); } catch (Exception ex) { return BadRequest(await localizationService.Translate(User.GetUserId(), ex.Message)); } return Ok(); } }