
* Introduced a new claim on the Token to get UserId as well as Username, thus allowing for many places of reduced DB calls. All users will need to reauthenticate. Introduced UTC Dates throughout the application, they are not exposed in all DTOs, that will come later when we fully switch over. For now, Utc dates will be updated along side timezone specific dates. Refactored get-progress/progress api to be 50% faster by reducing how much data is loaded from the query. * Speed up the following apis: collection/search, download/bookmarks, reader/bookmark-info, recommended/quick-reads, recommended/quick-catchup-reads, recommended/highly-rated, recommended/more-in, recommended/rediscover, want-to-read/ * Added a migration to sync all dates with their new UTC counterpart. * Added LastReadingProgressUtc onto ChapterDto for some browsing apis, but not all. Added LastReadingProgressUtc to reading list items. Refactored the migration to run raw SQL which is much faster. * Added LastReadingProgressUtc onto ChapterDto for some browsing apis, but not all. Added LastReadingProgressUtc to reading list items. Refactored the migration to run raw SQL which is much faster. * Fixed the unit tests * Fixed an issue with auto mapper which was causing progress page number to not get sent to UI * series/volume has chapter last reading progress * Added filesize and library name on reading list item dto for CDisplayEx. * Some minor code cleanup * Forgot to fill a field
128 lines
4.4 KiB
C#
128 lines
4.4 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using API.Data;
|
|
using API.DTOs.Device;
|
|
using API.DTOs.Email;
|
|
using API.Entities;
|
|
using API.Entities.Enums;
|
|
using API.Entities.Enums.Device;
|
|
using API.SignalR;
|
|
using Kavita.Common;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace API.Services;
|
|
|
|
public interface IDeviceService
|
|
{
|
|
Task<Device> Create(CreateDeviceDto dto, AppUser userWithDevices);
|
|
Task<Device> Update(UpdateDeviceDto dto, AppUser userWithDevices);
|
|
Task<bool> Delete(AppUser userWithDevices, int deviceId);
|
|
Task<bool> SendTo(IReadOnlyList<int> chapterIds, int deviceId);
|
|
}
|
|
|
|
public class DeviceService : IDeviceService
|
|
{
|
|
private readonly IUnitOfWork _unitOfWork;
|
|
private readonly ILogger<DeviceService> _logger;
|
|
private readonly IEmailService _emailService;
|
|
|
|
public DeviceService(IUnitOfWork unitOfWork, ILogger<DeviceService> logger, IEmailService emailService)
|
|
{
|
|
_unitOfWork = unitOfWork;
|
|
_logger = logger;
|
|
_emailService = emailService;
|
|
}
|
|
#nullable enable
|
|
public async Task<Device?> Create(CreateDeviceDto dto, AppUser userWithDevices)
|
|
{
|
|
try
|
|
{
|
|
userWithDevices.Devices ??= new List<Device>();
|
|
var existingDevice = userWithDevices.Devices.SingleOrDefault(d => d.Name.Equals(dto.Name));
|
|
if (existingDevice != null) throw new KavitaException("A device with this name already exists");
|
|
|
|
existingDevice = DbFactory.Device(dto.Name);
|
|
existingDevice.Platform = dto.Platform;
|
|
existingDevice.EmailAddress = dto.EmailAddress;
|
|
|
|
|
|
userWithDevices.Devices.Add(existingDevice);
|
|
_unitOfWork.UserRepository.Update(userWithDevices);
|
|
|
|
if (!_unitOfWork.HasChanges()) return existingDevice;
|
|
if (await _unitOfWork.CommitAsync()) return existingDevice;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "There was an error when creating your device");
|
|
await _unitOfWork.RollbackAsync();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public async Task<Device?> Update(UpdateDeviceDto dto, AppUser userWithDevices)
|
|
{
|
|
try
|
|
{
|
|
var existingDevice = userWithDevices.Devices.SingleOrDefault(d => d.Id == dto.Id);
|
|
if (existingDevice == null) throw new KavitaException("This device doesn't exist yet. Please create first");
|
|
|
|
existingDevice.Name = dto.Name;
|
|
existingDevice.Platform = dto.Platform;
|
|
existingDevice.EmailAddress = dto.EmailAddress;
|
|
|
|
if (!_unitOfWork.HasChanges()) return existingDevice;
|
|
if (await _unitOfWork.CommitAsync()) return existingDevice;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "There was an error when updating your device");
|
|
await _unitOfWork.RollbackAsync();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
#nullable disable
|
|
|
|
public async Task<bool> Delete(AppUser userWithDevices, int deviceId)
|
|
{
|
|
try
|
|
{
|
|
userWithDevices.Devices = userWithDevices.Devices.Where(d => d.Id != deviceId).ToList();
|
|
_unitOfWork.UserRepository.Update(userWithDevices);
|
|
if (!_unitOfWork.HasChanges()) return true;
|
|
if (await _unitOfWork.CommitAsync()) return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "There was an issue with deleting the device, {DeviceId} for user {UserName}", deviceId, userWithDevices.UserName);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task<bool> SendTo(IReadOnlyList<int> chapterIds, int deviceId)
|
|
{
|
|
var device = await _unitOfWork.DeviceRepository.GetDeviceById(deviceId);
|
|
if (device == null) throw new KavitaException("Device doesn't exist");
|
|
|
|
var files = await _unitOfWork.ChapterRepository.GetFilesForChaptersAsync(chapterIds);
|
|
if (files.Any(f => f.Format is not (MangaFormat.Epub or MangaFormat.Pdf)) && device.Platform == DevicePlatform.Kindle)
|
|
throw new KavitaException("Cannot Send non Epub or Pdf to devices as not supported on Kindle");
|
|
|
|
|
|
device.UpdateLastUsed();
|
|
_unitOfWork.DeviceRepository.Update(device);
|
|
await _unitOfWork.CommitAsync();
|
|
var success = await _emailService.SendFilesToEmail(new SendToDto()
|
|
{
|
|
DestinationEmail = device.EmailAddress,
|
|
FilePaths = files.Select(m => m.FilePath)
|
|
});
|
|
|
|
return success;
|
|
}
|
|
}
|