setting up all the commands

This commit is contained in:
benbierens 2023-10-22 10:10:52 +02:00
parent 8ad2dee67c
commit 4aa4731480
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
12 changed files with 222 additions and 16 deletions

View File

@ -13,5 +13,10 @@
} }
public string Address { get; } public string Address { get; }
public override string ToString()
{
return Address;
}
} }
} }

View File

@ -1,5 +1,6 @@
using Discord.WebSocket; using Discord.WebSocket;
using Discord; using Discord;
using BiblioTech.TokenCommands;
namespace BiblioTech namespace BiblioTech
{ {
@ -33,19 +34,33 @@ namespace BiblioTech
} }
protected abstract Task Invoke(SocketSlashCommand command); protected abstract Task Invoke(SocketSlashCommand command);
protected bool IsSenderAdmin(SocketSlashCommand command)
{
}
protected ulong GetUserId(UserOption userOption, SocketSlashCommand command)
{
var targetUser = userOption.GetOptionUserId(command);
if (IsSenderAdmin(command) && targetUser != null) return targetUser.Value;
return command.User.Id;
}
} }
public class CommandOption public class CommandOption
{ {
public CommandOption(string name, string description, ApplicationCommandOptionType type) public CommandOption(string name, string description, ApplicationCommandOptionType type, bool isRequired)
{ {
Name = name; Name = name;
Description = description; Description = description;
Type = type; Type = type;
IsRequired = isRequired;
} }
public string Name { get; } public string Name { get; }
public string Description { get; } public string Description { get; }
public ApplicationCommandOptionType Type { get; } public ApplicationCommandOptionType Type { get; }
public bool IsRequired { get; }
} }
} }

View File

@ -31,7 +31,7 @@ namespace BiblioTech
foreach (var option in c.Options) foreach (var option in c.Options)
{ {
builder.AddOption(option.Name, option.Type, option.Description, isRequired: true); builder.AddOption(option.Name, option.Type, option.Description, isRequired: option.IsRequired);
} }
return builder; return builder;

View File

@ -0,0 +1,34 @@
using Discord.WebSocket;
namespace BiblioTech.TokenCommands
{
public class ClearUserAssociationCommand : BaseCommand
{
private readonly UserOption user = new UserOption(
description: "User to clear Eth address for.",
isRequired: true);
public override string Name => "clear";
public override string StartingMessage => "Hold on...";
public override string Description => "Admin only. Clears current Eth address for a user, allowing them to set a new one.";
protected override async Task Invoke(SocketSlashCommand command)
{
if (!IsSenderAdmin(command))
{
await command.FollowupAsync("You're not an admin.");
return;
}
var userId = user.GetOptionUserId(command);
if (userId == null)
{
await command.FollowupAsync("Failed to get user ID");
return;
}
Program.UserRepo.ClearUserAssociatedAddress(userId.Value);
await command.FollowupAsync("Done."); ;
}
}
}

View File

@ -8,7 +8,8 @@ namespace BiblioTech.TokenCommands
public EthAddressOption() public EthAddressOption()
: base(name: "ethaddress", : base(name: "ethaddress",
description: "Ethereum address starting with '0x'.", description: "Ethereum address starting with '0x'.",
type: Discord.ApplicationCommandOptionType.String) type: Discord.ApplicationCommandOptionType.String,
isRequired: true)
{ {
} }

View File

