MAL Interest Stacks (#2932)

This commit is contained in:
Joe Milazzo 2024-05-04 15:23:58 -05:00 committed by GitHub
parent 29eb65c783
commit b23300b1a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
61 changed files with 4104 additions and 382 deletions

View file

@ -898,8 +898,6 @@ public class AccountController : BaseApiController
{
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
if (!settings.IsEmailSetup()) return Ok(await _localizationService.Get("en", "email-not-enabled"));
var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(email);
if (user == null)
{
@ -914,11 +912,7 @@ public class AccountController : BaseApiController
if (string.IsNullOrEmpty(user.Email) || !user.EmailConfirmed)
return BadRequest(await _localizationService.Translate(user.Id, "confirm-email"));
if (!_emailService.IsValidEmail(user.Email))
{
_logger.LogCritical("[Forgot Password]: User is trying to do a forgot password flow, but their email ({Email}) isn't valid. No email will be send. Admin must change it in UI", user.Email);
return Ok(await _localizationService.Translate(user.Id, "invalid-email"));
}
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
var emailLink = await _emailService.GenerateEmailLink(Request, token, "confirm-reset-password", user.Email);
@ -927,6 +921,13 @@ public class AccountController : BaseApiController
await _unitOfWork.CommitAsync();
_logger.LogCritical("[Forgot Password]: Email Link for {UserName}: {Link}", user.UserName, emailLink);
if (!settings.IsEmailSetup()) return Ok(await _localizationService.Get("en", "email-not-enabled"));
if (!_emailService.IsValidEmail(user.Email))
{
_logger.LogCritical("[Forgot Password]: User is trying to do a forgot password flow, but their email ({Email}) isn't valid. No email will be send. Admin must change it in UI or from url above", user.Email);
return Ok(await _localizationService.Translate(user.Id, "invalid-email"));
}
var installId = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId)).Value;
BackgroundJob.Enqueue(() => _emailService.SendForgotPasswordEmail(new PasswordResetEmailDto()
{

View file

@ -12,8 +12,11 @@ using API.Extensions;
using API.Helpers.Builders;
using API.Services;
using API.Services.Plus;
using API.SignalR;
using Hangfire;
using Kavita.Common;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace API.Controllers;
@ -28,15 +31,23 @@ public class CollectionController : BaseApiController
private readonly ICollectionTagService _collectionService;
private readonly ILocalizationService _localizationService;
private readonly IExternalMetadataService _externalMetadataService;
private readonly ISmartCollectionSyncService _collectionSyncService;
private readonly ILogger<CollectionController> _logger;
private readonly IEventHub _eventHub;
/// <inheritdoc />
public CollectionController(IUnitOfWork unitOfWork, ICollectionTagService collectionService,
ILocalizationService localizationService, IExternalMetadataService externalMetadataService)
ILocalizationService localizationService, IExternalMetadataService externalMetadataService,
ISmartCollectionSyncService collectionSyncService, ILogger<CollectionController> logger,
IEventHub eventHub)
{
_unitOfWork = unitOfWork;
_collectionService = collectionService;
_localizationService = localizationService;
_externalMetadataService = externalMetadataService;
_collectionSyncService = collectionSyncService;
_logger = logger;
_eventHub = eventHub;
}
/// <summary>
@ -49,6 +60,18 @@ public class CollectionController : BaseApiController
return Ok(await _unitOfWork.CollectionTagRepository.GetCollectionDtosAsync(User.GetUserId(), !ownedOnly));
}
/// <summary>
/// Returns a single Collection tag by Id for a given user
/// </summary>
/// <param name="collectionId"></param>
/// <returns></returns>
[HttpGet("single")]
public async Task<ActionResult<IEnumerable<AppUserCollectionDto>>> GetTag(int collectionId)
{
var collections = await _unitOfWork.CollectionTagRepository.GetCollectionDtosAsync(User.GetUserId(), false);
return Ok(collections.FirstOrDefault(c => c.Id == collectionId));
}
/// <summary>
/// Returns all collections that contain the Series for the user with the option to allow for promoted collections (non-user owned)
/// </summary>
@ -86,6 +109,8 @@ public class CollectionController : BaseApiController
{
if (await _collectionService.UpdateTag(updatedTag, User.GetUserId()))
{
await _eventHub.SendMessageAsync(MessageFactory.CollectionUpdated,
MessageFactory.CollectionUpdatedEvent(updatedTag.Id), false);
return Ok(await _localizationService.Translate(User.GetUserId(), "collection-updated-successfully"));
}
}
@ -129,12 +154,12 @@ public class CollectionController : BaseApiController
/// <summary>
/// Promote/UnPromote multiple collections in one go
/// Delete multiple collections in one go
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost("delete-multiple")]
public async Task<ActionResult> DeleteMultipleCollections(PromoteCollectionsDto dto)
public async Task<ActionResult> DeleteMultipleCollections(DeleteCollectionsDto dto)
{
// This needs to take into account owner as I can select other users cards
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Collections);
@ -178,7 +203,7 @@ public class CollectionController : BaseApiController
return BadRequest(_localizationService.Translate(User.GetUserId(), "collection-doesnt-exists"));
}
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdsAsync(dto.SeriesIds.ToList());
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdsAsync(dto.SeriesIds.ToList(), false);
foreach (var s in series)
{
if (tag.Items.Contains(s)) continue;
@ -253,4 +278,45 @@ public class CollectionController : BaseApiController
{
return Ok(await _externalMetadataService.GetStacksForUser(User.GetUserId()));
}
/// <summary>
/// Imports a MAL Stack into Kavita
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost("import-stack")]
public async Task<ActionResult> ImportMalStack(MalStackDto dto)
{
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.Collections);
if (user == null) return Unauthorized();
// Validation check to ensure stack doesn't exist already
if (await _unitOfWork.CollectionTagRepository.CollectionExists(dto.Title, user.Id))
{
return BadRequest(_localizationService.Translate(user.Id, "collection-already-exists"));
}
try
{
// Create new collection
var newCollection = new AppUserCollectionBuilder(dto.Title)
.WithSource(ScrobbleProvider.Mal)
.WithSourceUrl(dto.Url)
.Build();
user.Collections.Add(newCollection);
_unitOfWork.UserRepository.Update(user);
await _unitOfWork.CommitAsync();
// Trigger Stack Refresh for just one stack (not all)
BackgroundJob.Enqueue(() => _collectionSyncService.Sync(newCollection.Id));
return Ok();
}
catch (Exception ex)
{
_logger.LogError(ex, "There was an issue importing MAL Stack");
}
return BadRequest(_localizationService.Translate(user.Id, "error-import-stack"));
}
}