feat: Fixed errors
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using LctMonolith.Infrastructure.UnitOfWork;
|
||||
using LctMonolith.Database.UnitOfWork;
|
||||
using LctMonolith.Models;
|
||||
using LctMonolith.Services.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@@ -16,7 +17,7 @@ public class AnalyticsService : IAnalyticsService
|
||||
{
|
||||
var totalUsers = await _uow.Users.Query().CountAsync(ct);
|
||||
var totalMissions = await _uow.Missions.Query().CountAsync(ct);
|
||||
var completedMissions = await _uow.UserMissions.Query(um => um.Status == Domain.Entities.MissionStatus.Completed).CountAsync(ct);
|
||||
var completedMissions = await _uow.UserMissions.Query(um => um.Status == MissionStatus.Completed).CountAsync(ct);
|
||||
var totalArtifacts = await _uow.Artifacts.Query().CountAsync(ct);
|
||||
var totalStoreItems = await _uow.StoreItems.Query().CountAsync(ct);
|
||||
var totalExperience = await _uow.Users.Query().SumAsync(u => (long)u.Experience, ct);
|
||||
@@ -31,4 +32,3 @@ public class AnalyticsService : IAnalyticsService
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
LctMonolith/Services/Contracts/IAnalyticsService.cs
Normal file
10
LctMonolith/Services/Contracts/IAnalyticsService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using LctMonolith.Services.Models;
|
||||
|
||||
using LctMonolith.Services.Models;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
|
||||
public interface IAnalyticsService
|
||||
{
|
||||
Task<AnalyticsSummary> GetSummaryAsync(CancellationToken ct = default);
|
||||
}
|
||||
15
LctMonolith/Services/Contracts/IGamificationService.cs
Normal file
15
LctMonolith/Services/Contracts/IGamificationService.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using LctMonolith.Models;
|
||||
using LctMonolith.Services.Models;
|
||||
|
||||
namespace LctMonolith.Services.Contracts;
|
||||
|
||||
/// <summary>Gamification progression logic (progress, rewards, rank evaluation).</summary>
|
||||
public interface IGamificationService
|
||||
{
|
||||
/// <summary>Get current user progression snapshot (xp, mana, next rank requirements).</summary>
|
||||
Task<ProgressSnapshot> GetProgressAsync(Guid userId, CancellationToken ct = default);
|
||||
/// <summary>Apply mission completion rewards (xp, mana, skills, artifacts) to user.</summary>
|
||||
Task ApplyMissionCompletionAsync(Guid userId, Mission mission, CancellationToken ct = default);
|
||||
/// <summary>Re-evaluate and apply rank upgrade if requirements are met.</summary>
|
||||
Task EvaluateRankUpgradeAsync(Guid userId, CancellationToken ct = default);
|
||||
}
|
||||
9
LctMonolith/Services/Contracts/IInventoryService.cs
Normal file
9
LctMonolith/Services/Contracts/IInventoryService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using LctMonolith.Models;
|
||||
|
||||
namespace LctMonolith.Services.Contracts;
|
||||
|
||||
public interface IInventoryService
|
||||
{
|
||||
Task<IEnumerable<UserInventoryItem>> GetStoreInventoryAsync(Guid userId, CancellationToken ct = default);
|
||||
Task<IEnumerable<UserArtifact>> GetArtifactsAsync(Guid userId, CancellationToken ct = default);
|
||||
}
|
||||
11
LctMonolith/Services/Contracts/IMissionService.cs
Normal file
11
LctMonolith/Services/Contracts/IMissionService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using LctMonolith.Models;
|
||||
using LctMonolith.Services.Models;
|
||||
|
||||
namespace LctMonolith.Services.Contracts;
|
||||
|
||||
public interface IMissionService
|
||||
{
|
||||
Task<Mission> CreateMissionAsync(CreateMissionModel model, CancellationToken ct = default);
|
||||
Task<IEnumerable<Mission>> GetAvailableMissionsAsync(Guid userId, CancellationToken ct = default);
|
||||
Task<UserMission> UpdateStatusAsync(Guid userId, Guid missionId, MissionStatus status, string? submissionData, CancellationToken ct = default);
|
||||
}
|
||||
12
LctMonolith/Services/Contracts/INotificationService.cs
Normal file
12
LctMonolith/Services/Contracts/INotificationService.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using LctMonolith.Models;
|
||||
|
||||
namespace LctMonolith.Services.Contracts;
|
||||
|
||||
public interface INotificationService
|
||||
{
|
||||
Task<Notification> CreateAsync(Guid userId, string type, string title, string message, CancellationToken ct = default);
|
||||
Task<IEnumerable<Notification>> GetUnreadAsync(Guid userId, CancellationToken ct = default);
|
||||
Task<IEnumerable<Notification>> GetAllAsync(Guid userId, int take = 100, CancellationToken ct = default);
|
||||
Task MarkReadAsync(Guid userId, Guid notificationId, CancellationToken ct = default);
|
||||
Task<int> MarkAllReadAsync(Guid userId, CancellationToken ct = default);
|
||||
}
|
||||
9
LctMonolith/Services/Contracts/IStoreService.cs
Normal file
9
LctMonolith/Services/Contracts/IStoreService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using LctMonolith.Models;
|
||||
|
||||
namespace LctMonolith.Services.Contracts;
|
||||
|
||||
public interface IStoreService
|
||||
{
|
||||
Task<IEnumerable<StoreItem>> GetActiveItemsAsync(CancellationToken ct = default);
|
||||
Task<UserInventoryItem> PurchaseAsync(Guid userId, Guid itemId, int quantity, CancellationToken ct = default);
|
||||
}
|
||||
11
LctMonolith/Services/Contracts/ITokenService.cs
Normal file
11
LctMonolith/Services/Contracts/ITokenService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using LctMonolith.Models;
|
||||
using LctMonolith.Services.Models;
|
||||
|
||||
namespace LctMonolith.Services.Contracts;
|
||||
|
||||
public interface ITokenService
|
||||
{
|
||||
Task<TokenPair> IssueAsync(AppUser user, CancellationToken ct = default);
|
||||
Task<TokenPair> RefreshAsync(string refreshToken, CancellationToken ct = default);
|
||||
Task RevokeAsync(string refreshToken, CancellationToken ct = default);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq;
|
||||
using LctMonolith.Domain.Entities;
|
||||
using LctMonolith.Infrastructure.UnitOfWork;
|
||||
using LctMonolith.Database.UnitOfWork;
|
||||
using LctMonolith.Models;
|
||||
using LctMonolith.Services.Contracts;
|
||||
using LctMonolith.Services.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Serilog;
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
// Removed legacy Weather service placeholder.
|
||||
// Intentionally left blank.
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
using LctMonolith.Domain.Entities;
|
||||
using LctMonolith.Services.Models;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
|
||||
/// <summary>Service for issuing JWT and refresh tokens.</summary>
|
||||
public interface ITokenService
|
||||
{
|
||||
Task<TokenPair> IssueAsync(AppUser user, CancellationToken ct = default);
|
||||
Task<TokenPair> RefreshAsync(string refreshToken, CancellationToken ct = default);
|
||||
Task RevokeAsync(string refreshToken, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>Gamification progression logic (awards, rank upgrade).</summary>
|
||||
public interface IGamificationService
|
||||
{
|
||||
Task<ProgressSnapshot> GetProgressAsync(Guid userId, CancellationToken ct = default);
|
||||
Task ApplyMissionCompletionAsync(Guid userId, Mission mission, CancellationToken ct = default);
|
||||
Task EvaluateRankUpgradeAsync(Guid userId, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>Mission management and user mission state transitions.</summary>
|
||||
public interface IMissionService
|
||||
{
|
||||
Task<Mission> CreateMissionAsync(CreateMissionModel model, CancellationToken ct = default);
|
||||
Task<IEnumerable<Mission>> GetAvailableMissionsAsync(Guid userId, CancellationToken ct = default);
|
||||
Task<UserMission> UpdateStatusAsync(Guid userId, Guid missionId, MissionStatus status, string? submissionData, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>Store and inventory operations.</summary>
|
||||
public interface IStoreService
|
||||
{
|
||||
Task<IEnumerable<StoreItem>> GetActiveItemsAsync(CancellationToken ct = default);
|
||||
Task<UserInventoryItem> PurchaseAsync(Guid userId, Guid itemId, int quantity, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>User notifications (in-app) management.</summary>
|
||||
public interface INotificationService
|
||||
{
|
||||
Task<Notification> CreateAsync(Guid userId, string type, string title, string message, CancellationToken ct = default);
|
||||
Task<IEnumerable<Notification>> GetUnreadAsync(Guid userId, CancellationToken ct = default);
|
||||
Task<IEnumerable<Notification>> GetAllAsync(Guid userId, int take = 100, CancellationToken ct = default);
|
||||
Task MarkReadAsync(Guid userId, Guid notificationId, CancellationToken ct = default);
|
||||
Task<int> MarkAllReadAsync(Guid userId, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>Inventory querying (owned artifacts, store items).</summary>
|
||||
public interface IInventoryService
|
||||
{
|
||||
Task<IEnumerable<UserInventoryItem>> GetStoreInventoryAsync(Guid userId, CancellationToken ct = default);
|
||||
Task<IEnumerable<UserArtifact>> GetArtifactsAsync(Guid userId, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>Basic analytics / aggregated metrics.</summary>
|
||||
public interface IAnalyticsService
|
||||
{
|
||||
Task<AnalyticsSummary> GetSummaryAsync(CancellationToken ct = default);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using LctMonolith.Domain.Entities;
|
||||
using LctMonolith.Infrastructure.UnitOfWork;
|
||||
using LctMonolith.Database.UnitOfWork;
|
||||
using LctMonolith.Models;
|
||||
using LctMonolith.Services.Contracts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
@@ -32,4 +33,3 @@ public class InventoryService : IInventoryService
|
||||
.ToListAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using LctMonolith.Domain.Entities;
|
||||
using LctMonolith.Infrastructure.UnitOfWork;
|
||||
using LctMonolith.Models;
|
||||
using LctMonolith.Services.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Serilog;
|
||||
using System.Text.Json;
|
||||
using System.Linq;
|
||||
using LctMonolith.Database.UnitOfWork;
|
||||
using LctMonolith.Services.Contracts;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
|
||||
|
||||
12
LctMonolith/Services/Models/AnalyticsSummary.cs
Normal file
12
LctMonolith/Services/Models/AnalyticsSummary.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public class AnalyticsSummary
|
||||
{
|
||||
public int TotalUsers { get; set; }
|
||||
public int TotalMissions { get; set; }
|
||||
public int CompletedMissions { get; set; }
|
||||
public int TotalArtifacts { get; set; }
|
||||
public int TotalStoreItems { get; set; }
|
||||
public long TotalExperience { get; set; }
|
||||
public DateTime GeneratedAtUtc { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
9
LctMonolith/Services/Models/AuthRequest.cs
Normal file
9
LctMonolith/Services/Models/AuthRequest.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public class AuthRequest
|
||||
{
|
||||
public string Email { get; set; } = null!;
|
||||
public string Password { get; set; } = null!;
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
}
|
||||
8
LctMonolith/Services/Models/CompetencyRewardModel.cs
Normal file
8
LctMonolith/Services/Models/CompetencyRewardModel.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public class CompetencyRewardModel
|
||||
{
|
||||
public Guid CompetencyId { get; set; }
|
||||
public int LevelDelta { get; set; }
|
||||
public int ProgressPointsDelta { get; set; }
|
||||
}
|
||||
16
LctMonolith/Services/Models/CreateMissionModel.cs
Normal file
16
LctMonolith/Services/Models/CreateMissionModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using LctMonolith.Models;
|
||||
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public class CreateMissionModel
|
||||
{
|
||||
public string Title { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public string? Branch { get; set; }
|
||||
public MissionCategory Category { get; set; }
|
||||
public Guid? MinRankId { get; set; }
|
||||
public int ExperienceReward { get; set; }
|
||||
public int ManaReward { get; set; }
|
||||
public List<CompetencyRewardModel> CompetencyRewards { get; set; } = new();
|
||||
public List<Guid> ArtifactRewardIds { get; set; } = new();
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
using LctMonolith.Domain.Entities;
|
||||
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
/// <summary>Returned access+refresh token pair with expiry metadata.</summary>
|
||||
public record TokenPair(string AccessToken, DateTime AccessTokenExpiresAt, string RefreshToken, DateTime RefreshTokenExpiresAt);
|
||||
|
||||
/// <summary>Mission creation request model.</summary>
|
||||
public class CreateMissionModel
|
||||
{
|
||||
public string Title { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public string? Branch { get; set; }
|
||||
public MissionCategory Category { get; set; }
|
||||
public Guid? MinRankId { get; set; }
|
||||
public int ExperienceReward { get; set; }
|
||||
public int ManaReward { get; set; }
|
||||
public List<CompetencyRewardModel> CompetencyRewards { get; set; } = new();
|
||||
public List<Guid> ArtifactRewardIds { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>Competency reward definition for mission creation.</summary>
|
||||
public class CompetencyRewardModel
|
||||
{
|
||||
public Guid CompetencyId { get; set; }
|
||||
public int LevelDelta { get; set; }
|
||||
public int ProgressPointsDelta { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Progress snapshot for UI: rank, xp, remaining requirements.</summary>
|
||||
public class ProgressSnapshot
|
||||
{
|
||||
public int Experience { get; set; }
|
||||
public int Mana { get; set; }
|
||||
public Guid? CurrentRankId { get; set; }
|
||||
public string? CurrentRankName { get; set; }
|
||||
public Guid? NextRankId { get; set; }
|
||||
public string? NextRankName { get; set; }
|
||||
public int? RequiredExperienceForNextRank { get; set; }
|
||||
public int? ExperienceRemaining => RequiredExperienceForNextRank.HasValue ? Math.Max(0, RequiredExperienceForNextRank.Value - Experience) : null;
|
||||
public List<Guid> OutstandingMissionIds { get; set; } = new();
|
||||
public List<OutstandingCompetency> OutstandingCompetencies { get; set; } = new();
|
||||
}
|
||||
|
||||
/// <summary>Competency requirement still unmet for next rank.</summary>
|
||||
public class OutstandingCompetency
|
||||
{
|
||||
public Guid CompetencyId { get; set; }
|
||||
public string? CompetencyName { get; set; }
|
||||
public int RequiredLevel { get; set; }
|
||||
public int CurrentLevel { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Request to update mission status with optional submission data.</summary>
|
||||
public class UpdateMissionStatusRequest
|
||||
{
|
||||
public MissionStatus Status { get; set; }
|
||||
public string? SubmissionData { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Store purchase request.</summary>
|
||||
public class PurchaseRequest
|
||||
{
|
||||
public Guid ItemId { get; set; }
|
||||
public int Quantity { get; set; } = 1;
|
||||
}
|
||||
|
||||
/// <summary>Authentication request (login/register) simple mock.</summary>
|
||||
public class AuthRequest
|
||||
{
|
||||
public string Email { get; set; } = null!;
|
||||
public string Password { get; set; } = null!;
|
||||
public string? FirstName { get; set; }
|
||||
public string? LastName { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Refresh token request.</summary>
|
||||
public class RefreshRequest
|
||||
{
|
||||
public string RefreshToken { get; set; } = null!;
|
||||
}
|
||||
|
||||
/// <summary>Revoke refresh token request.</summary>
|
||||
public class RevokeRequest
|
||||
{
|
||||
public string RefreshToken { get; set; } = null!;
|
||||
}
|
||||
|
||||
/// <summary>Analytics summary for admin dashboard.</summary>
|
||||
public class AnalyticsSummary
|
||||
{
|
||||
public int TotalUsers { get; set; }
|
||||
public int TotalMissions { get; set; }
|
||||
public int CompletedMissions { get; set; }
|
||||
public int TotalArtifacts { get; set; }
|
||||
public int TotalStoreItems { get; set; }
|
||||
public long TotalExperience { get; set; }
|
||||
public DateTime GeneratedAtUtc { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
23
LctMonolith/Services/Models/ProgressSnapshot.cs
Normal file
23
LctMonolith/Services/Models/ProgressSnapshot.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public class ProgressSnapshot
|
||||
{
|
||||
public int Experience { get; set; }
|
||||
public int Mana { get; set; }
|
||||
public Guid? CurrentRankId { get; set; }
|
||||
public string? CurrentRankName { get; set; }
|
||||
public Guid? NextRankId { get; set; }
|
||||
public string? NextRankName { get; set; }
|
||||
public int? RequiredExperienceForNextRank { get; set; }
|
||||
public int? ExperienceRemaining => RequiredExperienceForNextRank.HasValue ? Math.Max(0, RequiredExperienceForNextRank.Value - Experience) : null;
|
||||
public List<Guid> OutstandingMissionIds { get; set; } = new();
|
||||
public List<OutstandingCompetency> OutstandingCompetencies { get; set; } = new();
|
||||
}
|
||||
|
||||
public class OutstandingCompetency
|
||||
{
|
||||
public Guid CompetencyId { get; set; }
|
||||
public string? CompetencyName { get; set; }
|
||||
public int RequiredLevel { get; set; }
|
||||
public int CurrentLevel { get; set; }
|
||||
}
|
||||
7
LctMonolith/Services/Models/PurchaseRequest.cs
Normal file
7
LctMonolith/Services/Models/PurchaseRequest.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public class PurchaseRequest
|
||||
{
|
||||
public Guid ItemId { get; set; }
|
||||
public int Quantity { get; set; } = 1;
|
||||
}
|
||||
6
LctMonolith/Services/Models/RefreshRequest.cs
Normal file
6
LctMonolith/Services/Models/RefreshRequest.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public class RefreshRequest
|
||||
{
|
||||
public string RefreshToken { get; set; } = null!;
|
||||
}
|
||||
6
LctMonolith/Services/Models/RevokeRequest.cs
Normal file
6
LctMonolith/Services/Models/RevokeRequest.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public class RevokeRequest
|
||||
{
|
||||
public string RefreshToken { get; set; } = null!;
|
||||
}
|
||||
3
LctMonolith/Services/Models/TokenPair.cs
Normal file
3
LctMonolith/Services/Models/TokenPair.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public record TokenPair(string AccessToken, DateTime AccessTokenExpiresAt, string RefreshToken, DateTime RefreshTokenExpiresAt);
|
||||
@@ -0,0 +1,9 @@
|
||||
using LctMonolith.Models;
|
||||
|
||||
namespace LctMonolith.Services.Models;
|
||||
|
||||
public class UpdateMissionStatusRequest
|
||||
{
|
||||
public MissionStatus Status { get; set; }
|
||||
public string? SubmissionData { get; set; }
|
||||
}
|
||||
@@ -1 +1,79 @@
|
||||
using LctMonolith.Database.UnitOfWork;
|
||||
using LctMonolith.Models;
|
||||
using LctMonolith.Services.Contracts;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
|
||||
/// <summary>
|
||||
/// In-app user notifications CRUD / read-state operations.
|
||||
/// </summary>
|
||||
public class NotificationService : INotificationService
|
||||
{
|
||||
private readonly IUnitOfWork _uow;
|
||||
|
||||
public NotificationService(IUnitOfWork uow)
|
||||
{
|
||||
_uow = uow;
|
||||
}
|
||||
|
||||
public async Task<Notification> CreateAsync(Guid userId, string type, string title, string message, CancellationToken ct = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type)) throw new ArgumentException("Required", nameof(type));
|
||||
if (string.IsNullOrWhiteSpace(title)) throw new ArgumentException("Required", nameof(title));
|
||||
if (string.IsNullOrWhiteSpace(message)) throw new ArgumentException("Required", nameof(message));
|
||||
|
||||
var n = new Notification
|
||||
{
|
||||
UserId = userId,
|
||||
Type = type.Trim(),
|
||||
Title = title.Trim(),
|
||||
Message = message.Trim(),
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
IsRead = false
|
||||
};
|
||||
await _uow.Notifications.AddAsync(n, ct);
|
||||
await _uow.SaveChangesAsync(ct);
|
||||
return n;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Notification>> GetUnreadAsync(Guid userId, CancellationToken ct = default)
|
||||
{
|
||||
var query = _uow.Notifications.Query(n => n.UserId == userId && !n.IsRead, q => q.OrderByDescending(x => x.CreatedAt));
|
||||
return await query.Take(100).ToListAsync(ct);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Notification>> GetAllAsync(Guid userId, int take = 100, CancellationToken ct = default)
|
||||
{
|
||||
if (take <= 0) take = 1;
|
||||
if (take > 500) take = 500;
|
||||
var query = _uow.Notifications.Query(n => n.UserId == userId, q => q.OrderByDescending(x => x.CreatedAt));
|
||||
return await query.Take(take).ToListAsync(ct);
|
||||
}
|
||||
|
||||
public async Task MarkReadAsync(Guid userId, Guid notificationId, CancellationToken ct = default)
|
||||
{
|
||||
var notif = await _uow.Notifications.Query(n => n.Id == notificationId && n.UserId == userId).FirstOrDefaultAsync(ct)
|
||||
?? throw new KeyNotFoundException("Notification not found");
|
||||
if (!notif.IsRead)
|
||||
{
|
||||
notif.IsRead = true;
|
||||
notif.ReadAt = DateTime.UtcNow;
|
||||
await _uow.SaveChangesAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> MarkAllReadAsync(Guid userId, CancellationToken ct = default)
|
||||
{
|
||||
var unread = await _uow.Notifications.Query(n => n.UserId == userId && !n.IsRead).ToListAsync(ct);
|
||||
if (unread.Count == 0) return 0;
|
||||
var now = DateTime.UtcNow;
|
||||
foreach (var n in unread)
|
||||
{
|
||||
n.IsRead = true;
|
||||
n.ReadAt = now;
|
||||
}
|
||||
await _uow.SaveChangesAsync(ct);
|
||||
return unread.Count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using LctMonolith.Domain.Entities;
|
||||
using LctMonolith.Infrastructure.UnitOfWork;
|
||||
using LctMonolith.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Serilog;
|
||||
using System.Text.Json;
|
||||
using LctMonolith.Database.UnitOfWork;
|
||||
using LctMonolith.Services.Contracts;
|
||||
|
||||
namespace LctMonolith.Services;
|
||||
|
||||
@@ -72,4 +73,3 @@ public class StoreService : IStoreService
|
||||
return inv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@ using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using LctMonolith.Application.Options;
|
||||
using LctMonolith.Domain.Entities;
|
||||
using LctMonolith.Infrastructure.UnitOfWork;
|
||||
using LctMonolith.Database.UnitOfWork;
|
||||
using LctMonolith.Models;
|
||||
using LctMonolith.Services.Contracts;
|
||||
using LctMonolith.Services.Models;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
Reference in New Issue
Block a user