@ -1,5 +1,4 @@
using CodexContractsPlugin; using CodexContractsPlugin;
using CodexPlugin;
using Core; using Core;
using Discord.WebSocket; using Discord.WebSocket;
using GethPlugin; using GethPlugin;
@ -8,29 +7,36 @@ namespace BiblioTech.TokenCommands
{ {
public class GetBalanceCommand : BaseNetCommand public class GetBalanceCommand : BaseNetCommand
{ {
private readonly EthAddressOption ethOption = new EthAddressOption(); private readonly UserAssociateCommand userAssociateCommand;
private readonly UserOption optionalUser = new UserOption(
description: "If set, get balance for another user. (Optional, admin-only)",
isRequired: false);
public GetBalanceCommand(DeploymentsFilesMonitor monitor, CoreInterface ci) public GetBalanceCommand(DeploymentsFilesMonitor monitor, CoreInterface ci, UserAssociateCommand userAssociateCommand)
: base(monitor, ci) : base(monitor, ci)
{ {
this.userAssociateCommand = userAssociateCommand;
} }
// connect users to eth address!
public override string Name => "balance"; public override string Name => "balance";
public override string StartingMessage => "Fetching balance..."; public override string StartingMessage => "Fetching balance...";
public override string Description => "Shows Eth and TestToken balance of an eth address."; public override string Description => "Shows Eth and TestToken balance of an eth address.";
public override CommandOption[] Options => new[] { ethOption }; public override CommandOption[] Options => new[] { optionalUser };
protected override async Task Execute(SocketSlashCommand command, IGethNode gethNode, ICodexContracts contracts) protected override async Task Execute(SocketSlashCommand command, IGethNode gethNode, ICodexContracts contracts)
{ {
var addr = await ethOption.Parse(command); var userId = GetUserId(optionalUser, command);
if (addr == null) return; var addr = Program.UserRepo.GetCurrentAddressForUser(userId);
if (addr == null)
{
await command.FollowupAsync($"No address has been set for this user. Please use '/{userAssociateCommand.Name}' to set it first.");
return;
}
var eth = gethNode.GetEthBalance(addr); var eth = gethNode.GetEthBalance(addr);
var testTokens = contracts.GetTestTokenBalance(gethNode, addr); var testTokens = contracts.GetTestTokenBalance(gethNode, addr);
await command.RespondAsync($"Address '{addr.Address}' has {eth} and {testTokens}."); await command.FollowupAsync($"{command.User.Username} has {eth} and {testTokens}.");
} }
} }
} }

View File

