Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: webui notifications #374

Draft
wants to merge 29 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
}
34 changes: 28 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,24 @@ 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();
}
10 changes: 4 additions & 6 deletions src/Application/Characters/Models/CharacterPublicViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
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 CharacterRatingViewModel Rating { get; init; } = new();
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; }
}
12 changes: 6 additions & 6 deletions src/Application/Characters/Queries/GetLeaderboardQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@

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; }

internal class Handler : IMediatorRequestHandler<GetLeaderboardQuery, IList<CharacterPublicViewModel>>
internal class Handler : IMediatorRequestHandler<GetLeaderboardQuery, IList<CharacterPublicCompetitiveViewModel>>
{
private readonly ICrpgDbContext _db;
private readonly IMapper _mapper;
Expand All @@ -29,11 +29,11 @@ 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)
{
// 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
Expand All @@ -42,10 +42,10 @@ public async Task<Result<IList<CharacterPublicViewModel>>> Handle(GetLeaderboard
.Where(c => (req.Region == null || req.Region == c.User!.Region)
&& (req.CharacterClass == null || req.CharacterClass == c.Class))
.Take(500)
.ProjectTo<CharacterPublicViewModel>(_mapper.ConfigurationProvider)
.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
Loading