cs-codex-dist-tests/Tools/BiblioTech/Rewards/RoleDriver.cs

225 lines
7.4 KiB
C#
Raw Normal View History

2024-01-22 09:27:07 +00:00
using Discord;
using Discord.WebSocket;
using DiscordRewards;
2023-12-20 14:56:03 +00:00
namespace BiblioTech.Rewards
{
2024-02-19 13:56:49 +00:00
public class RoleDriver : IDiscordRoleDriver
2023-12-20 14:56:03 +00:00
{
2024-01-20 12:07:56 +00:00
private readonly DiscordSocketClient client;
2023-12-20 14:56:03 +00:00
private readonly SocketTextChannel? rewardsChannel;
private readonly RewardRepo repo = new RewardRepo();
2023-12-20 14:56:03 +00:00
2024-02-19 13:56:49 +00:00
public RoleDriver(DiscordSocketClient client)
2023-12-20 14:56:03 +00:00
{
2024-01-20 12:07:56 +00:00
this.client = client;
2023-12-20 14:56:03 +00:00
if (!string.IsNullOrEmpty(Program.Config.RewardsChannelName))
{
2024-01-20 12:07:56 +00:00
rewardsChannel = GetGuild().TextChannels.SingleOrDefault(c => c.Name == Program.Config.RewardsChannelName);
2023-12-20 14:56:03 +00:00
}
}
2024-01-22 09:27:07 +00:00
public async Task GiveRewards(GiveRewardsCommand rewards)
2023-12-20 14:56:03 +00:00
{
2024-01-20 12:07:56 +00:00
var guild = GetGuild();
2024-01-22 09:27:07 +00:00
// We load all role and user information first,
// so we don't ask the server for the same info multiple times.
var context = new RewardContext(
await LoadAllUsers(guild),
LookUpAllRoles(guild, rewards),
rewardsChannel);
await context.ProcessGiveRewardsCommand(LookUpUsers(rewards));
2024-01-22 09:27:07 +00:00
}
private async Task<Dictionary<ulong, IGuildUser>> LoadAllUsers(SocketGuild guild)
{
var result = new Dictionary<ulong, IGuildUser>();
var users = guild.GetUsersAsync();
await foreach (var ulist in users)
{
foreach (var u in ulist)
{
result.Add(u.Id, u);
}
}
return result;
}
private Dictionary<ulong, RoleReward> LookUpAllRoles(SocketGuild guild, GiveRewardsCommand rewards)
2024-01-22 09:27:07 +00:00
{
var result = new Dictionary<ulong, RoleReward>();
2024-01-22 09:27:07 +00:00
foreach (var r in rewards.Rewards)
{
if (!result.ContainsKey(r.RewardId))
2024-01-22 09:27:07 +00:00
{
var rewardConfig = repo.Rewards.SingleOrDefault(rr => rr.RoleId == r.RewardId);
if (rewardConfig == null)
{
Program.Log.Log($"No Reward is configured for id '{r.RewardId}'.");
}
else
2024-01-22 09:27:07 +00:00
{
var socketRole = guild.GetRole(r.RewardId);
if (socketRole == null)
{
Program.Log.Log($"Guild Role by id '{r.RewardId}' not found.");
}
else
{
result.Add(r.RewardId, new RoleReward(socketRole, rewardConfig));
2024-01-22 09:27:07 +00:00
}
}
}
}
return result;
}
private UserReward[] LookUpUsers(GiveRewardsCommand rewards)
{
return rewards.Rewards.Select(LookUpUserData).ToArray();
}
private UserReward LookUpUserData(RewardUsersCommand command)
{
return new UserReward(command,
command.UserAddresses
.Select(LookUpUserDataForAddress)
.Where(d => d != null)
.Cast<UserData>()
.ToArray());
}
private UserData? LookUpUserDataForAddress(string address)
{
try
{
return Program.UserRepo.GetUserDataForAddress(new GethPlugin.EthAddress(address));
}
catch (Exception ex)
{
Program.Log.Error("Error during UserData lookup: " + ex);
return null;
}
}
2024-01-22 09:27:07 +00:00
private SocketGuild GetGuild()
{
2024-02-19 13:56:49 +00:00
var guild = client.Guilds.SingleOrDefault(g => g.Name == Program.Config.ServerName);
if (guild == null)
{
throw new Exception($"Unable to find guild by name: '{Program.Config.ServerName}'. " +
$"Known guilds: [{string.Join(",", client.Guilds.Select(g => g.Name))}]");
}
return guild;
2024-01-22 09:27:07 +00:00
}
}
2023-12-20 14:56:03 +00:00
public class RoleReward
{
public RoleReward(SocketRole socketRole, RewardConfig reward)
{
SocketRole = socketRole;
Reward = reward;
}
public SocketRole SocketRole { get; }
public RewardConfig Reward { get; }
}
public class UserReward
{
public UserReward(RewardUsersCommand rewardCommand, UserData[] users)
{
RewardCommand = rewardCommand;
Users = users;
}
public RewardUsersCommand RewardCommand { get; }
public UserData[] Users { get; }
}
2024-01-22 09:27:07 +00:00
public class RewardContext
{
private readonly Dictionary<ulong, IGuildUser> users;
private readonly Dictionary<ulong, RoleReward> roles;
2024-01-22 09:27:07 +00:00
private readonly SocketTextChannel? rewardsChannel;
2023-12-20 14:56:03 +00:00
public RewardContext(Dictionary<ulong, IGuildUser> users, Dictionary<ulong, RoleReward> roles, SocketTextChannel? rewardsChannel)
2024-01-22 09:27:07 +00:00
{
this.users = users;
this.roles = roles;
this.rewardsChannel = rewardsChannel;
}
2024-01-20 12:07:56 +00:00
public async Task ProcessGiveRewardsCommand(UserReward[] rewards)
2024-01-22 09:27:07 +00:00
{
foreach (var rewardCommand in rewards)
2024-01-22 09:27:07 +00:00
{
if (roles.ContainsKey(rewardCommand.RewardCommand.RewardId))
2024-01-22 09:27:07 +00:00
{
var role = roles[rewardCommand.RewardCommand.RewardId];
2024-01-22 09:27:07 +00:00
await ProcessRewardCommand(role, rewardCommand);
}
}
}
2023-12-20 14:56:03 +00:00
private async Task ProcessRewardCommand(RoleReward role, UserReward reward)
2024-01-22 09:27:07 +00:00
{
foreach (var user in reward.Users)
{
await GiveReward(role, user);
}
2023-12-20 14:56:03 +00:00
}
private async Task GiveReward(RoleReward role, UserData user)
2024-01-22 09:27:07 +00:00
{
if (!users.ContainsKey(user.DiscordId))
{
Program.Log.Log($"User by id '{user.DiscordId}' not found.");
return;
}
var guildUser = users[user.DiscordId];
var alreadyHas = guildUser.RoleIds.ToArray();
if (alreadyHas.Any(r => r == role.Reward.RoleId)) return;
2024-01-22 09:27:07 +00:00
await GiveRole(guildUser, role.SocketRole);
2024-01-22 09:27:07 +00:00
await SendNotification(role, user, guildUser);
await Task.Delay(1000);
}
private async Task GiveRole(IGuildUser user, SocketRole role)
2023-12-20 14:56:03 +00:00
{
try
{
2024-01-20 12:07:56 +00:00
Program.Log.Log($"Giving role {role.Name}={role.Id} to user {user.DisplayName}");
2024-01-22 09:27:07 +00:00
await user.AddRoleAsync(role);
2023-12-20 14:56:03 +00:00
}
catch (Exception ex)
{
Program.Log.Error($"Failed to give role '{role.Name}' to user '{user.DisplayName}': {ex}");
}
}
private async Task SendNotification(RoleReward reward, UserData userData, IGuildUser user)
2023-12-20 14:56:03 +00:00
{
try
{
if (userData.NotificationsEnabled && rewardsChannel != null)
{
var msg = reward.Reward.Message.Replace(RewardConfig.UsernameTag, $"<@{user.Id}>");
2024-01-22 09:27:07 +00:00
await rewardsChannel.SendMessageAsync(msg);
2023-12-20 14:56:03 +00:00
}
}
catch (Exception ex)
{
Program.Log.Error($"Failed to notify user '{user.DisplayName}' about role '{reward.SocketRole.Name}': {ex}");
2023-12-20 14:56:03 +00:00
}
}
}
}