/ Tools / BiblioTech / Rewards / RoleModifyContext.cs
RoleModifyContext.cs
  1  using Discord.WebSocket;
  2  using Discord;
  3  using DiscordRewards;
  4  using Nethereum.Model;
  5  using Logging;
  6  
  7  namespace BiblioTech.Rewards
  8  {
  9      public class RoleModifyContext
 10      {
 11          private Dictionary<ulong, IGuildUser> users = new();
 12          private Dictionary<ulong, SocketRole> roles = new();
 13          private DateTime lastLoad = DateTime.MinValue;
 14          private readonly object _lock = new object();
 15  
 16          private readonly SocketGuild guild;
 17          private readonly UserRepo userRepo;
 18          private readonly ILog log;
 19          private readonly SocketTextChannel? rewardsChannel;
 20  
 21          public RoleModifyContext(SocketGuild guild, UserRepo userRepo, ILog log, SocketTextChannel? rewardsChannel)
 22          {
 23              this.guild = guild;
 24              this.userRepo = userRepo;
 25              this.log = log;
 26              this.rewardsChannel = rewardsChannel;
 27          }
 28  
 29          public void Initialize()
 30          {
 31              lock (_lock)
 32              {
 33                  var span = DateTime.UtcNow - lastLoad;
 34                  if (span > TimeSpan.FromMinutes(10))
 35                  {
 36                      lastLoad = DateTime.UtcNow;
 37                      log.Log("Loading all users and roles...");
 38                      var task = LoadAllUsers(guild);
 39                      task.Wait();
 40                      this.users = task.Result;
 41                      this.roles = LoadAllRoles(guild);
 42                  }
 43              }
 44          }
 45  
 46          public IGuildUser[] Users => users.Values.ToArray();
 47  
 48          public async Task GiveRole(ulong userId, ulong roleId)
 49          {
 50              Log($"Giving role {roleId} to user {userId}");
 51              var role = GetRole(roleId);
 52              var guildUser = GetUser(userId);
 53              if (role == null) return;
 54              if (guildUser == null) return;
 55  
 56              await guildUser.AddRoleAsync(role);
 57              await Program.AdminChecker.SendInAdminChannel($"Added role '{role.Name}' for user <@{userId}>.");
 58  
 59              await SendNotification(guildUser, role);
 60          }
 61  
 62          public async Task RemoveRole(ulong userId, ulong roleId)
 63          {
 64              Log($"Removing role {roleId} from user {userId}");
 65              var role = GetRole(roleId);
 66              var guildUser = GetUser(userId);
 67              if (role == null) return;
 68              if (guildUser == null) return;
 69  
 70              await guildUser.RemoveRoleAsync(role);
 71              await Program.AdminChecker.SendInAdminChannel($"Removed role '{role.Name}' for user <@{userId}>.");
 72          }
 73  
 74          private SocketRole? GetRole(ulong roleId)
 75          {
 76              if (roles.ContainsKey(roleId)) return roles[roleId];
 77              return null;
 78          }
 79  
 80          private IGuildUser? GetUser(ulong userId)
 81          {
 82              if (users.ContainsKey(userId)) return users[userId];
 83              return null;
 84          }
 85  
 86          private void Log(string msg)
 87          {
 88              log.Log(msg);
 89          }
 90  
 91          private async Task<Dictionary<ulong, IGuildUser>> LoadAllUsers(SocketGuild guild)
 92          {
 93              var result = new Dictionary<ulong, IGuildUser>();
 94              var users = guild.GetUsersAsync();
 95              await foreach (var ulist in users)
 96              {
 97                  foreach (var u in ulist)
 98                  {
 99                      result.Add(u.Id, u);
100                  }
101              }
102              return result;
103          }
104  
105          private Dictionary<ulong, SocketRole> LoadAllRoles(SocketGuild guild)
106          {
107              var result = new Dictionary<ulong, SocketRole>();
108              var roles = guild.Roles.ToArray();
109              foreach (var role in roles)
110              {
111                  result.Add(role.Id, role);
112              }
113              return result;
114          }
115  
116          private async Task SendNotification(IGuildUser user, SocketRole role)
117          {
118              try
119              {
120                  var userData = userRepo.GetUser(user);
121                  if (userData == null) return;
122  
123                  if (userData.NotificationsEnabled && rewardsChannel != null)
124                  {
125                      var msg = $"<@{user.Id}> has received '{role.Name}'.";
126                      await rewardsChannel.SendMessageAsync(msg);
127                  }
128              }
129              catch (Exception ex)
130              {
131                  log.Error($"Failed to notify user '{user.DisplayName}' about role '{role.Name}': {ex}");
132              }
133          }
134      }
135  }