mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
- Added a simple bank system. Users can deposit, withdraw and check the balance of their currency in the bank.
- Users can't check other user's bank balances. - Added a button on a .$ command which, when clicked, sends you a message with your bank balance that only you can see. - Updated pagination, it now uses buttons instead of reactions - using .h <command group> (atm only .bank is a proper group) will list commands with their descriptions in that group
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o
|
||||||
@@ -13,6 +14,13 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
|
|||||||
- Old embed format will still work
|
- Old embed format will still work
|
||||||
- There shouldn't be any breaking changes
|
- There shouldn't be any breaking changes
|
||||||
- Added `.stondel` command which, when toggled, will make the bot delete online stream messages on the server when the stream goes offline
|
- Added `.stondel` command which, when toggled, will make the bot delete online stream messages on the server when the stream goes offline
|
||||||
|
- Added a simple bank system.
|
||||||
|
- Users can deposit, withdraw and check the balance of their currency in the bank.
|
||||||
|
- Users can't check other user's bank balances.
|
||||||
|
- Added a button on a .$ command which, when clicked, sends you a message with your bank balance that only you can see.
|
||||||
|
- Added `.h <command group>`
|
||||||
|
- Using this command will list all commands in the specified group
|
||||||
|
- Atm only .bank is a proper group (`.h bank`)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@@ -5,6 +5,20 @@ namespace NadekoBot;
|
|||||||
|
|
||||||
public static class MedusaExtensions
|
public static class MedusaExtensions
|
||||||
{
|
{
|
||||||
|
// public static Task<IUserMessage> EmbedAsync(this IMessageChannel ch,
|
||||||
|
// IEmbedBuilder embed,
|
||||||
|
// string msg = "",
|
||||||
|
// MessageComponent? components = null)
|
||||||
|
// {
|
||||||
|
// return ch.SendMessageAsync(msg,
|
||||||
|
// embed: embed.Build(),
|
||||||
|
// components: components,
|
||||||
|
// options: new()
|
||||||
|
// {
|
||||||
|
// RetryMode = RetryMode.AlwaysRetry
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
public static Task<IUserMessage> EmbedAsync(this IMessageChannel ch,
|
public static Task<IUserMessage> EmbedAsync(this IMessageChannel ch,
|
||||||
IEmbedBuilder embed,
|
IEmbedBuilder embed,
|
||||||
string msg = "",
|
string msg = "",
|
||||||
@@ -37,7 +51,7 @@ public static class MedusaExtensions
|
|||||||
public static Task<IUserMessage> SendErrorAsync(this AnyContext ctx, string msg)
|
public static Task<IUserMessage> SendErrorAsync(this AnyContext ctx, string msg)
|
||||||
=> ctx.Channel.SendErrorAsync(ctx, msg);
|
=> ctx.Channel.SendErrorAsync(ctx, msg);
|
||||||
|
|
||||||
// localized
|
// reaction responses
|
||||||
public static Task ConfirmAsync(this AnyContext ctx)
|
public static Task ConfirmAsync(this AnyContext ctx)
|
||||||
=> ctx.Message.AddReactionAsync(new Emoji("✅"));
|
=> ctx.Message.AddReactionAsync(new Emoji("✅"));
|
||||||
|
|
||||||
@@ -50,6 +64,7 @@ public static class MedusaExtensions
|
|||||||
public static Task WaitAsync(this AnyContext ctx)
|
public static Task WaitAsync(this AnyContext ctx)
|
||||||
=> ctx.Message.AddReactionAsync(new Emoji("🤔"));
|
=> ctx.Message.AddReactionAsync(new Emoji("🤔"));
|
||||||
|
|
||||||
|
// localized
|
||||||
public static Task<IUserMessage> ErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
public static Task<IUserMessage> ErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||||
=> ctx.SendErrorAsync(ctx.GetText(key));
|
=> ctx.SendErrorAsync(ctx.GetText(key));
|
||||||
|
|
||||||
|
80
src/NadekoBot/Common/NadekoInteractionBase.cs
Normal file
80
src/NadekoBot/Common/NadekoInteractionBase.cs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
namespace NadekoBot;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class NadekoInteraction
|
||||||
|
{
|
||||||
|
// improvements:
|
||||||
|
// - state in OnAction
|
||||||
|
// - configurable delay
|
||||||
|
// -
|
||||||
|
public abstract string Name { get; }
|
||||||
|
public abstract IEmote Emote { get; }
|
||||||
|
public Func<SocketMessageComponent, Task> OnAction { get; }
|
||||||
|
|
||||||
|
protected readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
|
protected readonly TaskCompletionSource<bool> _interactionCompletedSource;
|
||||||
|
|
||||||
|
protected ulong _authorId;
|
||||||
|
protected IUserMessage message;
|
||||||
|
|
||||||
|
protected NadekoInteraction(DiscordSocketClient client, ulong authorId, Func<SocketMessageComponent, Task> onAction)
|
||||||
|
{
|
||||||
|
_client = client;
|
||||||
|
_authorId = authorId;
|
||||||
|
OnAction = onAction;
|
||||||
|
_interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunAsync(IUserMessage msg)
|
||||||
|
{
|
||||||
|
message = msg;
|
||||||
|
|
||||||
|
_client.InteractionCreated += OnInteraction;
|
||||||
|
await Task.WhenAny(Task.Delay(10_000), _interactionCompletedSource.Task);
|
||||||
|
_client.InteractionCreated -= OnInteraction;
|
||||||
|
|
||||||
|
await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnInteraction(SocketInteraction arg)
|
||||||
|
{
|
||||||
|
if (arg is not SocketMessageComponent smc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (smc.Message.Id != message.Id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (smc.Data.CustomId != Name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (smc.User.Id != _authorId)
|
||||||
|
{
|
||||||
|
await arg.DeferAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await OnAction(smc);
|
||||||
|
|
||||||
|
// this should only be a thing on single-response buttons
|
||||||
|
_interactionCompletedSource.TrySetResult(true);
|
||||||
|
|
||||||
|
if (!smc.HasResponded)
|
||||||
|
{
|
||||||
|
await smc.DeferAsync();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public MessageComponent CreateComponent()
|
||||||
|
{
|
||||||
|
var comp = new ComponentBuilder()
|
||||||
|
.WithButton(new ButtonBuilder(style: ButtonStyle.Secondary, emote: Emote, customId: Name));
|
||||||
|
|
||||||
|
return comp.Build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -1,5 +1,6 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using MessageType = NadekoBot.Extensions.MessageType;
|
||||||
|
|
||||||
// ReSharper disable InconsistentNaming
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
@@ -29,20 +30,15 @@ public abstract class NadekoModule : ModuleBase
|
|||||||
|
|
||||||
protected string GetText(in LocStr data)
|
protected string GetText(in LocStr data)
|
||||||
=> Strings.GetText(data, Culture);
|
=> Strings.GetText(data, Culture);
|
||||||
|
|
||||||
public Task<IUserMessage> SendErrorAsync(string error)
|
|
||||||
=> ctx.Channel.SendErrorAsync(_eb, error);
|
|
||||||
|
|
||||||
public Task<IUserMessage> SendErrorAsync(
|
public Task<IUserMessage> SendErrorAsync(
|
||||||
string title,
|
string title,
|
||||||
string error,
|
string error,
|
||||||
string url = null,
|
string url = null,
|
||||||
string footer = null)
|
string footer = null,
|
||||||
|
NadekoInteraction inter = null)
|
||||||
=> ctx.Channel.SendErrorAsync(_eb, title, error, url, footer);
|
=> ctx.Channel.SendErrorAsync(_eb, title, error, url, footer);
|
||||||
|
|
||||||
public Task<IUserMessage> SendConfirmAsync(string text)
|
|
||||||
=> ctx.Channel.SendConfirmAsync(_eb, text);
|
|
||||||
|
|
||||||
public Task<IUserMessage> SendConfirmAsync(
|
public Task<IUserMessage> SendConfirmAsync(
|
||||||
string title,
|
string title,
|
||||||
string text,
|
string text,
|
||||||
@@ -50,25 +46,33 @@ public abstract class NadekoModule : ModuleBase
|
|||||||
string footer = null)
|
string footer = null)
|
||||||
=> ctx.Channel.SendConfirmAsync(_eb, title, text, url, footer);
|
=> ctx.Channel.SendConfirmAsync(_eb, title, text, url, footer);
|
||||||
|
|
||||||
public Task<IUserMessage> SendPendingAsync(string text)
|
//
|
||||||
=> ctx.Channel.SendPendingAsync(_eb, text);
|
public Task<IUserMessage> SendErrorAsync(string text, NadekoInteraction inter = null)
|
||||||
|
=> ctx.Channel.SendAsync(_eb, text, MessageType.Error, inter);
|
||||||
|
public Task<IUserMessage> SendConfirmAsync(string text, NadekoInteraction inter = null)
|
||||||
|
=> ctx.Channel.SendAsync(_eb, text, MessageType.Ok, inter);
|
||||||
|
public Task<IUserMessage> SendPendingAsync(string text, NadekoInteraction inter = null)
|
||||||
|
=> ctx.Channel.SendAsync(_eb, text, MessageType.Pending, inter);
|
||||||
|
|
||||||
public Task<IUserMessage> ErrorLocalizedAsync(LocStr str)
|
|
||||||
=> SendErrorAsync(GetText(str));
|
// localized normal
|
||||||
|
public Task<IUserMessage> ErrorLocalizedAsync(LocStr str, NadekoInteraction inter = null)
|
||||||
|
=> SendErrorAsync(GetText(str), inter);
|
||||||
|
|
||||||
public Task<IUserMessage> PendingLocalizedAsync(LocStr str)
|
public Task<IUserMessage> PendingLocalizedAsync(LocStr str, NadekoInteraction inter = null)
|
||||||
=> SendPendingAsync(GetText(str));
|
=> SendPendingAsync(GetText(str), inter);
|
||||||
|
|
||||||
public Task<IUserMessage> ConfirmLocalizedAsync(LocStr str)
|
public Task<IUserMessage> ConfirmLocalizedAsync(LocStr str, NadekoInteraction inter = null)
|
||||||
=> SendConfirmAsync(GetText(str));
|
=> SendConfirmAsync(GetText(str), inter);
|
||||||
|
|
||||||
public Task<IUserMessage> ReplyErrorLocalizedAsync(LocStr str)
|
// localized replies
|
||||||
|
public Task<IUserMessage> ReplyErrorLocalizedAsync(LocStr str, NadekoInteraction inter = null)
|
||||||
=> SendErrorAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}");
|
=> SendErrorAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}");
|
||||||
|
|
||||||
public Task<IUserMessage> ReplyPendingLocalizedAsync(LocStr str)
|
public Task<IUserMessage> ReplyPendingLocalizedAsync(LocStr str, NadekoInteraction inter = null)
|
||||||
=> SendPendingAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}");
|
=> SendPendingAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}");
|
||||||
|
|
||||||
public Task<IUserMessage> ReplyConfirmLocalizedAsync(LocStr str)
|
public Task<IUserMessage> ReplyConfirmLocalizedAsync(LocStr str, NadekoInteraction inter = null)
|
||||||
=> SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}");
|
=> SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {GetText(str)}");
|
||||||
|
|
||||||
public async Task<bool> PromptUserConfirmAsync(IEmbedBuilder embed)
|
public async Task<bool> PromptUserConfirmAsync(IEmbedBuilder embed)
|
||||||
|
9
src/NadekoBot/Db/Models/BankUser.cs
Normal file
9
src/NadekoBot/Db/Models/BankUser.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
|
namespace NadekoBot.Db.Models;
|
||||||
|
|
||||||
|
public class BankUser : DbEntity
|
||||||
|
{
|
||||||
|
public ulong UserId { get; set; }
|
||||||
|
public long Balance { get; set; }
|
||||||
|
}
|
@@ -51,6 +51,8 @@ public abstract class NadekoContext : DbContext
|
|||||||
public DbSet<AutoTranslateUser> AutoTranslateUsers { get; set; }
|
public DbSet<AutoTranslateUser> AutoTranslateUsers { get; set; }
|
||||||
|
|
||||||
public DbSet<Permissionv2> Permissions { get; set; }
|
public DbSet<Permissionv2> Permissions { get; set; }
|
||||||
|
|
||||||
|
public DbSet<BankUser> BankUsers { get; set; }
|
||||||
|
|
||||||
#region Mandatory Provider-Specific Values
|
#region Mandatory Provider-Specific Values
|
||||||
|
|
||||||
@@ -402,6 +404,12 @@ public abstract class NadekoContext : DbContext
|
|||||||
x.ChannelId,
|
x.ChannelId,
|
||||||
x.UserId
|
x.UserId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
#region BANK
|
||||||
|
|
||||||
|
modelBuilder.Entity<BankUser>(bu => bu.HasIndex(x => x.UserId).IsUnique());
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
3458
src/NadekoBot/Migrations/MySql/20220429044757_bank.Designer.cs
generated
Normal file
3458
src/NadekoBot/Migrations/MySql/20220429044757_bank.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
42
src/NadekoBot/Migrations/MySql/20220429044757_bank.cs
Normal file
42
src/NadekoBot/Migrations/MySql/20220429044757_bank.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations.Mysql
|
||||||
|
{
|
||||||
|
public partial class bank : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "bankusers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
userid = table.Column<ulong>(type: "bigint unsigned", nullable: false),
|
||||||
|
balance = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
dateadded = table.Column<DateTime>(type: "datetime(6)", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_bankusers", x => x.id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_bankusers_userid",
|
||||||
|
table: "bankusers",
|
||||||
|
column: "userid",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "bankusers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -19,6 +19,35 @@ namespace NadekoBot.Migrations.Mysql
|
|||||||
.HasAnnotation("ProductVersion", "6.0.3")
|
.HasAnnotation("ProductVersion", "6.0.3")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<long>("Balance")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("balance");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("datetime(6)")
|
||||||
|
.HasColumnName("dateadded");
|
||||||
|
|
||||||
|
b.Property<ulong>("UserId")
|
||||||
|
.HasColumnType("bigint unsigned")
|
||||||
|
.HasColumnName("userid");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_bankusers");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_bankusers_userid");
|
||||||
|
|
||||||
|
b.ToTable("bankusers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ClubId")
|
b.Property<int>("ClubId")
|
||||||
|
3600
src/NadekoBot/Migrations/Postgresql/20220429044808_bank.Designer.cs
generated
Normal file
3600
src/NadekoBot/Migrations/Postgresql/20220429044808_bank.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
41
src/NadekoBot/Migrations/Postgresql/20220429044808_bank.cs
Normal file
41
src/NadekoBot/Migrations/Postgresql/20220429044808_bank.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations.PostgreSql
|
||||||
|
{
|
||||||
|
public partial class bank : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "bankusers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
userid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||||
|
balance = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
dateadded = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_bankusers", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_bankusers_userid",
|
||||||
|
table: "bankusers",
|
||||||
|
column: "userid",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "bankusers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -22,6 +22,37 @@ namespace NadekoBot.Migrations.PostgreSql
|
|||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<long>("Balance")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("balance");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("dateadded");
|
||||||
|
|
||||||
|
b.Property<decimal>("UserId")
|
||||||
|
.HasColumnType("numeric(20,0)")
|
||||||
|
.HasColumnName("userid");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_bankusers");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasDatabaseName("ix_bankusers_userid");
|
||||||
|
|
||||||
|
b.ToTable("bankusers", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ClubId")
|
b.Property<int>("ClubId")
|
||||||
|
2782
src/NadekoBot/Migrations/Sqlite/20220428051304_bank.Designer.cs
generated
Normal file
2782
src/NadekoBot/Migrations/Sqlite/20220428051304_bank.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
src/NadekoBot/Migrations/Sqlite/20220428051304_bank.cs
Normal file
40
src/NadekoBot/Migrations/Sqlite/20220428051304_bank.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class bank : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "BankUsers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||||
|
Balance = table.Column<long>(type: "INTEGER", nullable: false),
|
||||||
|
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_BankUsers", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_BankUsers_UserId",
|
||||||
|
table: "BankUsers",
|
||||||
|
column: "UserId",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "BankUsers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,6 +17,29 @@ namespace NadekoBot.Migrations
|
|||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "6.0.3");
|
modelBuilder.HasAnnotation("ProductVersion", "6.0.3");
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Db.Models.BankUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Balance")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<ulong>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("BankUsers");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ClubId")
|
b.Property<int>("ClubId")
|
||||||
|
61
src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs
Normal file
61
src/NadekoBot/Modules/Gambling/Bank/BankCommands.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using NadekoBot.Modules.Gambling.Bank;
|
||||||
|
using NadekoBot.Modules.Gambling.Common;
|
||||||
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Gambling;
|
||||||
|
|
||||||
|
// todo .h [group] should show commands in that group
|
||||||
|
public partial class Gambling
|
||||||
|
{
|
||||||
|
[Name("Bank")]
|
||||||
|
[Group("bank")]
|
||||||
|
public partial class BankCommands : GamblingModule<IBankService>
|
||||||
|
{
|
||||||
|
private readonly IBankService _bank;
|
||||||
|
|
||||||
|
public BankCommands(GamblingConfigService gcs, IBankService bank) : base(gcs)
|
||||||
|
{
|
||||||
|
_bank = bank;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
public async partial Task BankDeposit(ShmartNumber amount)
|
||||||
|
{
|
||||||
|
if (amount <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (await _bank.DepositAsync(ctx.User.Id, amount))
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalizedAsync(strs.bank_deposited(N(amount)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalizedAsync(strs.not_enough(CurrencySign));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
public async partial Task BankWithdraw(ShmartNumber amount)
|
||||||
|
{
|
||||||
|
if (amount <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (await _bank.WithdrawAsync(ctx.User.Id, amount))
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalizedAsync(strs.bank_withdrew(N(amount)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalizedAsync(strs.bank_withdraw_insuff(CurrencySign));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cmd]
|
||||||
|
public async partial Task BankBalance()
|
||||||
|
{
|
||||||
|
var bal = await _bank.GetBalanceAsync(ctx.User.Id);
|
||||||
|
|
||||||
|
await ReplyConfirmLocalizedAsync(strs.bank_balance(N(bal)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
src/NadekoBot/Modules/Gambling/Bank/BankService.cs
Normal file
77
src/NadekoBot/Modules/Gambling/Bank/BankService.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using LinqToDB;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Gambling.Bank;
|
||||||
|
|
||||||
|
public sealed class BankService : IBankService, INService
|
||||||
|
{
|
||||||
|
private readonly ICurrencyService _cur;
|
||||||
|
private readonly DbService _db;
|
||||||
|
|
||||||
|
public BankService(ICurrencyService cur, DbService db)
|
||||||
|
{
|
||||||
|
_cur = cur;
|
||||||
|
_db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> DepositAsync(ulong userId, long amount)
|
||||||
|
{
|
||||||
|
if (amount <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(amount));
|
||||||
|
|
||||||
|
if (!await _cur.RemoveAsync(userId, amount, new("bank", "deposit")))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
await ctx.BankUsers
|
||||||
|
.ToLinqToDBTable()
|
||||||
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
UserId = userId,
|
||||||
|
Balance = amount
|
||||||
|
},
|
||||||
|
(old) => new()
|
||||||
|
{
|
||||||
|
Balance = old.Balance + amount
|
||||||
|
},
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
UserId = userId
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> WithdrawAsync(ulong userId, long amount)
|
||||||
|
{
|
||||||
|
if (amount <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(amount));
|
||||||
|
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
var rows = await ctx.BankUsers
|
||||||
|
.ToLinqToDBTable()
|
||||||
|
.Where(x => x.UserId == userId && x.Balance >= amount)
|
||||||
|
.UpdateAsync((old) => new()
|
||||||
|
{
|
||||||
|
Balance = old.Balance - amount
|
||||||
|
});
|
||||||
|
|
||||||
|
if (rows > 0)
|
||||||
|
{
|
||||||
|
await _cur.AddAsync(userId, amount, new("bank", "withdraw"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<long> GetBalanceAsync(ulong userId)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
return (await ctx.BankUsers
|
||||||
|
.ToLinqToDBTable()
|
||||||
|
.FirstOrDefaultAsync(x => x.UserId == userId))
|
||||||
|
?.Balance
|
||||||
|
?? 0;
|
||||||
|
}
|
||||||
|
}
|
8
src/NadekoBot/Modules/Gambling/Bank/IBankService.cs
Normal file
8
src/NadekoBot/Modules/Gambling/Bank/IBankService.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace NadekoBot.Modules.Gambling.Bank;
|
||||||
|
|
||||||
|
public interface IBankService
|
||||||
|
{
|
||||||
|
Task<bool> DepositAsync(ulong userId, long amount);
|
||||||
|
Task<bool> WithdrawAsync(ulong userId, long amount);
|
||||||
|
Task<long> GetBalanceAsync(ulong userId);
|
||||||
|
}
|
@@ -3,6 +3,7 @@ using LinqToDB;
|
|||||||
using LinqToDB.EntityFrameworkCore;
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using NadekoBot.Db;
|
using NadekoBot.Db;
|
||||||
using NadekoBot.Db.Models;
|
using NadekoBot.Db.Models;
|
||||||
|
using NadekoBot.Modules.Gambling.Bank;
|
||||||
using NadekoBot.Modules.Gambling.Common;
|
using NadekoBot.Modules.Gambling.Common;
|
||||||
using NadekoBot.Modules.Gambling.Services;
|
using NadekoBot.Modules.Gambling.Services;
|
||||||
using NadekoBot.Services.Currency;
|
using NadekoBot.Services.Currency;
|
||||||
@@ -40,6 +41,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
private readonly NumberFormatInfo _enUsCulture;
|
private readonly NumberFormatInfo _enUsCulture;
|
||||||
private readonly DownloadTracker _tracker;
|
private readonly DownloadTracker _tracker;
|
||||||
private readonly GamblingConfigService _configService;
|
private readonly GamblingConfigService _configService;
|
||||||
|
private readonly IBankService _bank;
|
||||||
|
|
||||||
private IUserMessage rdMsg;
|
private IUserMessage rdMsg;
|
||||||
|
|
||||||
@@ -49,13 +51,16 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
IDataCache cache,
|
IDataCache cache,
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
DownloadTracker tracker,
|
DownloadTracker tracker,
|
||||||
GamblingConfigService configService)
|
GamblingConfigService configService,
|
||||||
|
IBankService bank)
|
||||||
: base(configService)
|
: base(configService)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_cs = currency;
|
_cs = currency;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_client = client;
|
_client = client;
|
||||||
|
_bank = bank;
|
||||||
|
|
||||||
_enUsCulture = new CultureInfo("en-US", false).NumberFormat;
|
_enUsCulture = new CultureInfo("en-US", false).NumberFormat;
|
||||||
_enUsCulture.NumberDecimalDigits = 0;
|
_enUsCulture.NumberDecimalDigits = 0;
|
||||||
_enUsCulture.NumberGroupSeparator = " ";
|
_enUsCulture.NumberGroupSeparator = " ";
|
||||||
@@ -312,6 +317,31 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
_ => $"{type.Titleize()} - {subType.Titleize()}"
|
_ => $"{type.Titleize()} - {subType.Titleize()}"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public sealed class CashInteraction : NadekoInteraction
|
||||||
|
{
|
||||||
|
public override string Name
|
||||||
|
=> "CASH_OPEN_BANK";
|
||||||
|
|
||||||
|
public override IEmote Emote
|
||||||
|
=> new Emoji("🏦");
|
||||||
|
|
||||||
|
public CashInteraction(
|
||||||
|
[NotNull] DiscordSocketClient client,
|
||||||
|
ulong authorId,
|
||||||
|
Func<SocketMessageComponent, Task> onAction)
|
||||||
|
: base(client, authorId, onAction)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CashInteraction Create(
|
||||||
|
DiscordSocketClient client,
|
||||||
|
ulong userId,
|
||||||
|
Func<SocketMessageComponent, Task> onAction)
|
||||||
|
=> new(client, userId, onAction);
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async partial Task Cash(ulong userId)
|
public async partial Task Cash(ulong userId)
|
||||||
@@ -319,14 +349,30 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
var cur = await GetBalanceStringAsync(userId);
|
var cur = await GetBalanceStringAsync(userId);
|
||||||
await ReplyConfirmLocalizedAsync(strs.has(Format.Code(userId.ToString()), cur));
|
await ReplyConfirmLocalizedAsync(strs.has(Format.Code(userId.ToString()), cur));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task BankAction(SocketMessageComponent smc)
|
||||||
|
{
|
||||||
|
var balance = await _bank.GetBalanceAsync(ctx.User.Id);
|
||||||
|
await smc.RespondAsync(GetText(strs.bank_balance(N(balance))), ephemeral: true);
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[Priority(1)]
|
[Priority(1)]
|
||||||
public async partial Task Cash([Leftover] IUser user = null)
|
public async partial Task Cash([Leftover] IUser user = null)
|
||||||
{
|
{
|
||||||
user ??= ctx.User;
|
user ??= ctx.User;
|
||||||
var cur = await GetBalanceStringAsync(user.Id);
|
var cur = await GetBalanceStringAsync(user.Id);
|
||||||
await ConfirmLocalizedAsync(strs.has(Format.Bold(user.ToString()), cur));
|
|
||||||
|
if (user == ctx.User)
|
||||||
|
{
|
||||||
|
var inter = CashInteraction.Create(_client, ctx.User.Id, BankAction);
|
||||||
|
await ConfirmLocalizedAsync(strs.has(Format.Bold(user.ToString()), cur), inter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ConfirmLocalizedAsync(strs.has(Format.Bold(user.ToString()), cur));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
@@ -266,6 +266,20 @@ public partial class Help : NadekoModule<HelpService>
|
|||||||
await ctx.Channel.EmbedAsync(embed);
|
await ctx.Channel.EmbedAsync(embed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task Group(ModuleInfo group)
|
||||||
|
{
|
||||||
|
var eb = _eb.Create(ctx)
|
||||||
|
.WithTitle(GetText(strs.cmd_group_commands(group.Name)))
|
||||||
|
.WithOkColor();
|
||||||
|
|
||||||
|
foreach (var cmd in group.Commands)
|
||||||
|
{
|
||||||
|
eb.AddField(prefix + cmd.Aliases.First(), cmd.RealSummary(_strings, _medusae, Culture, prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
await ctx.Channel.EmbedAsync(eb);
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async partial Task H([Leftover] string fail)
|
public async partial Task H([Leftover] string fail)
|
||||||
@@ -278,6 +292,20 @@ public partial class Help : NadekoModule<HelpService>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fail.StartsWith(prefix))
|
||||||
|
fail = fail.Substring(prefix.Length);
|
||||||
|
|
||||||
|
var group = _cmds.Modules
|
||||||
|
.SelectMany(x => x.Submodules)
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x.Group))
|
||||||
|
.FirstOrDefault(x => x.Group.Equals(fail, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
|
||||||
|
if (group is not null)
|
||||||
|
{
|
||||||
|
await Group(group);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await ReplyErrorLocalizedAsync(strs.command_not_found);
|
await ReplyErrorLocalizedAsync(strs.command_not_found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -121,7 +121,7 @@ public static class Extensions
|
|||||||
args = strings.GetCommandStrings(cmd.Summary, culture).Args;
|
args = strings.GetCommandStrings(cmd.Summary, culture).Args;
|
||||||
}
|
}
|
||||||
|
|
||||||
return args.Map(arg => GetFullUsage(cmd.Name, arg, prefix));
|
return args.Map(arg => GetFullUsage(cmd.Aliases.First(), arg, prefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetFullUsage(string commandName, string args, string prefix)
|
private static string GetFullUsage(string commandName, string args, string prefix)
|
||||||
|
@@ -2,53 +2,116 @@ namespace NadekoBot.Extensions;
|
|||||||
|
|
||||||
public static class MessageChannelExtensions
|
public static class MessageChannelExtensions
|
||||||
{
|
{
|
||||||
public static Task<IUserMessage> EmbedAsync(
|
// main overload that all other send methods reduce to
|
||||||
this IMessageChannel ch,
|
public static Task<IUserMessage> SendAsync(
|
||||||
IEmbedBuilder embed,
|
this IMessageChannel channel,
|
||||||
string msg = "",
|
string? plainText,
|
||||||
|
Embed? embed = null,
|
||||||
|
IReadOnlyCollection<Embed>? embeds = null,
|
||||||
|
bool sanitizeAll = false,
|
||||||
MessageComponent? components = null)
|
MessageComponent? components = null)
|
||||||
=> ch.SendMessageAsync(msg,
|
{
|
||||||
embed: embed.Build(),
|
plainText = sanitizeAll
|
||||||
|
? plainText?.SanitizeAllMentions() ?? ""
|
||||||
|
: plainText?.SanitizeMentions() ?? "";
|
||||||
|
|
||||||
|
return channel.SendMessageAsync(plainText,
|
||||||
|
embed: embed,
|
||||||
|
embeds: embeds is null
|
||||||
|
? null
|
||||||
|
: embeds as Embed[] ?? embeds.ToArray(),
|
||||||
components: components,
|
components: components,
|
||||||
options: new()
|
options: new()
|
||||||
{
|
{
|
||||||
RetryMode = RetryMode.AlwaysRetry
|
RetryMode = RetryMode.AlwaysRetry
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<IUserMessage> SendAsync(
|
||||||
|
this IMessageChannel channel,
|
||||||
|
string? plainText,
|
||||||
|
NadekoInteraction? inter,
|
||||||
|
Embed? embed = null,
|
||||||
|
IReadOnlyCollection<Embed>? embeds = null,
|
||||||
|
bool sanitizeAll = false)
|
||||||
|
{
|
||||||
|
var msg = await channel.SendAsync(plainText,
|
||||||
|
embed,
|
||||||
|
embeds,
|
||||||
|
sanitizeAll,
|
||||||
|
inter?.CreateComponent());
|
||||||
|
|
||||||
|
if (inter is not null)
|
||||||
|
await inter.RunAsync(msg);
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
public static Task<IUserMessage> SendAsync(
|
public static Task<IUserMessage> SendAsync(
|
||||||
this IMessageChannel channel,
|
this IMessageChannel channel,
|
||||||
string? plainText,
|
SmartText text,
|
||||||
Embed? embed = null,
|
|
||||||
Embed[]? embeds = null,
|
|
||||||
bool sanitizeAll = false)
|
bool sanitizeAll = false)
|
||||||
{
|
|
||||||
plainText = sanitizeAll ? plainText?.SanitizeAllMentions() ?? "" : plainText?.SanitizeMentions() ?? "";
|
|
||||||
|
|
||||||
return channel.SendMessageAsync(plainText, embed: embed, embeds: embeds);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Task<IUserMessage> SendAsync(this IMessageChannel channel, SmartText text, bool sanitizeAll = false)
|
|
||||||
=> text switch
|
=> text switch
|
||||||
{
|
{
|
||||||
SmartEmbedText set => channel.SendAsync(set.PlainText, set.GetEmbed().Build(), sanitizeAll: sanitizeAll),
|
SmartEmbedText set => channel.SendAsync(set.PlainText,
|
||||||
SmartPlainText st => channel.SendAsync(st.Text, null, sanitizeAll: sanitizeAll),
|
set.GetEmbed().Build(),
|
||||||
|
sanitizeAll: sanitizeAll),
|
||||||
|
SmartPlainText st => channel.SendAsync(st.Text,
|
||||||
|
default(Embed),
|
||||||
|
sanitizeAll: sanitizeAll),
|
||||||
SmartEmbedTextArray arr => channel.SendAsync(arr.Content,
|
SmartEmbedTextArray arr => channel.SendAsync(arr.Content,
|
||||||
embeds: arr.GetEmbedBuilders().Map(e => e.Build())),
|
embeds: arr.GetEmbedBuilders().Map(e => e.Build())),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
_ => throw new ArgumentOutOfRangeException(nameof(text))
|
||||||
};
|
};
|
||||||
|
|
||||||
// this is a huge problem, because now i don't have
|
public static Task<IUserMessage> EmbedAsync(
|
||||||
// access to embed builder service
|
this IMessageChannel ch,
|
||||||
// as this is an extension of the message channel
|
IEmbedBuilder? embed,
|
||||||
public static Task<IUserMessage> SendErrorAsync(
|
string plainText = "",
|
||||||
|
IReadOnlyCollection<IEmbedBuilder>? embeds = null,
|
||||||
|
NadekoInteraction? inter = null)
|
||||||
|
=> ch.SendAsync(plainText,
|
||||||
|
inter,
|
||||||
|
embed: embed?.Build(),
|
||||||
|
embeds: embeds?.Map(x => x.Build()));
|
||||||
|
|
||||||
|
public static Task<IUserMessage> SendAsync(
|
||||||
this IMessageChannel ch,
|
this IMessageChannel ch,
|
||||||
IEmbedBuilderService eb,
|
IEmbedBuilderService eb,
|
||||||
|
string text,
|
||||||
|
MessageType type,
|
||||||
|
NadekoInteraction? inter = null)
|
||||||
|
{
|
||||||
|
var builder = eb.Create().WithDescription(text);
|
||||||
|
|
||||||
|
builder = (type switch
|
||||||
|
{
|
||||||
|
MessageType.Error => builder.WithErrorColor(),
|
||||||
|
MessageType.Ok => builder.WithOkColor(),
|
||||||
|
MessageType.Pending => builder.WithPendingColor(),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||||
|
});
|
||||||
|
|
||||||
|
return ch.EmbedAsync(builder, inter: inter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// regular send overloads
|
||||||
|
public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, IEmbedBuilderService eb, string text)
|
||||||
|
=> ch.SendAsync(eb, text, MessageType.Error);
|
||||||
|
|
||||||
|
public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, IEmbedBuilderService eb, string text)
|
||||||
|
=> ch.SendAsync(eb, text, MessageType.Ok);
|
||||||
|
|
||||||
|
public static Task<IUserMessage> SendAsync(
|
||||||
|
this IMessageChannel ch,
|
||||||
|
IEmbedBuilderService eb,
|
||||||
|
MessageType type,
|
||||||
string title,
|
string title,
|
||||||
string error,
|
string text,
|
||||||
string? url = null,
|
string? url = null,
|
||||||
string? footer = null)
|
string? footer = null)
|
||||||
{
|
{
|
||||||
var embed = eb.Create().WithErrorColor().WithDescription(error).WithTitle(title);
|
var embed = eb.Create().WithDescription(text).WithTitle(title);
|
||||||
|
|
||||||
if (url is not null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
|
if (url is not null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
|
||||||
embed.WithUrl(url);
|
embed.WithUrl(url);
|
||||||
@@ -56,15 +119,19 @@ public static class MessageChannelExtensions
|
|||||||
if (!string.IsNullOrWhiteSpace(footer))
|
if (!string.IsNullOrWhiteSpace(footer))
|
||||||
embed.WithFooter(footer);
|
embed.WithFooter(footer);
|
||||||
|
|
||||||
return ch.SendMessageAsync("", embed: embed.Build());
|
embed = type switch
|
||||||
|
{
|
||||||
|
MessageType.Error => embed.WithErrorColor(),
|
||||||
|
MessageType.Ok => embed.WithOkColor(),
|
||||||
|
MessageType.Pending => embed.WithPendingColor(),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||||
|
};
|
||||||
|
|
||||||
|
return ch.EmbedAsync(embed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, IEmbedBuilderService eb, string error)
|
// embed title and optional footer overloads
|
||||||
=> ch.SendMessageAsync("", embed: eb.Create().WithErrorColor().WithDescription(error).Build());
|
|
||||||
|
|
||||||
public static Task<IUserMessage> SendPendingAsync(this IMessageChannel ch, IEmbedBuilderService eb, string message)
|
|
||||||
=> ch.SendMessageAsync("", embed: eb.Create().WithPendingColor().WithDescription(message).Build());
|
|
||||||
|
|
||||||
public static Task<IUserMessage> SendConfirmAsync(
|
public static Task<IUserMessage> SendConfirmAsync(
|
||||||
this IMessageChannel ch,
|
this IMessageChannel ch,
|
||||||
IEmbedBuilderService eb,
|
IEmbedBuilderService eb,
|
||||||
@@ -72,21 +139,19 @@ public static class MessageChannelExtensions
|
|||||||
string text,
|
string text,
|
||||||
string? url = null,
|
string? url = null,
|
||||||
string? footer = null)
|
string? footer = null)
|
||||||
{
|
=> ch.SendAsync(eb, MessageType.Ok, title, text, url, footer);
|
||||||
var embed = eb.Create().WithOkColor().WithDescription(text).WithTitle(title);
|
|
||||||
|
public static Task<IUserMessage> SendErrorAsync(
|
||||||
if (url is not null && Uri.IsWellFormedUriString(url, UriKind.Absolute))
|
this IMessageChannel ch,
|
||||||
embed.WithUrl(url);
|
IEmbedBuilderService eb,
|
||||||
|
string title,
|
||||||
if (!string.IsNullOrWhiteSpace(footer))
|
string text,
|
||||||
embed.WithFooter(footer);
|
string? url = null,
|
||||||
|
string? footer = null)
|
||||||
return ch.SendMessageAsync("", embed: embed.Build());
|
=> ch.SendAsync(eb, MessageType.Error, title, text, url, footer);
|
||||||
}
|
|
||||||
|
|
||||||
public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, IEmbedBuilderService eb, string text)
|
|
||||||
=> ch.SendMessageAsync("", embed: eb.Create().WithOkColor().WithDescription(text).Build());
|
|
||||||
|
|
||||||
|
// weird stuff
|
||||||
|
|
||||||
public static Task<IUserMessage> SendTableAsync<T>(
|
public static Task<IUserMessage> SendTableAsync<T>(
|
||||||
this IMessageChannel ch,
|
this IMessageChannel ch,
|
||||||
string seed,
|
string seed,
|
||||||
@@ -142,7 +207,7 @@ public static class MessageChannelExtensions
|
|||||||
|
|
||||||
var component = new ComponentBuilder()
|
var component = new ComponentBuilder()
|
||||||
.WithButton(new ButtonBuilder()
|
.WithButton(new ButtonBuilder()
|
||||||
.WithStyle(ButtonStyle.Secondary)
|
.WithStyle(ButtonStyle.Primary)
|
||||||
.WithCustomId(BUTTON_LEFT)
|
.WithCustomId(BUTTON_LEFT)
|
||||||
.WithDisabled(lastPage == 0)
|
.WithDisabled(lastPage == 0)
|
||||||
.WithEmote(_arrowLeft))
|
.WithEmote(_arrowLeft))
|
||||||
@@ -164,6 +229,9 @@ public static class MessageChannelExtensions
|
|||||||
|
|
||||||
if (smc.Message.Id != msg.Id)
|
if (smc.Message.Id != msg.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (smc.Data.CustomId != BUTTON_LEFT && smc.Data.CustomId != BUTTON_RIGHT)
|
||||||
|
return;
|
||||||
|
|
||||||
await si.DeferAsync();
|
await si.DeferAsync();
|
||||||
if (smc.User.Id != ctx.User.Id)
|
if (smc.User.Id != ctx.User.Id)
|
||||||
@@ -210,12 +278,36 @@ public static class MessageChannelExtensions
|
|||||||
await msg.ModifyAsync(mp => mp.Components = new ComponentBuilder().Build());
|
await msg.ModifyAsync(mp => mp.Components = new ComponentBuilder().Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly Emoji _okEmoji = new Emoji("✅");
|
||||||
|
private static readonly Emoji _warnEmoji = new Emoji("⚠️");
|
||||||
|
private static readonly Emoji _errorEmoji = new Emoji("❌");
|
||||||
|
|
||||||
|
public static Task ReactAsync(this ICommandContext ctx, MessageType type)
|
||||||
|
{
|
||||||
|
var emoji = type switch
|
||||||
|
{
|
||||||
|
MessageType.Error => _errorEmoji,
|
||||||
|
MessageType.Pending => _warnEmoji,
|
||||||
|
MessageType.Ok => _okEmoji,
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(type)),
|
||||||
|
};
|
||||||
|
|
||||||
|
return ctx.Message.AddReactionAsync(emoji);
|
||||||
|
}
|
||||||
|
|
||||||
public static Task OkAsync(this ICommandContext ctx)
|
public static Task OkAsync(this ICommandContext ctx)
|
||||||
=> ctx.Message.AddReactionAsync(new Emoji("✅"));
|
=> ctx.ReactAsync(MessageType.Ok);
|
||||||
|
|
||||||
public static Task ErrorAsync(this ICommandContext ctx)
|
public static Task ErrorAsync(this ICommandContext ctx)
|
||||||
=> ctx.Message.AddReactionAsync(new Emoji("❌"));
|
=> ctx.ReactAsync(MessageType.Error);
|
||||||
|
|
||||||
public static Task WarningAsync(this ICommandContext ctx)
|
public static Task WarningAsync(this ICommandContext ctx)
|
||||||
=> ctx.Message.AddReactionAsync(new Emoji("⚠️"));
|
=> ctx.ReactAsync(MessageType.Pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MessageType
|
||||||
|
{
|
||||||
|
Ok,
|
||||||
|
Pending,
|
||||||
|
Error
|
||||||
}
|
}
|
@@ -519,7 +519,7 @@ streamoffline:
|
|||||||
- sto
|
- sto
|
||||||
- stoff
|
- stoff
|
||||||
streamonlinedelete:
|
streamonlinedelete:
|
||||||
- streamonlinedelte
|
- streamonlinedelete
|
||||||
- stondel
|
- stondel
|
||||||
streammessage:
|
streammessage:
|
||||||
- streammsg
|
- streammsg
|
||||||
@@ -1285,4 +1285,16 @@ medusalist:
|
|||||||
- melist
|
- melist
|
||||||
medusainfo:
|
medusainfo:
|
||||||
- medusainfo
|
- medusainfo
|
||||||
- meinfo
|
- meinfo
|
||||||
|
bankdeposit:
|
||||||
|
- deposit
|
||||||
|
- d
|
||||||
|
- dep
|
||||||
|
bankwithdraw:
|
||||||
|
- withdraw
|
||||||
|
- w
|
||||||
|
- with
|
||||||
|
bankbalance:
|
||||||
|
- balance
|
||||||
|
- b
|
||||||
|
- bal
|
||||||
|
@@ -2185,4 +2185,15 @@ medusalist:
|
|||||||
Read about the medusa system [here](https://nadekobot.readthedocs.io/en/latest/medusa/creating-a-medusa/)
|
Read about the medusa system [here](https://nadekobot.readthedocs.io/en/latest/medusa/creating-a-medusa/)
|
||||||
args:
|
args:
|
||||||
- ""
|
- ""
|
||||||
|
bankdeposit:
|
||||||
|
desc: "Deposits the specified amount of currency into the bank for later use."
|
||||||
|
args:
|
||||||
|
- "50"
|
||||||
|
bankwithdraw:
|
||||||
|
desc: "Withdraws the specified amount of currency from the bank if available."
|
||||||
|
args:
|
||||||
|
- "49"
|
||||||
|
bankbalance:
|
||||||
|
desc: "Shows your current bank balance available for withdrawal."
|
||||||
|
args:
|
||||||
|
- ""
|
@@ -993,5 +993,10 @@
|
|||||||
"medusa_unloaded": "Medusa {0} has been unloaded.",
|
"medusa_unloaded": "Medusa {0} has been unloaded.",
|
||||||
"medusa_empty": "Medusa wasn't loaded as it didn't contain any Sneks.",
|
"medusa_empty": "Medusa wasn't loaded as it didn't contain any Sneks.",
|
||||||
"medusa_already_loaded": "Medusa {0} is already loaded",
|
"medusa_already_loaded": "Medusa {0} is already loaded",
|
||||||
"medusa_invalid_not_found": "Medusa with that name wasn't found or the file was invalid"
|
"medusa_invalid_not_found": "Medusa with that name wasn't found or the file was invalid",
|
||||||
|
"bank_balance": "You have {0} in your bank account.",
|
||||||
|
"bank_deposited": "You deposited {0} to your bank account.",
|
||||||
|
"bank_withdrew": "You withdrew {0} from your bank account.",
|
||||||
|
"bank_withdraw_insuff": "You don't have sufficient {0} in your bank account.",
|
||||||
|
"cmd_group_commands": "'{0}' command group"
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user