2024-01-22 09:27:07 +00:00
|
|
|
|
using Discord;
|
|
|
|
|
using Discord.WebSocket;
|
2023-12-20 14:56:03 +00:00
|
|
|
|
|
|
|
|
|
namespace BiblioTech.Rewards
|
|
|
|
|
{
|
|
|
|
|
public class RoleController : IDiscordRoleController
|
|
|
|
|
{
|
2024-01-22 09:27:07 +00:00
|
|
|
|
public const string UsernameTag = "<USER>";
|
2024-01-20 12:07:56 +00:00
|
|
|
|
private readonly DiscordSocketClient client;
|
2023-12-20 14:56:03 +00:00
|
|
|
|
private readonly SocketTextChannel? rewardsChannel;
|
2024-01-22 09:27:07 +00:00
|
|
|
|
private readonly RewardsRepo repo = new RewardsRepo();
|
2023-12-20 14:56:03 +00:00
|
|
|
|
|
2024-01-20 12:07:56 +00:00
|
|
|
|
public RoleController(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(rewards);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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, RoleRewardConfig> LookUpAllRoles(SocketGuild guild, GiveRewardsCommand rewards)
|
|
|
|
|
{
|
|
|
|
|
var result = new Dictionary<ulong, RoleRewardConfig>();
|
|
|
|
|
foreach (var r in rewards.Rewards)
|
|
|
|
|
{
|
|
|
|
|
var role = repo.Rewards.SingleOrDefault(rr => rr.RoleId == r.RewardId);
|
|
|
|
|
if (role == null)
|
|
|
|
|
{
|
|
|
|
|
Program.Log.Log($"No RoleReward is configured for reward with id '{r.RewardId}'.");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (role.SocketRole == null)
|
|
|
|
|
{
|
|
|
|
|
var socketRole = guild.GetRole(r.RewardId);
|
|
|
|
|
if (socketRole == null)
|
|
|
|
|
{
|
|
|
|
|
Program.Log.Log($"Guild Role by id '{r.RewardId}' not found.");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
role.SocketRole = socketRole;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
result.Add(role.RoleId, role);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private SocketGuild GetGuild()
|
|
|
|
|
{
|
|
|
|
|
return client.Guilds.Single(g => g.Name == Program.Config.ServerName);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-20 14:56:03 +00:00
|
|
|
|
|
2024-01-22 09:27:07 +00:00
|
|
|
|
public class RewardContext
|
|
|
|
|
{
|
|
|
|
|
private readonly Dictionary<ulong, IGuildUser> users;
|
|
|
|
|
private readonly Dictionary<ulong, RoleRewardConfig> roles;
|
|
|
|
|
private readonly SocketTextChannel? rewardsChannel;
|
2023-12-20 14:56:03 +00:00
|
|
|
|
|
2024-01-22 09:27:07 +00:00
|
|
|
|
public RewardContext(Dictionary<ulong, IGuildUser> users, Dictionary<ulong, RoleRewardConfig> roles, SocketTextChannel? rewardsChannel)
|
|
|
|
|
{
|
|
|
|
|
this.users = users;
|
|
|
|
|
this.roles = roles;
|
|
|
|
|
this.rewardsChannel = rewardsChannel;
|
|
|
|
|
}
|
2024-01-20 12:07:56 +00:00
|
|
|
|
|
2024-01-22 09:27:07 +00:00
|
|
|
|
public async Task ProcessGiveRewardsCommand(GiveRewardsCommand rewards)
|
|
|
|
|
{
|
|
|
|
|
foreach (var rewardCommand in rewards.Rewards)
|
|
|
|
|
{
|
|
|
|
|
if (roles.ContainsKey(rewardCommand.RewardId))
|
|
|
|
|
{
|
|
|
|
|
var role = roles[rewardCommand.RewardId];
|
|
|
|
|
await ProcessRewardCommand(role, rewardCommand);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-20 14:56:03 +00:00
|
|
|
|
|
2024-01-22 09:27:07 +00:00
|
|
|
|
private async Task ProcessRewardCommand(RoleRewardConfig role, RewardUsersCommand reward)
|
|
|
|
|
{
|
|
|
|
|
foreach (var user in reward.Users)
|
|
|
|
|
{
|
|
|
|
|
await GiveReward(role, user);
|
|
|
|
|
}
|
2023-12-20 14:56:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-22 09:27:07 +00:00
|
|
|
|
private async Task GiveReward(RoleRewardConfig role, UserData user)
|
|
|
|
|
{
|
|
|
|
|
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.RoleId)) return;
|
|
|
|
|
|
|
|
|
|
await GiveRole(guildUser, role.SocketRole!);
|
|
|
|
|
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}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-22 09:27:07 +00:00
|
|
|
|
private async Task SendNotification(RoleRewardConfig reward, UserData userData, IGuildUser user)
|
2023-12-20 14:56:03 +00:00
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (userData.NotificationsEnabled && rewardsChannel != null)
|
|
|
|
|
{
|
2024-01-22 09:27:07 +00:00
|
|
|
|
var msg = reward.Message.Replace(RoleController.UsernameTag, $"<@{user.Id}>");
|
|
|
|
|
await rewardsChannel.SendMessageAsync(msg);
|
2023-12-20 14:56:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2024-01-22 09:27:07 +00:00
|
|
|
|
Program.Log.Error($"Failed to notify user '{user.DisplayName}' about role '{reward.SocketRole!.Name}': {ex}");
|
2023-12-20 14:56:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-22 09:27:07 +00:00
|
|
|
|
public class RoleRewardConfig
|
2023-12-20 14:56:03 +00:00
|
|
|
|
{
|
2024-01-22 09:27:07 +00:00
|
|
|
|
public RoleRewardConfig(ulong roleId, string message)
|
2023-12-20 14:56:03 +00:00
|
|
|
|
{
|
|
|
|
|
RoleId = roleId;
|
|
|
|
|
Message = message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ulong RoleId { get; }
|
|
|
|
|
public string Message { get; }
|
2024-01-22 09:27:07 +00:00
|
|
|
|
public SocketRole? SocketRole { get; set; }
|
2023-12-20 14:56:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|