Update spam circle cache after updating circle status.

This commit is contained in:
2025-09-11 00:26:11 -04:00
parent 3c0a39b324
commit 39274165cb
10 changed files with 70 additions and 37 deletions

View File

@@ -1,11 +1,20 @@
using JSMR.Application.Circles.Ports;
using JSMR.Application.Common.Caching;
namespace JSMR.Application.Circles.Commands.UpdateCircleStatus;
public class UpdateCircleStatusHandler(ICircleWriter writer)
public class UpdateCircleStatusHandler(ICircleWriter writer, ISpamCircleCache spamCircleCache)
{
public Task<UpdateCircleStatusResponse> HandleAsync(UpdateCircleStatusRequest request, CancellationToken cancellationToken = default)
public async Task<UpdateCircleStatusResponse> HandleAsync(UpdateCircleStatusRequest request, CancellationToken cancellationToken = default)
{
return writer.UpdateStatusAsync(request, cancellationToken);
UpdateCircleStatusResponse response = await writer.UpdateStatusAsync(request, cancellationToken);
bool wasChangedToSpam = response.OldStatus is not Contracts.CircleStatus.Spam && response.NewStatus is Contracts.CircleStatus.Spam;
bool wasChangedFromSpam = response.OldStatus is Contracts.CircleStatus.Spam && response.NewStatus is not Contracts.CircleStatus.Spam;
if (wasChangedToSpam || wasChangedFromSpam)
await spamCircleCache.RefreshAsync(cancellationToken);
return response;
}
}

View File

@@ -2,4 +2,4 @@
namespace JSMR.Application.Circles.Commands.UpdateCircleStatus;
public sealed record UpdateCircleStatusResponse(int CircleId, CircleStatus CircleStatus);
public sealed record UpdateCircleStatusResponse(int CircleId, CircleStatus OldStatus, CircleStatus NewStatus);

View File

@@ -0,0 +1,7 @@
namespace JSMR.Application.Common.Caching;
public interface ICacheObject<T>
{
Task<T> GetAsync(CancellationToken cancellationToken = default);
Task<T> RefreshAsync(CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,6 @@
namespace JSMR.Application.Common.Caching;
public interface ISpamCircleCache : ICacheObject<string[]>
{
}

View File

@@ -4,12 +4,6 @@ using Microsoft.EntityFrameworkCore;
namespace JSMR.Infrastructure.Caching;
public interface ICacheObject<T>
{
Task<T> GetAsync(CancellationToken cancellationToken = default);
Task<T> RefreshAsync(CancellationToken cancellationToken = default);
}
public abstract class CacheObject<T>(ICache cache) : ICacheObject<T>
{
protected abstract string Key { get; }
@@ -30,26 +24,4 @@ public abstract class CacheObject<T>(ICache cache) : ICacheObject<T>
return cacheObject;
}
}
public interface ISpamCircleCache : ICacheObject<string[]>
{
}
public class SpamCircleCache(IDbContextFactory<AppDbContext> contextFactory, ICache cache) : CacheObject<string[]>(cache), ISpamCircleCache
{
protected override string Key => "SpamCircles";
protected override async Task<string[]> FetchAsync(CancellationToken cancellationToken = default)
{
using var context = contextFactory.CreateDbContext();
return await context.Circles
.AsNoTracking()
.Where(circle => circle.Spam)
.Select(circle => circle.MakerId)
.Distinct()
.ToArrayAsync(cancellationToken);
}
}

View File

@@ -0,0 +1,23 @@
using JSMR.Application.Common.Caching;
using JSMR.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace JSMR.Infrastructure.Caching;
public class SpamCircleCache(IDbContextFactory<AppDbContext> contextFactory, ICache cache)
: CacheObject<string[]>(cache), ISpamCircleCache
{
protected override string Key => "SpamCircles";
protected override async Task<string[]> FetchAsync(CancellationToken cancellationToken = default)
{
using var context = contextFactory.CreateDbContext();
return await context.Circles
.AsNoTracking()
.Where(circle => circle.Spam)
.Select(circle => circle.MakerId)
.Distinct()
.ToArrayAsync(cancellationToken);
}
}

View File

@@ -11,6 +11,7 @@ public class CircleWriter(AppDbContext context) : ICircleWriter
public async Task<UpdateCircleStatusResponse> UpdateStatusAsync(UpdateCircleStatusRequest request, CancellationToken cancellationToken = default)
{
Circle circle = await GetCircleAsync(request.CircleId, cancellationToken);
CircleStatus oldStatus = GetCircleStatus(circle);
switch (request.CircleStatus)
{
@@ -38,7 +39,23 @@ public class CircleWriter(AppDbContext context) : ICircleWriter
await context.SaveChangesAsync(cancellationToken);
return new UpdateCircleStatusResponse(request.CircleId, request.CircleStatus);
CircleStatus newStatus = GetCircleStatus(circle);
return new UpdateCircleStatusResponse(request.CircleId, oldStatus, newStatus);
}
private static CircleStatus GetCircleStatus(Circle circle)
{
if (circle.Favorite)
return CircleStatus.Favorite;
if (circle.Blacklisted)
return CircleStatus.Blacklisted;
if (circle.Spam)
return CircleStatus.Spam;
return CircleStatus.Neutral;
}
private async Task<Circle> GetCircleAsync(int circleId, CancellationToken cancellationToken)

View File

@@ -1,5 +1,4 @@
using JSMR.Application.Scanning;
using JSMR.Infrastructure.Caching;
using JSMR.Application.Common.Caching;
using JSMR.Infrastructure.Common.Locales;
using JSMR.Infrastructure.Common.SupportedLanguages;
using JSMR.Infrastructure.Http;

View File

@@ -1,4 +1,4 @@
using JSMR.Infrastructure.Caching;
using JSMR.Application.Common.Caching;
using JSMR.Infrastructure.Common.Locales;
using JSMR.Infrastructure.Common.SupportedLanguages;
using JSMR.Infrastructure.Http;

View File

@@ -1,8 +1,8 @@
using HtmlAgilityPack;
using JSMR.Application.Common.Caching;
using JSMR.Application.Scanning;
using JSMR.Application.Scanning.Contracts;
using JSMR.Application.Scanning.Ports;
using JSMR.Infrastructure.Caching;
using JSMR.Infrastructure.Common.Locales;
using JSMR.Infrastructure.Common.SupportedLanguages;
using JSMR.Infrastructure.Http;