@ -10,7 +10,9 @@ namespace BiblioTech.TokenCommands
private readonly string nl = Environment.NewLine; private readonly string nl = Environment.NewLine;
private readonly Ether defaultEthToSend = 10.Eth(); private readonly Ether defaultEthToSend = 10.Eth();
private readonly TestToken defaultTestTokensToMint = 1024.TestTokens(); private readonly TestToken defaultTestTokensToMint = 1024.TestTokens();
private readonly EthAddressOption ethOption = new EthAddressOption(); private readonly UserOption optionalUser = new UserOption(
description: "If set, mint tokens for this user. (Optional, admin-only)",
isRequired: true);
public MintCommand(DeploymentsFilesMonitor monitor, CoreInterface ci) public MintCommand(DeploymentsFilesMonitor monitor, CoreInterface ci)
: base(monitor, ci) : base(monitor, ci)
@ -19,12 +21,13 @@ namespace BiblioTech.TokenCommands
public override string Name => "mint"; public override string Name => "mint";
public override string StartingMessage => "Minting some tokens..."; public override string StartingMessage => "Minting some tokens...";
public override string Description => "Mint some TestTokens and send some Eth to the address if its balance is low."; public override string Description => "Mint some TestTokens and send some Eth to the user if their balance is low.";
public override CommandOption[] Options => new[] { ethOption }; public override CommandOption[] Options => new[] { optionalUser };
protected override async Task Execute(SocketSlashCommand command, IGethNode gethNode, ICodexContracts contracts) protected override async Task Execute(SocketSlashCommand command, IGethNode gethNode, ICodexContracts contracts)
{ {
var addr = await ethOption.Parse(command); var userId = GetUserId(optionalUser, command);
var addr = Program.UserRepo.GetCurrentAddressForUser(userId);
if (addr == null) return; if (addr == null) return;
var report = var report =

View File

@ -0,0 +1,34 @@
using Discord.WebSocket;
namespace BiblioTech.TokenCommands
{
public class ReportHistoryCommand : BaseCommand
{
private readonly UserOption user = new UserOption(
description: "User to report history for.",
isRequired: true);
public override string Name => "report";
public override string StartingMessage => "Getting that data...";
public override string Description => "Admin only. Reports bot-interaction history for a user.";
protected override async Task Invoke(SocketSlashCommand command)
{
if (!IsSenderAdmin(command))
{
await command.FollowupAsync("You're not an admin.");
return;
}
var userId = user.GetOptionUserId(command);
if (userId == null)
{
await command.FollowupAsync("Failed to get user ID");
return;
}
var report = Program.UserRepo.GetInteractionReport(userId.Value);
await command.FollowupAsync(string.Join(Environment.NewLine, report));
}
}
}

View File

@ -0,0 +1,16 @@
using Discord.WebSocket;
namespace BiblioTech.TokenCommands
{
public class ShowIdCommand : BaseCommand
{
public override string Name => "my-id";
public override string StartingMessage => "...";
public override string Description => "Shows you your Discord ID. (Useful for admins)";
protected override async Task Invoke(SocketSlashCommand command)
{
await command.FollowupAsync("Your ID: " + command.User.Id);
}
}
}

View File

@ -0,0 +1,33 @@
using Discord.WebSocket;
namespace BiblioTech.TokenCommands
{
public class UserAssociateCommand : BaseCommand
{
private readonly EthAddressOption ethOption = new EthAddressOption();
public override string Name => "set";
public override string StartingMessage => "hold on...";
public override string Description => "Associates a Discord user with an Ethereum address in the TestNet. " +
"Warning: You can set your Ethereum address only once! Double-check before hitting enter.";
public override CommandOption[] Options => new[] { ethOption };
protected override async Task Invoke(SocketSlashCommand command)
{
var userId = command.User.Id;
var data = await ethOption.Parse(command);
if (data == null) return;
var currentAddress = Program.UserRepo.GetCurrentAddressForUser(userId);
if (currentAddress != null)
{
await command.FollowupAsync($"You've already set your Ethereum address to {currentAddress}.");
return;
}
Program.UserRepo.AssociateUserWithAddress(userId, data);
await command.FollowupAsync("Done! Thank you for joining the test net!");
}
}
}

View File

@ -0,0 +1,22 @@
using Discord;
using Discord.WebSocket;
namespace BiblioTech.TokenCommands
{
public class UserOption : CommandOption
{
public UserOption(string description, bool isRequired)
: base("user", description, ApplicationCommandOptionType.User, isRequired)
{
}
public ulong? GetOptionUserId(SocketSlashCommand command)
{
var userOptionData = command.Data.Options.SingleOrDefault(o => o.Name == Name);
if (userOptionData == null) return null;
var user = userOptionData.Value as IUser;
if (user == null) return null;
return user.Id;
}
}
}

View File

@ -42,6 +42,43 @@ namespace BiblioTech
} }
} }
public string[] GetInteractionReport(ulong discordId)
{
var result = new List<string>();
lock (repoLock)
{
var filename = GetFilename(discordId);
if (!File.Exists(filename))
{
result.Add("User has not joined the test net.");
}
else
{
var user = JsonConvert.DeserializeObject<User>(File.ReadAllText(filename));
if (user == null)
{
result.Add("Failed to load user records.");
}
else
{
result.Add("User joined on " + user.CreatedUtc.ToString("o"));
result.Add("Current address: " + user.CurrentAddress);
foreach (var ae in user.AssociateEvents)
{
result.Add($"{ae.Utc.ToString("o")} - Address set to: {ae.NewAddress}");
}
foreach (var me in user.MintEvents)
{
result.Add($"{me.Utc.ToString("o")} - Minted {me.EthReceived} and {me.TestTokensMinted} to {me.UsedAddress}.");
}
}
}
}
return result.ToArray();
}
private void SetUserAddress(ulong discordId, EthAddress? address) private void SetUserAddress(ulong discordId, EthAddress? address)
{ {
var user = GetOrCreate(discordId); var user = GetOrCreate(discordId);