Skip to content

Commit

Permalink
user notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
or2e committed Oct 17, 2024
1 parent fdbb1a0 commit 167e299
Show file tree
Hide file tree
Showing 109 changed files with 2,484 additions and 1,261 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Crpg.Application.Characters.Models;
using Crpg.Application.Clans.Models;
using Crpg.Application.Users.Models;

namespace Crpg.Application.ActivityLogs.Models;

public record ActivityLogMetadataEnrichedViewModel
{
public IList<ClanPublicViewModel> Clans { get; init; } = Array.Empty<ClanPublicViewModel>();
public IList<UserPublicViewModel> Users { get; init; } = Array.Empty<UserPublicViewModel>();
public IList<CharacterPublicViewModel> Characters { get; init; } = Array.Empty<CharacterPublicViewModel>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Crpg.Application.ActivityLogs.Models;

public record ActivityLogWithDictViewModel
{
public IList<ActivityLogViewModel> ActivityLogs { get; init; } = Array.Empty<ActivityLogViewModel>();
public ActivityLogMetadataEnrichedViewModel Dict { get; init; } = new();
}
33 changes: 27 additions & 6 deletions src/Application/ActivityLogs/Queries/GetActivityLogsQuery.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
using AutoMapper;
using Crpg.Application.ActivityLogs.Models;
using Crpg.Application.Characters.Models;
using Crpg.Application.Clans.Models;
using Crpg.Application.Common.Interfaces;
using Crpg.Application.Common.Mediator;
using Crpg.Application.Common.Results;
using Crpg.Application.Common.Services;
using Crpg.Application.Users.Models;
using Crpg.Domain.Entities.ActivityLogs;
using FluentValidation;
using Microsoft.EntityFrameworkCore;

namespace Crpg.Application.ActivityLogs.Queries;

public record GetActivityLogsQuery : IMediatorRequest<IList<ActivityLogViewModel>>
public record GetActivityLogsQuery : IMediatorRequest<ActivityLogWithDictViewModel>
{
public DateTime From { get; init; }
public DateTime To { get; init; }
Expand All @@ -25,18 +29,20 @@ public Validator()
}
}

