/ Tools / BiblioTech / Commands / UserAssociateCommand.cs
UserAssociateCommand.cs
 1  using BiblioTech.Options;
 2  using Discord;
 3  using Utils;
 4  
 5  namespace BiblioTech.Commands
 6  {
 7      public class UserAssociateCommand : BaseCommand
 8      {
 9          public UserAssociateCommand(NotifyCommand notifyCommand)
10          {
11              this.notifyCommand = notifyCommand;
12          }
13          
14          private readonly NotifyCommand notifyCommand;
15          private readonly EthAddressOption ethOption = new EthAddressOption(isRequired: false);
16          private readonly UserOption optionalUser = new UserOption(
17              description: "If set, associates Ethereum address for another user. (Optional, admin-only)",
18              isRequired: false);
19  
20          public override string Name => "set";
21          public override string StartingMessage => RandomBusyMessage.Get();
22          public override string Description => "Associates a Discord user with an Ethereum address.";
23          public override CommandOption[] Options => new CommandOption[] { ethOption, optionalUser };
24  
25          protected override async Task Invoke(CommandContext context)
26          {
27              var user = GetUserFromCommand(optionalUser, context);
28              var newAddress = await ethOption.Parse(context);
29              if (newAddress == null) return;
30  
31              var currentAddress = Program.UserRepo.GetCurrentAddressForUser(user);
32              if (currentAddress != null && !IsSenderAdmin(context.Command))
33              {
34                  await context.Followup($"You've already set your Ethereum address to {currentAddress}.");
35                  await Program.AdminChecker.SendInAdminChannel($"User {Mention(user)} used '/{Name}' but already has an address set. ({currentAddress})");
36                  return;
37              }
38  
39              var result = Program.UserRepo.AssociateUserWithAddress(user, newAddress);
40              switch (result)
41              {
42                  case SetAddressResponse.OK:
43                      await ResponseOK(context, user, newAddress);
44                      break;
45                  case SetAddressResponse.AddressAlreadyInUse:
46                      await ResponseAlreadyUsed(context, user, newAddress);
47                      break;
48                  case SetAddressResponse.CreateUserFailed:
49                      await ResponseCreateUserFailed(context, user);
50                      break;
51                  default:
52                      throw new Exception("Unknown SetAddressResponse mode");
53              }
54          }
55  
56          private async Task ResponseCreateUserFailed(CommandContext context, IUser user)
57          {
58              await context.Followup("Internal error. Error details sent to admin.");
59              await Program.AdminChecker.SendInAdminChannel($"User {Mention(user)} used '/{Name}' but failed to create new user.");
60          }
61  
62          private async Task ResponseAlreadyUsed(CommandContext context, IUser user, EthAddress newAddress)
63          {
64              await context.Followup("This address is already in use by another user.");
65              await Program.AdminChecker.SendInAdminChannel($"User {Mention(user)} used '/{Name}' but the provided address is already in use by another user. (address: {newAddress})");
66          }
67  
68          private async Task ResponseOK(CommandContext context, IUser user, EthAddress newAddress)
69          {
70              await context.Followup(new string[]
71              {
72                      "Done! Thank you for joining!",
73                      "By default, the bot will @-mention you with discord role notifications.",
74                      $"You can enable/disable this behavior with the '/{notifyCommand.Name}' command."
75              });
76  
77              await Program.AdminChecker.SendInAdminChannel($"User {Mention(user)} used '/{Name}' successfully. ({newAddress})");
78          }
79      }
80  }