internal class Handler : IMediatorRequestHandler<GetActivityLogsQuery, IList<ActivityLogViewModel>>
internal class Handler : IMediatorRequestHandler<GetActivityLogsQuery, ActivityLogWithDictViewModel>
{
private readonly ICrpgDbContext _db;
private readonly IMapper _mapper;
private readonly IActivityLogService _activityLogService;

public Handler(ICrpgDbContext db, IMapper mapper)
public Handler(ICrpgDbContext db, IMapper mapper, IActivityLogService activityLogService)
{
_db = db;
_mapper = mapper;
_activityLogService = activityLogService;
}

public async Task<Result<IList<ActivityLogViewModel>>> Handle(GetActivityLogsQuery req,
public async Task<Result<ActivityLogWithDictViewModel>> Handle(GetActivityLogsQuery req,
CancellationToken cancellationToken)
{
var activityLogs = await _db.ActivityLogs
Expand All @@ -48,8 +54,23 @@ public async Task<Result<IList<ActivityLogViewModel>>> Handle(GetActivityLogsQue
&& (req.Types.Length == 0 || req.Types.Contains(l.Type)))
.OrderByDescending(l => l.CreatedAt)
.Take(1000)
.ToArrayAsync(cancellationToken);
return new(_mapper.Map<IList<ActivityLogViewModel>>(activityLogs));
.ToListAsync(cancellationToken);

var entitiesFromMetadata = _activityLogService.ExtractEntitiesFromMetadata(activityLogs);
var clans = await _db.Clans.Where(c => entitiesFromMetadata.ClansIds.Contains(c.Id)).ToArrayAsync();
var users = await _db.Users.Where(u => entitiesFromMetadata.UsersIds.Contains(u.Id)).ToArrayAsync();
var characters = await _db.Characters.Where(c => entitiesFromMetadata.CharactersIds.Contains(c.Id)).ToArrayAsync();

return new(new ActivityLogWithDictViewModel()
{
ActivityLogs = _mapper.Map<IList<ActivityLogViewModel>>(activityLogs),
Dict = new()
{
Clans = _mapper.Map<IList<ClanPublicViewModel>>(clans),
Users = _mapper.Map<IList<UserPublicViewModel>>(users),
Characters = _mapper.Map<IList<CharacterPublicViewModel>>(characters),
},
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal class Handler : IMediatorRequestHandler<RewardCharacterCommand, Charact
private readonly ICharacterService _characterService;
private readonly IExperienceTable _experienceTable;
private readonly IActivityLogService _activityLogService;
private readonly IUserNotificationService _userNotificationService;
private readonly ICrpgDbContext _db;
private readonly IMapper _mapper;
private readonly Constants _constants;
Expand All @@ -43,13 +44,15 @@ public Handler(
ICharacterService characterService,
IExperienceTable experienceTable,
IActivityLogService activityLogService,
IUserNotificationService userNotificationService,
ICrpgDbContext db,
IMapper mapper,
Constants constants)
{
_characterService = characterService;
_experienceTable = experienceTable;
_activityLogService = activityLogService;
_userNotificationService = userNotificationService;
_db = db;
_mapper = mapper;
_constants = constants;
Expand Down Expand Up @@ -90,7 +93,9 @@ public async Task<Result<CharacterViewModel>> Handle(RewardCharacterCommand req,
_characterService.GiveExperience(character, req.Experience, useExperienceMultiplier: false);
}

_db.ActivityLogs.Add(_activityLogService.CreateCharacterRewardedLog(req.UserId, req.ActorUserId, req.CharacterId, req.Experience));
var activityLog = _activityLogService.CreateCharacterRewardedLog(req.UserId, req.ActorUserId, req.CharacterId, req.Experience);
_db.ActivityLogs.Add(activityLog);
_db.UserNotifications.Add(_userNotificationService.CreateCharacterRewardedToUserNotification(req.UserId, activityLog.Id));

await _db.SaveChangesAsync(cancellationToken);
Logger.LogInformation("Character '{0}' rewarded", req.CharacterId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Crpg.Application.Common.Mappings;
using Crpg.Application.Users.Models;
using Crpg.Domain.Entities.Characters;

namespace Crpg.Application.Characters.Models;

public record CharacterPublicCompetitiveViewModel : IMapFrom<Character>
{
public int Id { get; init; }
public int Level { get; init; }
public CharacterClass Class { get; init; }
public CharacterRatingViewModel Rating { get; init; } = new();
public UserPublicViewModel User { get; init; } = new();
}
11 changes: 5 additions & 6 deletions src/Application/Characters/Models/CharacterPublicViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using Crpg.Application.Common.Mappings;
using Crpg.Application.Users.Models;
using Crpg.Domain.Entities.Characters;

namespace Crpg.Application.Characters.Models;

public record CharacterPublicViewModel : IMapFrom<Character>
{
public int Id { get; init; }
public int Level { get; init; }
public CharacterClass Class { get; init; }
public IList<CharacterStatisticsViewModel> Statistics { get; init; } = Array.Empty<CharacterStatisticsViewModel>();
public UserPublicViewModel User { get; init; } = new();
public int Id { get; init; }
public int Level { get; init; }
public string Name { get; init; } = string.Empty;
public CharacterClass Class { get; init; }
public IList<CharacterStatisticsViewModel> Statistics { get; init; } = Array.Empty<CharacterStatisticsViewModel>();
}
25 changes: 12 additions & 13 deletions src/Application/Characters/Queries/GetLeaderboardQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@

namespace Crpg.Application.Characters.Queries;

public record GetLeaderboardQuery : IMediatorRequest<IList<CharacterPublicViewModel>>
public record GetLeaderboardQuery : IMediatorRequest<IList<CharacterPublicCompetitiveViewModel>>
{
public Region? Region { get; set; }
public CharacterClass? CharacterClass { get; set; }
public GameMode? GameMode { get; set; }

internal class Handler : IMediatorRequestHandler<GetLeaderboardQuery, IList<CharacterPublicViewModel>>
internal class Handler : IMediatorRequestHandler<GetLeaderboardQuery, IList<CharacterPublicCompetitiveViewModel>>
{
private readonly ICrpgDbContext _db;
private readonly IMapper _mapper;
Expand All @@ -31,25 +31,24 @@ public Handler(ICrpgDbContext db, IMapper mapper, IMemoryCache cache)
_cache = cache;
}

public async Task<Result<IList<CharacterPublicViewModel>>> Handle(GetLeaderboardQuery req, CancellationToken cancellationToken)
public async Task<Result<IList<CharacterPublicCompetitiveViewModel>>> Handle(GetLeaderboardQuery req, CancellationToken cancellationToken)
{
string cacheKey = GetCacheKey(req);

if (_cache.TryGetValue(cacheKey, out IList<CharacterPublicViewModel>? results) == false)
if (_cache.TryGetValue(cacheKey, out IList<CharacterPublicCompetitiveViewModel>? results) == false)
{
var requestGameMode = req.GameMode ?? Domain.Entities.Servers.GameMode.CRPGBattle;
// Todo: use DistinctBy here when EfCore implements it (does not work for now: https://github.com/dotnet/efcore/issues/27470 )
var topRatedCharactersByRegion = await _db.Characters
.Include(c => c.User)
.Where(c => (req.Region == null || req.Region == c.User!.Region)
&& (req.CharacterClass == null || req.CharacterClass == c.Class)
&& c.Statistics.First(s => s.GameMode == requestGameMode) != null)
.OrderByDescending(c => c.Statistics.First(s => s.GameMode == requestGameMode).Rating.CompetitiveValue)
.Take(500)
.ProjectTo<CharacterPublicViewModel>(_mapper.ConfigurationProvider)
.ToArrayAsync(cancellationToken);
.Include(c => c.User)
.OrderByDescending(c => c.Statistics.First(s => s.GameMode == requestGameMode).Rating.CompetitiveValue)
.Where(c => (req.Region == null || req.Region == c.User!.Region)
&& (req.CharacterClass == null || req.CharacterClass == c.Class))
.Take(500)
.ProjectTo<CharacterPublicCompetitiveViewModel>(_mapper.ConfigurationProvider)
.ToArrayAsync(cancellationToken);

IList<CharacterPublicViewModel> data = topRatedCharactersByRegion.DistinctBy(c => c.User.Id).Take(50).ToList();
IList<CharacterPublicCompetitiveViewModel> data = topRatedCharactersByRegion.DistinctBy(c => c.User.Id).Take(50).ToList();

var cacheOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@ internal class Handler : IMediatorRequestHandler<AddItemToClanArmoryCommand, Cla

private readonly ICrpgDbContext _db;
private readonly IMapper _mapper;
private readonly IActivityLogService _activityLogService;
private readonly IClanService _clanService;

public Handler(ICrpgDbContext db, IMapper mapper, IActivityLogService activityLogService, IClanService clanService)
public Handler(ICrpgDbContext db, IMapper mapper, IClanService clanService)
{
_activityLogService = activityLogService;
_db = db;
_mapper = mapper;
_clanService = clanService;
Expand Down Expand Up @@ -58,8 +56,6 @@ public async Task<Result<ClanArmoryItemViewModel>> Handle(AddItemToClanArmoryCom
return new(result.Errors);
}

_db.ActivityLogs.Add(_activityLogService.CreateAddItemToClanArmory(user.Id, clan.Id, req.UserItemId));

await _db.SaveChangesAsync(cancellationToken);
Logger.LogInformation("User '{0}' added item '{1}' to the armory '{2}'", req.UserId, req.UserItemId, req.ClanId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ internal class Handler : IMediatorRequestHandler<BorrowItemFromClanArmoryCommand

private readonly ICrpgDbContext _db;
private readonly IMapper _mapper;
private readonly IActivityLogService _activityLogService;
private readonly IClanService _clanService;

public Handler(ICrpgDbContext db, IMapper mapper, IActivityLogService activityLogService, IClanService clanService)
public Handler(
ICrpgDbContext db,
IMapper mapper,
IClanService clanService)
{
_activityLogService = activityLogService;
_db = db;
_mapper = mapper;
_clanService = clanService;
Expand Down Expand Up @@ -58,8 +59,6 @@ public async Task<Result<ClanArmoryBorrowedItemViewModel>> Handle(BorrowItemFrom
return new(result.Errors);
}

_db.ActivityLogs.Add(_activityLogService.CreateBorrowItemFromClanArmory(user.Id, clan.Id, req.UserItemId));

await _db.SaveChangesAsync(cancellationToken);
Logger.LogInformation("User '{0}' borrowed item '{1}' from the armory '{2}'", req.UserId, req.UserItemId, req.ClanId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ internal class Handler : IMediatorRequestHandler<RemoveItemFromClanArmoryCommand
private static readonly ILogger Logger = LoggerFactory.CreateLogger<RemoveItemFromClanArmoryCommand>();

private readonly ICrpgDbContext _db;
private readonly IActivityLogService _activityLogService;
private readonly IClanService _clanService;

public Handler(ICrpgDbContext db, IActivityLogService activityLogService, IClanService clanService)
public Handler(ICrpgDbContext db, IClanService clanService)
{
_activityLogService = activityLogService;
_db = db;
_clanService = clanService;
}
Expand Down Expand Up @@ -54,8 +52,6 @@ public async Task<Result> Handle(RemoveItemFromClanArmoryCommand req, Cancellati
return new(result.Errors);
}

_db.ActivityLogs.Add(_activityLogService.CreateRemoveItemFromClanArmory(user.Id, clan.Id, req.UserItemId));

await _db.SaveChangesAsync(cancellationToken);
Logger.LogInformation("User '{0}' removed item '{1}' from the armory '{2}'", req.UserId, req.UserItemId, req.ClanId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ internal class Handler : IMediatorRequestHandler<ReturnItemToClanArmoryCommand>
private static readonly ILogger Logger = LoggerFactory.CreateLogger<ReturnItemToClanArmoryCommand>();

private readonly ICrpgDbContext _db;
private readonly IActivityLogService _activityLogService;
private readonly IClanService _clanService;

public Handler(ICrpgDbContext db, IActivityLogService activityLogService, IClanService clanService)
public Handler(ICrpgDbContext db, IClanService clanService)
{
_activityLogService = activityLogService;
_db = db;
_clanService = clanService;
}
Expand Down Expand Up @@ -54,8 +52,6 @@ public async Task<Result> Handle(ReturnItemToClanArmoryCommand req, Cancellation
return new(result.Errors);
}

_db.ActivityLogs.Add(_activityLogService.CreateReturnItemToClanArmory(user.Id, clan.Id, req.UserItemId));

await _db.SaveChangesAsync(cancellationToken);
Logger.LogInformation("User '{0}' returned item '{1}' to the armory '{2}'", req.UserId, req.UserItemId, req.ClanId);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Crpg.Application.Common.Interfaces;
using Crpg.Application.Common.Mediator;
using Crpg.Application.Common.Results;
using Crpg.Application.Common.Services;
using Crpg.Sdk.Abstractions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
Expand All @@ -16,11 +17,15 @@ internal class Handler : IMediatorRequestHandler<ReturnUnusedItemsToClanArmoryCo

private readonly ICrpgDbContext _db;
private readonly IDateTime _dateTime;
private readonly IActivityLogService _activityLogService;
private readonly IUserNotificationService _userNotificationService;

public Handler(ICrpgDbContext db, IDateTime dateTime)
public Handler(ICrpgDbContext db, IDateTime dateTime, IActivityLogService activityLogService, IUserNotificationService userNotificationService)
{
_db = db;
_dateTime = dateTime;
_activityLogService = activityLogService;
_userNotificationService = userNotificationService;
}

public async Task<Result> Handle(ReturnUnusedItemsToClanArmoryCommand req, CancellationToken cancellationToken)
Expand All @@ -40,6 +45,12 @@ public async Task<Result> Handle(ReturnUnusedItemsToClanArmoryCommand req, Cance
var equipped = u.ClanMembership!.ArmoryBorrowedItems.SelectMany(bi => bi.UserItem!.EquippedItems);
_db.EquippedItems.RemoveRange(equipped);
_db.ClanArmoryBorrowedItems.RemoveRange(u.ClanMembership!.ArmoryBorrowedItems);
foreach (var bi in u.ClanMembership!.ArmoryBorrowedItems)
{
var activityLog = _activityLogService.CreateReturnItemToClanArmoryLog(bi.UserItem!.UserId, u.ClanMembership.ClanId, bi.UserItem!);
_db.ActivityLogs.Add(activityLog);
_db.UserNotifications.Add(_userNotificationService.CreateClanArmoryRemoveItemToBorrowerNotification(u.Id, activityLog.Id));
}
}

await _db.SaveChangesAsync(cancellationToken);
Expand Down
7 changes: 6 additions & 1 deletion src/Application/Clans/Commands/CreateClanCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Crpg.Application.Common.Interfaces;
using Crpg.Application.Common.Mediator;
using Crpg.Application.Common.Results;
using Crpg.Application.Common.Services;
using Crpg.Domain.Entities;
using Crpg.Domain.Entities.Clans;
using FluentValidation;
Expand Down Expand Up @@ -73,10 +74,13 @@ internal class Handler : IMediatorRequestHandler<CreateClanCommand, ClanViewMode
private readonly ICrpgDbContext _db;
private readonly IMapper _mapper;

public Handler(ICrpgDbContext db, IMapper mapper)
private readonly IActivityLogService _activityLogService;

public Handler(ICrpgDbContext db, IMapper mapper, IActivityLogService activityLogService)
{
_db = db;
_mapper = mapper;
_activityLogService = activityLogService;
}

public async Task<Result<ClanViewModel>> Handle(CreateClanCommand req, CancellationToken cancellationToken)
Expand Down Expand Up @@ -126,6 +130,7 @@ public async Task<Result<ClanViewModel>> Handle(CreateClanCommand req, Cancellat
};

_db.Clans.Add(clan);
_db.ActivityLogs.Add(_activityLogService.CreateClanCreatedLog(req.UserId, clan.Id));
await _db.SaveChangesAsync(cancellationToken);
Logger.LogInformation("User '{0}' created clan '[{1}] {2}' ({3})", req.UserId, req.Tag, req.Name, clan.Id);
return new(_mapper.Map<ClanViewModel>(clan));
Expand Down
Loading

0 comments on commit 167e299

Please sign in to comment.