mirror of
https://github.com/Jetsparrow/karmabot.git
synced 2026-01-21 09:06:09 +03:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bbc85ebf0 | ||
|
|
178f1ee089 | ||
|
|
ff63dbe386 | ||
|
|
7bef7255f8 | ||
|
|
45b94e7561 | ||
|
|
79e78f41c5 | ||
|
|
8322f4f871 | ||
|
|
61166ea0c9 | ||
|
|
e7c53fa2ad | ||
|
|
1ee1abc672 | ||
|
|
71a2328eb1 | ||
|
|
4353428d41 | ||
|
|
bf8778c7d9 | ||
|
|
2cd40cb85d | ||
|
|
68c2715c17 | ||
| bcda3b9282 | |||
| e2ee46eba9 | |||
|
|
d410d7ae47 | ||
| e5d81925f0 | |||
|
|
6835ba4843 | ||
|
|
d986a59844 | ||
|
|
7f9e5918d4 | ||
|
|
4be28f3c1b | ||
|
|
83d1b458af | ||
|
|
b93d20e07e | ||
|
|
fadd970c5d | ||
|
|
09d2ce7bb6 | ||
|
|
98361572dc | ||
|
|
08ebdbaa37 | ||
|
|
0a3d969bec | ||
|
|
fdfea2bbb1 | ||
|
|
3e7ace4a7e | ||
|
|
4aee536c63 | ||
|
|
6a4ee6e791 | ||
|
|
1159af1785 | ||
|
|
a9cca3ee59 | ||
|
|
51dce7f588 | ||
| d20cc89f28 | |||
| fd732d8719 | |||
|
|
d95dae4ddb | ||
| d3bbfe8c52 | |||
|
|
23dbd6ca17 | ||
|
|
c8adaaa0d4 | ||
|
|
bff68a9748 | ||
|
|
12b90d010f | ||
| efb1a532bd | |||
|
|
8918d576c4 | ||
|
|
6fb4fdf544 | ||
|
|
58c6d52232 | ||
|
|
8d0d70553c | ||
| 0025be1474 | |||
| 2fbfde551b | |||
| 37236d50ff | |||
| 4947351b89 | |||
| d535d2e8f4 | |||
| fff2c0d3fa | |||
| a55f7a1d97 | |||
|
|
1394062930 |
124
JetKarmaBot/CommandRouter.cs
Normal file
124
JetKarmaBot/CommandRouter.cs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
using JetKarmaBot.Commands;
|
||||||
|
using JetKarmaBot.Services;
|
||||||
|
using NLog;
|
||||||
|
using Perfusion;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Args;
|
||||||
|
|
||||||
|
namespace JetKarmaBot
|
||||||
|
{
|
||||||
|
public class ChatCommandRouter
|
||||||
|
{
|
||||||
|
Telegram.Bot.Types.User BotUser { get; }
|
||||||
|
[Inject] private Logger log;
|
||||||
|
[Inject] private KarmaContextFactory Db;
|
||||||
|
[Inject] private TelegramBotClient Client { get; set; }
|
||||||
|
|
||||||
|
public ChatCommandRouter(Telegram.Bot.Types.User botUser)
|
||||||
|
{
|
||||||
|
BotUser = botUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Execute(object sender, MessageEventArgs args)
|
||||||
|
{
|
||||||
|
log.Debug("Message received");
|
||||||
|
var text = args.Message.Text;
|
||||||
|
if (CommandString.TryParse(text, out var cmd))
|
||||||
|
{
|
||||||
|
if (cmd.UserName != null && cmd.UserName != BotUser.Username)
|
||||||
|
{
|
||||||
|
// directed not at us!
|
||||||
|
log.Debug("Message not directed at us");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (commands.ContainsKey(cmd.Command))
|
||||||
|
{
|
||||||
|
log.Debug($"Handling message via {commands[cmd.Command].GetType().Name}");
|
||||||
|
return commands[cmd.Command].Execute(cmd, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
log.Error($"Error while handling command {cmd.Command}!");
|
||||||
|
log.Error(e);
|
||||||
|
ReportToAdministratorChats($"Error while handling command {cmd.Command}!\n{e.ToString()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReportToAdministratorChats(string text)
|
||||||
|
{
|
||||||
|
using (var db = Db.GetContext())
|
||||||
|
{
|
||||||
|
foreach (long chatid in db.Chats.Where(x => x.IsAdministrator).Select(x => x.ChatId))
|
||||||
|
{
|
||||||
|
Client.SendTextMessageAsync(chatid, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(IChatCommand c)
|
||||||
|
{
|
||||||
|
log.ConditionalTrace($"Adding command {c.GetType().Name}");
|
||||||
|
foreach (var name in c.Names)
|
||||||
|
{
|
||||||
|
log.ConditionalTrace($"Mounting {c.GetType().Name} to {name}");
|
||||||
|
if (commands.ContainsKey(name))
|
||||||
|
throw new Exception($"command collision for name {name}, commands {commands[name].GetType()} and {c.GetType()}");
|
||||||
|
commands[name] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string GetHelpText(Locale loc)
|
||||||
|
{
|
||||||
|
List<string> pieces = new List<string>();
|
||||||
|
foreach (IChatCommand c in commands.Values.Distinct())
|
||||||
|
{
|
||||||
|
string build = "";
|
||||||
|
List<string> names = c.Names.ToList();
|
||||||
|
for (int i = 0; i < names.Count - 1; i++)
|
||||||
|
{
|
||||||
|
build = build + "/" + names[i] + "\n";
|
||||||
|
}
|
||||||
|
build += "/" + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>";
|
||||||
|
pieces.Add(build);
|
||||||
|
}
|
||||||
|
return string.Join("\n", pieces);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string GetHelpTextFor(string commandname, Locale loc)
|
||||||
|
{
|
||||||
|
IChatCommand c = commands[commandname];
|
||||||
|
string build = "";
|
||||||
|
List<string> names = c.Names.ToList();
|
||||||
|
for (int i = 0; i < names.Count - 1; i++)
|
||||||
|
{
|
||||||
|
build = build + "/" + names[i] + "\n";
|
||||||
|
}
|
||||||
|
build += "/" + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>\n";
|
||||||
|
build += string.Join("\n", c.Arguments.Select(ca => (!ca.Required ? "[" : "") + ca.Name + (!ca.Required ? "]" : "") + ": <i>" + getLocalizedCMDArgDesc(ca, loc) + "</i>"));
|
||||||
|
return build;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string getLocalizedCMDDesc(IChatCommand cmd, Locale loc)
|
||||||
|
{
|
||||||
|
if (loc.ContainsKey(cmd.DescriptionID)) return loc[cmd.DescriptionID];
|
||||||
|
else return cmd.Description;
|
||||||
|
}
|
||||||
|
private string getLocalizedCMDArgDesc(ChatCommandArgument arg, Locale loc)
|
||||||
|
{
|
||||||
|
if (loc.ContainsKey(arg.DescriptionID)) return loc[arg.DescriptionID];
|
||||||
|
else return arg.Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary<string, IChatCommand> commands = new Dictionary<string, IChatCommand>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,122 +1,99 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Args;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
|
using Perfusion;
|
||||||
|
using JetKarmaBot.Services;
|
||||||
using NLog;
|
using NLog;
|
||||||
using JetKarmaBot.Services.Handling;
|
|
||||||
using JetKarmaBot.Models;
|
|
||||||
|
|
||||||
namespace JetKarmaBot.Commands;
|
namespace JetKarmaBot.Commands
|
||||||
|
|
||||||
class AwardCommand : IChatCommand
|
|
||||||
{
|
{
|
||||||
|
class AwardCommand : IChatCommand
|
||||||
|
{
|
||||||
public IReadOnlyCollection<string> Names => new[] { "award", "revoke" };
|
public IReadOnlyCollection<string> Names => new[] { "award", "revoke" };
|
||||||
[Inject] private Logger log;
|
[Inject]
|
||||||
|
private Logger log;
|
||||||
|
|
||||||
public async Task<bool> Execute(RequestContext ctx)
|
public bool Execute(CommandString cmd, MessageEventArgs args)
|
||||||
{
|
{
|
||||||
var db = ctx.GetFeature<KarmaContext>();
|
using (var db = Db.GetContext())
|
||||||
var currentLocale = ctx.GetFeature<Locale>();
|
|
||||||
|
|
||||||
var awarder = ctx.EventArgs.Message.From;
|
|
||||||
|
|
||||||
if (Timeout.TimeoutCache[awarder.Id].PreviousAwardDate.AddSeconds(Config.Timeout.AwardTimeSeconds) > DateTime.Now)
|
|
||||||
{
|
{
|
||||||
ctx.GetFeature<TimeoutManager.Feature>().Multiplier = 0; // Doesn't count as success or failure
|
var currentLocale = Locale[db.Chats.Find(args.Message.Chat.Id).Locale];
|
||||||
if (!Timeout.TimeoutCache[awarder.Id].TimeoutMessaged)
|
if (args.Message.ReplyToMessage == null)
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.ratelimit"]);
|
{
|
||||||
Timeout.TimeoutCache[awarder.Id].TimeoutMessaged = true;
|
Client.SendTextMessageAsync(args.Message.Chat.Id, currentLocale["jetkarmabot.award.errawardnoreply"]);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string awardTypeText = null;
|
var awarder = args.Message.From;
|
||||||
long recipientId = default;
|
var recipient = args.Message.ReplyToMessage.From;
|
||||||
foreach (string arg in ctx.Command.Parameters)
|
|
||||||
|
bool awarding = cmd.Command == "award";
|
||||||
|
|
||||||
|
if (awarder.Id == recipient.Id)
|
||||||
{
|
{
|
||||||
if (arg.StartsWith('@'))
|
Client.SendTextMessageAsync(
|
||||||
{
|
args.Message.Chat.Id,
|
||||||
if (recipientId != default(int))
|
currentLocale["jetkarmabot.award.errawardself"],
|
||||||
{
|
replyToMessageId: args.Message.MessageId);
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.award.errdup"]);
|
return true;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
recipientId = await db.Users.Where(x => x.Username == arg).Select(x => x.UserId).FirstOrDefaultAsync();
|
|
||||||
if (recipientId == default(int))
|
|
||||||
{
|
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.award.errbadusername"]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (awardTypeText == null)
|
|
||||||
awardTypeText = arg;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.award.errdup"]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.EventArgs.Message.ReplyToMessage != null && recipientId == default)
|
if (Me.Id == recipient.Id)
|
||||||
{
|
{
|
||||||
recipientId = ctx.EventArgs.Message.ReplyToMessage.From.Id;
|
Client.SendTextMessageAsync(
|
||||||
}
|
args.Message.Chat.Id,
|
||||||
|
awarding
|
||||||
if (recipientId == default(int))
|
|
||||||
{
|
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.award.errawardnoreply"]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool awarding = ctx.Command.Command == "award";
|
|
||||||
|
|
||||||
if (awarder.Id == recipientId)
|
|
||||||
{
|
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.award.errawardself"]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx.GetFeature<ChatCommandRouter.Feature>().Router.Me.Id == recipientId)
|
|
||||||
{
|
|
||||||
await ctx.SendMessage(awarding
|
|
||||||
? currentLocale["jetkarmabot.award.errawardbot"]
|
? currentLocale["jetkarmabot.award.errawardbot"]
|
||||||
: currentLocale["jetkarmabot.award.errrevokebot"]);
|
: currentLocale["jetkarmabot.award.errrevokebot"],
|
||||||
return false;
|
replyToMessageId: args.Message.MessageId);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var text = ctx.EventArgs.Message.Text;
|
var text = args.Message.Text;
|
||||||
|
var awardTypeText = cmd.Parameters.FirstOrDefault();
|
||||||
global::JetKarmaBot.Models.AwardType awardType = awardTypeText != null
|
global::JetKarmaBot.Models.AwardType awardType = awardTypeText != null
|
||||||
? await db.AwardTypes.FirstAsync(at => at.CommandName == awardTypeText)
|
? db.AwardTypes.First(at => at.CommandName == awardTypeText)
|
||||||
: await db.AwardTypes.FindAsync((sbyte)1);
|
: db.AwardTypes.Find((sbyte)1);
|
||||||
|
DateTime cutoff = DateTime.Now - TimeSpan.FromMinutes(5);
|
||||||
var prevCount = await db.Awards
|
if (db.Awards.Where(x => x.Date > cutoff && x.FromId == awarder.Id).Count() >= 10)
|
||||||
.Where(aw => aw.ToId == recipientId && aw.AwardTypeId == awardType.AwardTypeId && aw.ChatId == ctx.EventArgs.Message.Chat.Id)
|
{
|
||||||
.SumAsync(aw => aw.Amount);
|
Client.SendTextMessageAsync(
|
||||||
|
args.Message.Chat.Id,
|
||||||
await db.Awards.AddAsync(new Models.Award()
|
currentLocale["jetkarmabot.award.ratelimit"],
|
||||||
|
replyToMessageId: args.Message.MessageId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
db.Awards.Add(new Models.Award()
|
||||||
{
|
{
|
||||||
AwardTypeId = awardType.AwardTypeId,
|
AwardTypeId = awardType.AwardTypeId,
|
||||||
Amount = (sbyte)(awarding ? 1 : -1),
|
Amount = (sbyte)(awarding ? 1 : -1),
|
||||||
FromId = awarder.Id,
|
FromId = awarder.Id,
|
||||||
ToId = recipientId,
|
ToId = recipient.Id,
|
||||||
ChatId = ctx.EventArgs.Message.Chat.Id
|
ChatId = args.Message.Chat.Id
|
||||||
});
|
});
|
||||||
|
log.Debug($"Awarded {(awarding ? 1 : -1)}{awardType.Symbol} to {recipient.Username}");
|
||||||
var recUserName = (await db.Users.FindAsync(recipientId)).Username;
|
db.SaveChanges();
|
||||||
|
|
||||||
log.Debug($"Awarded {(awarding ? 1 : -1)}{awardType.Symbol} to {recUserName}");
|
|
||||||
|
|
||||||
string message = awarding
|
string message = awarding
|
||||||
? string.Format(currentLocale["jetkarmabot.award.awardmessage"], getLocalizedName(awardType, currentLocale), recUserName)
|
? string.Format(currentLocale["jetkarmabot.award.awardmessage"], getLocalizedName(awardType, currentLocale), "@" + recipient.Username)
|
||||||
: string.Format(currentLocale["jetkarmabot.award.revokemessage"], getLocalizedName(awardType, currentLocale), recUserName);
|
: string.Format(currentLocale["jetkarmabot.award.revokemessage"], getLocalizedName(awardType, currentLocale), "@" + recipient.Username);
|
||||||
|
|
||||||
|
var currentCount = db.Awards
|
||||||
|
.Where(aw => aw.ToId == recipient.Id && aw.AwardTypeId == awardType.AwardTypeId)
|
||||||
|
.Sum(aw => aw.Amount);
|
||||||
|
|
||||||
var response = message + "\n" + String.Format(currentLocale["jetkarmabot.award.statustext"], recUserName, prevCount + (awarding ? 1 : -1), awardType.Symbol);
|
var response = message + "\n" + String.Format(currentLocale["jetkarmabot.award.statustext"], "@" + recipient.Username, currentCount, awardType.Symbol);
|
||||||
|
|
||||||
await ctx.SendMessage(response);
|
Client.SendTextMessageAsync(
|
||||||
Timeout.TimeoutCache[awarder.Id].PreviousAwardDate = DateTime.Now;
|
args.Message.Chat.Id,
|
||||||
|
response,
|
||||||
|
replyToMessageId: args.Message.MessageId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string getLocalizedName(global::JetKarmaBot.Models.AwardType awardType, Locale loc)
|
private string getLocalizedName(global::JetKarmaBot.Models.AwardType awardType, Locale loc)
|
||||||
{
|
{
|
||||||
@ -130,9 +107,10 @@ class AwardCommand : IChatCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inject] KarmaContextFactory Db { get; set; }
|
||||||
|
[Inject] TelegramBotClient Client { get; set; }
|
||||||
[Inject] Localization Locale { get; set; }
|
[Inject] Localization Locale { get; set; }
|
||||||
[Inject] TimeoutManager Timeout { get; set; }
|
User Me { get; }
|
||||||
[Inject] Config Config { get; set; }
|
|
||||||
|
|
||||||
public string Description => "Awards/revokes an award to a user.";
|
public string Description => "Awards/revokes an award to a user.";
|
||||||
public string DescriptionID => "jetkarmabot.award.help";
|
public string DescriptionID => "jetkarmabot.award.help";
|
||||||
@ -144,13 +122,12 @@ class AwardCommand : IChatCommand
|
|||||||
Type=ChatCommandArgumentType.String,
|
Type=ChatCommandArgumentType.String,
|
||||||
Description="The award to grant to/strip of the specified user",
|
Description="The award to grant to/strip of the specified user",
|
||||||
DescriptionID="jetkarmabot.award.awardtypehelp"
|
DescriptionID="jetkarmabot.award.awardtypehelp"
|
||||||
},
|
|
||||||
new ChatCommandArgument() {
|
|
||||||
Name="to",
|
|
||||||
Required=false,
|
|
||||||
Type=ChatCommandArgumentType.String,
|
|
||||||
Description="The user to award it to.",
|
|
||||||
DescriptionID="jetkarmabot.award.tohelp"
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public AwardCommand(User me)
|
||||||
|
{
|
||||||
|
Me = me;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +1,48 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Args;
|
||||||
|
using Perfusion;
|
||||||
|
using JetKarmaBot.Services;
|
||||||
using NLog;
|
using NLog;
|
||||||
using JetKarmaBot.Services.Handling;
|
using System.Linq;
|
||||||
using JetKarmaBot.Models;
|
|
||||||
|
|
||||||
namespace JetKarmaBot.Commands;
|
namespace JetKarmaBot.Commands
|
||||||
|
|
||||||
class LocaleCommand : IChatCommand
|
|
||||||
{
|
{
|
||||||
public IReadOnlyCollection<string> Names => new[] { "changelocale", "locale" };
|
class LocaleCommand : IChatCommand
|
||||||
[Inject] private Logger log;
|
|
||||||
|
|
||||||
public async Task<bool> Execute(RequestContext ctx)
|
|
||||||
{
|
{
|
||||||
var db = ctx.GetFeature<KarmaContext>();
|
public IReadOnlyCollection<string> Names => new[] { "changelocale", "locale" };
|
||||||
var currentLocale = ctx.GetFeature<Locale>();
|
[Inject]
|
||||||
var cmd = ctx.Command;
|
private Logger log;
|
||||||
var args = ctx.EventArgs;
|
|
||||||
|
|
||||||
|
public bool Execute(CommandString cmd, MessageEventArgs args)
|
||||||
|
{
|
||||||
|
using (var db = Db.GetContext())
|
||||||
|
{
|
||||||
|
var currentLocale = Locale[db.Chats.Find(args.Message.Chat.Id).Locale];
|
||||||
if (cmd.Parameters.Length < 1)
|
if (cmd.Parameters.Length < 1)
|
||||||
{
|
{
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.changelocale.getlocale"]);
|
Client.SendTextMessageAsync(
|
||||||
return false;
|
args.Message.Chat.Id,
|
||||||
|
currentLocale["jetkarmabot.changelocale.getlocale"],
|
||||||
|
replyToMessageId: args.Message.MessageId);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd.Parameters[0] == "list")
|
else if (cmd.Parameters[0] == "list")
|
||||||
{
|
{
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.changelocale.listalltext"] + "\n"
|
Client.SendTextMessageAsync(
|
||||||
+ string.Join("\n", Locale.Select(a => a.Key)));
|
args.Message.Chat.Id,
|
||||||
return false;
|
currentLocale["jetkarmabot.changelocale.listalltext"] + "\n"
|
||||||
|
+ string.Join("\n", Locale.Select(a => a.Key)),
|
||||||
|
replyToMessageId: args.Message.MessageId);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else if (cmd.Parameters[0] == "all")
|
else if (cmd.Parameters[0] == "all")
|
||||||
{
|
{
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.changelocale.errorall"]);
|
Client.SendTextMessageAsync(
|
||||||
return false;
|
args.Message.Chat.Id,
|
||||||
|
currentLocale["jetkarmabot.changelocale.errorall"],
|
||||||
|
replyToMessageId: args.Message.MessageId);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
string localeId;
|
string localeId;
|
||||||
if (Locale.ContainsLocale(cmd.Parameters[0]))
|
if (Locale.ContainsLocale(cmd.Parameters[0]))
|
||||||
@ -42,22 +54,29 @@ class LocaleCommand : IChatCommand
|
|||||||
}
|
}
|
||||||
catch (LocalizationException e)
|
catch (LocalizationException e)
|
||||||
{
|
{
|
||||||
await ctx.SendMessage(
|
Client.SendTextMessageAsync(
|
||||||
currentLocale["jetkarmabot.changelocale.toomany"] + "\n"
|
args.Message.Chat.Id,
|
||||||
+ string.Join("\n", (e.Data["LocaleNames"] as Locale[]).Select(x => x.Name)));
|
currentLocale["jetkarmabot.changelocale.toomany"] + "\n" + string.Join("\n", (e.Data["LocaleNames"] as Locale[]).Select(x => x.Name)),
|
||||||
return false;
|
replyToMessageId: args.Message.MessageId);
|
||||||
}
|
|
||||||
(await db.Chats.FindAsync(args.Message.Chat.Id)).Locale = localeId;
|
|
||||||
log.Debug($"Changed language of chat {args.Message.Chat.Id} to {localeId}");
|
|
||||||
|
|
||||||
currentLocale = Locale[localeId];
|
|
||||||
|
|
||||||
await ctx.SendMessage(
|
|
||||||
(currentLocale.HasNote ? currentLocale["jetkarmabot.changelocale.beforenote"] + currentLocale.Note + "\n" : "")
|
|
||||||
+ currentLocale["jetkarmabot.changelocale.justchanged"]);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
db.Chats.Find(args.Message.Chat.Id).Locale = localeId;
|
||||||
|
log.Debug($"Changed language of chat {args.Message.Chat.Id} to {localeId}");
|
||||||
|
db.SaveChanges();
|
||||||
|
|
||||||
|
currentLocale = Locale[db.Chats.Find(args.Message.Chat.Id).Locale];
|
||||||
|
|
||||||
|
Client.SendTextMessageAsync(
|
||||||
|
args.Message.Chat.Id,
|
||||||
|
(currentLocale.HasNote ? currentLocale["jetkarmabot.changelocale.beforenote"] + currentLocale.Note + "\n" : "")
|
||||||
|
+ currentLocale["jetkarmabot.changelocale.justchanged"],
|
||||||
|
replyToMessageId: args.Message.MessageId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inject] KarmaContextFactory Db { get; set; }
|
||||||
|
[Inject] TelegramBotClient Client { get; set; }
|
||||||
[Inject] Localization Locale { get; set; }
|
[Inject] Localization Locale { get; set; }
|
||||||
|
|
||||||
public string Description => "Switches current chat locale to [locale]";
|
public string Description => "Switches current chat locale to [locale]";
|
||||||
@ -72,4 +91,5 @@ class LocaleCommand : IChatCommand
|
|||||||
DescriptionID="jetkarmabot.changelocale.localehelp"
|
DescriptionID="jetkarmabot.changelocale.localehelp"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
using System.Text.RegularExpressions;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace JetKarmaBot.Commands;
|
namespace JetKarmaBot.Commands
|
||||||
|
|
||||||
public class CommandString
|
|
||||||
{
|
{
|
||||||
|
public class CommandString
|
||||||
|
{
|
||||||
public CommandString(string command, params string[] parameters)
|
public CommandString(string command, params string[] parameters)
|
||||||
{
|
{
|
||||||
Command = command;
|
Command = command;
|
||||||
@ -36,7 +40,7 @@ public class CommandString
|
|||||||
string username = match.Groups["name"].Captures.Count > 0 ? match.Groups["name"].Captures[0].Value : null;
|
string username = match.Groups["name"].Captures.Count > 0 ? match.Groups["name"].Captures[0].Value : null;
|
||||||
string[] parameters = words.Skip(1).ToArray();
|
string[] parameters = words.Skip(1).ToArray();
|
||||||
|
|
||||||
result = new CommandString(cmd, parameters) { UserName = username };
|
result = new CommandString(cmd, parameters) { UserName = username};
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,4 +49,5 @@ public class CommandString
|
|||||||
if (TryParse(s, out var c)) return c;
|
if (TryParse(s, out var c)) return c;
|
||||||
throw new ArgumentException($"\"{s}\" is not a command");
|
throw new ArgumentException($"\"{s}\" is not a command");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using System.Collections.Generic;
|
||||||
using JetKarmaBot.Services.Handling;
|
using Telegram.Bot.Args;
|
||||||
using JetKarmaBot.Models;
|
using Perfusion;
|
||||||
|
using JetKarmaBot.Services;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Types.Enums;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace JetKarmaBot.Commands;
|
namespace JetKarmaBot.Commands
|
||||||
|
|
||||||
public class CurrenciesCommand : IChatCommand
|
|
||||||
{
|
{
|
||||||
|
public class CurrenciesCommand : IChatCommand
|
||||||
|
{
|
||||||
|
[Inject] KarmaContextFactory Db;
|
||||||
|
[Inject] TelegramBotClient Client { get; set; }
|
||||||
[Inject] Localization Locale { get; set; }
|
[Inject] Localization Locale { get; set; }
|
||||||
public IReadOnlyCollection<string> Names => new[] { "currencies", "awardtypes" };
|
public IReadOnlyCollection<string> Names => new[] { "currencies", "awardtypes" };
|
||||||
|
|
||||||
@ -15,14 +21,20 @@ public class CurrenciesCommand : IChatCommand
|
|||||||
public IReadOnlyCollection<ChatCommandArgument> Arguments => new ChatCommandArgument[] {
|
public IReadOnlyCollection<ChatCommandArgument> Arguments => new ChatCommandArgument[] {
|
||||||
};
|
};
|
||||||
|
|
||||||
public async Task<bool> Execute(RequestContext ctx)
|
public bool Execute(CommandString cmd, MessageEventArgs args)
|
||||||
{
|
{
|
||||||
var db = ctx.GetFeature<KarmaContext>();
|
using (var db = Db.GetContext())
|
||||||
var currentLocale = ctx.GetFeature<Locale>();
|
{
|
||||||
await ctx.SendMessage(
|
var currentLocale = Locale[db.Chats.Find(args.Message.Chat.Id).Locale];
|
||||||
currentLocale["jetkarmabot.currencies.listtext"] + "\n" + string.Join("\n",
|
string resp = currentLocale["jetkarmabot.currencies.listtext"] + "\n" + string.Join("\n",
|
||||||
(await db.AwardTypes.ToListAsync())
|
db.AwardTypes.ToList().Select(x => $"{x.Symbol} ({x.CommandName}) <i>{currentLocale["jetkarmabot.awardtypes.nominative." + x.CommandName]}</i>"));
|
||||||
.Select(x => $"{x.Symbol} ({x.CommandName}) <i>{currentLocale["jetkarmabot.awardtypes.nominative." + x.CommandName]}</i>")));
|
Client.SendTextMessageAsync(
|
||||||
|
args.Message.Chat.Id,
|
||||||
|
resp,
|
||||||
|
replyToMessageId: args.Message.MessageId,
|
||||||
|
parseMode: ParseMode.Html);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,10 +1,18 @@
|
|||||||
using JetKarmaBot.Services.Handling;
|
using System.Collections.Generic;
|
||||||
|
using Telegram.Bot.Args;
|
||||||
|
using Perfusion;
|
||||||
|
using JetKarmaBot.Services;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Types.Enums;
|
||||||
|
|
||||||
namespace JetKarmaBot.Commands;
|
namespace JetKarmaBot.Commands
|
||||||
|
|
||||||
public class HelpCommand : IChatCommand
|
|
||||||
{
|
{
|
||||||
|
public class HelpCommand : IChatCommand
|
||||||
|
{
|
||||||
|
[Inject] KarmaContextFactory Db;
|
||||||
|
[Inject] TelegramBotClient Client { get; set; }
|
||||||
[Inject] Localization Locale { get; set; }
|
[Inject] Localization Locale { get; set; }
|
||||||
|
ChatCommandRouter Router;
|
||||||
public IReadOnlyCollection<string> Names => new[] { "help" };
|
public IReadOnlyCollection<string> Names => new[] { "help" };
|
||||||
|
|
||||||
public string Description => "Displays help text for all(one) command(s)";
|
public string Description => "Displays help text for all(one) command(s)";
|
||||||
@ -20,19 +28,34 @@ public class HelpCommand : IChatCommand
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public async Task<bool> Execute(RequestContext ctx)
|
public bool Execute(CommandString cmd, MessageEventArgs args)
|
||||||
{
|
{
|
||||||
var currentLocale = ctx.GetFeature<Locale>();
|
using (var db = Db.GetContext())
|
||||||
var router = ctx.GetFeature<ChatCommandRouter.Feature>().Router;
|
|
||||||
if (ctx.Command.Parameters.Length < 1)
|
|
||||||
{
|
{
|
||||||
await ctx.SendMessage(router.GetHelpText(currentLocale));
|
var currentLocale = Locale[db.Chats.Find(args.Message.Chat.Id).Locale];
|
||||||
|
if (cmd.Parameters.Length < 1)
|
||||||
|
{
|
||||||
|
Client.SendTextMessageAsync(
|
||||||
|
args.Message.Chat.Id,
|
||||||
|
Router.GetHelpText(currentLocale),
|
||||||
|
replyToMessageId: args.Message.MessageId,
|
||||||
|
parseMode: ParseMode.Html);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await ctx.SendMessage(router.GetHelpTextFor(ctx.Command.Parameters[0], currentLocale));
|
Client.SendTextMessageAsync(
|
||||||
|
args.Message.Chat.Id,
|
||||||
|
Router.GetHelpTextFor(cmd.Parameters[0], currentLocale),
|
||||||
|
replyToMessageId: args.Message.MessageId,
|
||||||
|
parseMode: ParseMode.Html);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
public HelpCommand(ChatCommandRouter router)
|
||||||
|
{
|
||||||
|
Router = router;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,29 +1,31 @@
|
|||||||
using JetKarmaBot.Services.Handling;
|
using System.Collections.Generic;
|
||||||
|
using Telegram.Bot.Args;
|
||||||
|
|
||||||
namespace JetKarmaBot.Commands;
|
namespace JetKarmaBot.Commands
|
||||||
|
|
||||||
public interface IChatCommand
|
|
||||||
{
|
{
|
||||||
|
public interface IChatCommand
|
||||||
|
{
|
||||||
IReadOnlyCollection<string> Names { get; }
|
IReadOnlyCollection<string> Names { get; }
|
||||||
string Description { get; }
|
string Description { get; }
|
||||||
string DescriptionID { get; }
|
string DescriptionID { get; }
|
||||||
IReadOnlyCollection<ChatCommandArgument> Arguments { get; }
|
IReadOnlyCollection<ChatCommandArgument> Arguments { get; }
|
||||||
|
|
||||||
Task<bool> Execute(RequestContext ctx);
|
bool Execute(CommandString cmd, MessageEventArgs messageEventArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ChatCommandArgument
|
public struct ChatCommandArgument
|
||||||
{
|
{
|
||||||
public string Name;
|
public string Name;
|
||||||
public bool Required;
|
public bool Required;
|
||||||
public ChatCommandArgumentType Type;
|
public ChatCommandArgumentType Type;
|
||||||
public string Description;
|
public string Description;
|
||||||
public string DescriptionID;
|
public string DescriptionID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ChatCommandArgumentType
|
public enum ChatCommandArgumentType
|
||||||
{
|
{
|
||||||
Boolean,
|
Boolean,
|
||||||
String,
|
String,
|
||||||
Integer,
|
Integer,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using JetKarmaBot.Services.Handling;
|
|
||||||
using JetKarmaBot.Models;
|
|
||||||
|
|
||||||
namespace JetKarmaBot.Commands;
|
|
||||||
|
|
||||||
class LeaderboardCommand : IChatCommand
|
|
||||||
{
|
|
||||||
public IReadOnlyCollection<string> Names => new[] { "leaderboard" };
|
|
||||||
|
|
||||||
public async Task<bool> Execute(RequestContext ctx)
|
|
||||||
{
|
|
||||||
bool isPrivate = ctx.EventArgs.Message.Chat.Type == Telegram.Bot.Types.Enums.ChatType.Private;
|
|
||||||
var currentLocale = ctx.GetFeature<Locale>();
|
|
||||||
if (isPrivate)
|
|
||||||
{
|
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.award.errawardself"]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var db = ctx.GetFeature<KarmaContext>();
|
|
||||||
var asker = ctx.EventArgs.Message.From;
|
|
||||||
var awardTypeName = ctx.Command.Parameters.FirstOrDefault();
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(awardTypeName))
|
|
||||||
awardTypeName = "star";
|
|
||||||
|
|
||||||
var awardTypeIdQuery = from awt in db.AwardTypes
|
|
||||||
where awt.CommandName == awardTypeName
|
|
||||||
select awt.AwardTypeId;
|
|
||||||
var awardTypeId = await awardTypeIdQuery.FirstAsync();
|
|
||||||
var awardType = await db.AwardTypes.FindAsync(awardTypeId);
|
|
||||||
|
|
||||||
var topEarners = await db.Awards
|
|
||||||
.Where(x => x.ChatId == ctx.EventArgs.Message.Chat.Id && x.AwardTypeId == awardTypeId)
|
|
||||||
.GroupBy(x => x.To)
|
|
||||||
.Select(x => new { User = x.Key, Amount = x.Sum(y => y.Amount) })
|
|
||||||
.OrderByDescending(x => x.Amount)
|
|
||||||
.Take(5)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var response = string.Format(currentLocale["jetkarmabot.leaderboard.specifictext"], awardType.Symbol) + "\n"
|
|
||||||
+ string.Join('\n', topEarners.Select((x, index)
|
|
||||||
=> $"{index + 1}. {x.User.Username} - {x.Amount}")
|
|
||||||
);
|
|
||||||
|
|
||||||
await ctx.SendMessage(response);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Inject] Localization Locale { get; set; }
|
|
||||||
|
|
||||||
public string Description => "Shows the people with the most of a specific award.";
|
|
||||||
public string DescriptionID => "jetkarmabot.leaderboard.help";
|
|
||||||
|
|
||||||
public IReadOnlyCollection<ChatCommandArgument> Arguments => new ChatCommandArgument[] {
|
|
||||||
new ChatCommandArgument() {
|
|
||||||
Name="awardtype",
|
|
||||||
Required=true,
|
|
||||||
Type=ChatCommandArgumentType.String,
|
|
||||||
Description="The awardtype to show a leaderboard for.",
|
|
||||||
DescriptionID= "jetkarmabot.leaderboard.awardtypehelp"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -1,51 +1,83 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using System;
|
||||||
using JetKarmaBot.Services.Handling;
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Perfusion;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Args;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
using JetKarmaBot.Models;
|
using JetKarmaBot.Models;
|
||||||
|
using JetKarmaBot.Services;
|
||||||
|
|
||||||
namespace JetKarmaBot.Commands;
|
namespace JetKarmaBot.Commands
|
||||||
|
|
||||||
class StatusCommand : IChatCommand
|
|
||||||
{
|
{
|
||||||
public IReadOnlyCollection<string> Names => ["status"];
|
class StatusCommand : IChatCommand
|
||||||
|
|
||||||
public async Task<bool> Execute(RequestContext ctx)
|
|
||||||
{
|
{
|
||||||
var db = ctx.GetFeature<KarmaContext>();
|
public IReadOnlyCollection<string> Names => new[] { "status" };
|
||||||
var currentLocale = ctx.GetFeature<Locale>();
|
|
||||||
var asker = ctx.EventArgs.Message.From;
|
public bool Execute(CommandString cmd, MessageEventArgs args)
|
||||||
bool isPrivate = ctx.EventArgs.Message.Chat.Type == Telegram.Bot.Types.Enums.ChatType.Private;
|
{
|
||||||
|
using (var db = Db.GetContext())
|
||||||
|
{
|
||||||
|
var currentLocale = Locale[db.Chats.Find(args.Message.Chat.Id).Locale];
|
||||||
|
var asker = args.Message.From;
|
||||||
|
var awardTypeName = cmd.Parameters.FirstOrDefault();
|
||||||
|
|
||||||
string response;
|
string response;
|
||||||
|
|
||||||
var awards = db.Awards.Where(x => x.ToId == asker.Id);
|
if (string.IsNullOrWhiteSpace(awardTypeName))
|
||||||
if (!isPrivate)
|
{
|
||||||
awards = awards.Where(x => x.ChatId == ctx.EventArgs.Message.Chat.Id);
|
// var awards = db.Awards.Where(x => x.ToId == asker.Id)
|
||||||
|
// .GroupBy(x => x.AwardTypeId)
|
||||||
if (!awards.Any())
|
// .Select(x => new { AwardTypeId = x.Key, Amount = x.Sum(y => y.Amount) });
|
||||||
|
if (!db.Awards.Any(x => x.ToId == asker.Id))
|
||||||
response = currentLocale["jetkarmabot.status.havenothing"];
|
response = currentLocale["jetkarmabot.status.havenothing"];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var aq = db.AwardTypes.GroupJoin(
|
var awardsQuery = from award in db.Awards
|
||||||
awards,
|
where award.ToId == asker.Id
|
||||||
at => at.AwardTypeId,
|
group award by award.AwardTypeId into g
|
||||||
aw => aw.AwardTypeId,
|
select new { AwardTypeId = g.Key, Amount = g.Sum(x => x.Amount) };
|
||||||
(at, aws) => new {at.Symbol, Amount = aws.Sum(aw => aw.Amount) });
|
var awardsByType = awardsQuery.ToList();
|
||||||
|
response = currentLocale["jetkarmabot.status.listalltext"] + "\n"
|
||||||
|
+ string.Join("\n", awardsByType.Select(a => $" - {db.AwardTypes.Find(a.AwardTypeId).Symbol} {a.Amount}"));
|
||||||
|
|
||||||
var awardsByType = await aq.ToListAsync();
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var awardTypeIdQuery = from awt in db.AwardTypes
|
||||||
|
where awt.CommandName == awardTypeName
|
||||||
|
select awt.AwardTypeId;
|
||||||
|
var awardTypeId = awardTypeIdQuery.First();
|
||||||
|
var awardType = db.AwardTypes.Find(awardTypeId);
|
||||||
|
|
||||||
response =
|
response = string.Format(currentLocale["jetkarmabot.status.listspecifictext"], db.Awards.Where(x => x.AwardTypeId == awardTypeId && x.ToId == asker.Id).Sum(x => x.Amount), awardType.Symbol);
|
||||||
currentLocale["jetkarmabot.status.listalltext"] + "\n"
|
|
||||||
+ string.Join("\n", awardsByType.Select(a => $" - {a.Symbol} {a.Amount}"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await ctx.SendMessage(response);
|
Client.SendTextMessageAsync(
|
||||||
|
args.Message.Chat.Id,
|
||||||
|
response,
|
||||||
|
replyToMessageId: args.Message.MessageId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Inject] KarmaContextFactory Db { get; set; }
|
||||||
|
[Inject] TelegramBotClient Client { get; set; }
|
||||||
[Inject] Localization Locale { get; set; }
|
[Inject] Localization Locale { get; set; }
|
||||||
|
|
||||||
public string Description => "Shows the amount of awards that you have";
|
public string Description => "Shows the amount of awards that you have";
|
||||||
public string DescriptionID => "jetkarmabot.status.help";
|
public string DescriptionID => "jetkarmabot.status.help";
|
||||||
|
|
||||||
public IReadOnlyCollection<ChatCommandArgument> Arguments => [];
|
public IReadOnlyCollection<ChatCommandArgument> Arguments => new ChatCommandArgument[] {
|
||||||
|
new ChatCommandArgument(){
|
||||||
|
Name="awardtype",
|
||||||
|
Required=false,
|
||||||
|
Type=ChatCommandArgumentType.String,
|
||||||
|
Description="The awardtype to show. If empty shows everything.",
|
||||||
|
DescriptionID= "jetkarmabot.status.awardtypehelp"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,10 @@ using Newtonsoft.Json;
|
|||||||
using JsonNet.PrivateSettersContractResolvers;
|
using JsonNet.PrivateSettersContractResolvers;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace JetKarmaBot;
|
namespace JetKarmaBot
|
||||||
|
|
||||||
public class Config : ConfigBase
|
|
||||||
{
|
{
|
||||||
|
public class Config : ConfigBase
|
||||||
|
{
|
||||||
public Config(string path) : base(path) { }
|
public Config(string path) : base(path) { }
|
||||||
|
|
||||||
public string ApiKey { get; private set; }
|
public string ApiKey { get; private set; }
|
||||||
@ -21,24 +21,11 @@ public class Config : ConfigBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ProxySettings Proxy { get; private set; }
|
public ProxySettings Proxy { get; private set; }
|
||||||
public class TimeoutConfig
|
public bool SqlDebug { get; private set; }
|
||||||
{
|
|
||||||
public int DebtLimitSeconds { get; private set; } = 60 * 60 * 2;
|
|
||||||
public Dictionary<string, int> CommandCostsSeconds { get; private set; } = new Dictionary<string, int>()
|
|
||||||
{
|
|
||||||
{"JetKarmaBot.Commands.AwardCommand (OK)", 60*15},
|
|
||||||
{"JetKarmaBot.Commands.AwardCommand (ERR)", 60*5},
|
|
||||||
{"Default", 60*5}
|
|
||||||
};
|
|
||||||
public int SaveIntervalSeconds { get; private set; } = 60 * 5;
|
|
||||||
public double AwardTimeSeconds { get; private set; } = 60;
|
|
||||||
}
|
}
|
||||||
public TimeoutConfig Timeout { get; private set; } = new TimeoutConfig();
|
|
||||||
public bool SqlDebug { get; private set; } = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class ConfigBase
|
public abstract class ConfigBase
|
||||||
{
|
{
|
||||||
public ConfigBase(string path)
|
public ConfigBase(string path)
|
||||||
{
|
{
|
||||||
JObject configJson;
|
JObject configJson;
|
||||||
@ -72,5 +59,6 @@ public abstract class ConfigBase
|
|||||||
System.Diagnostics.Debug.WriteLine(e);
|
System.Diagnostics.Debug.WriteLine(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
namespace JetKarmaBot;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public static class IReadOnlyDictionaryExtensions
|
namespace JetKarmaBot
|
||||||
{
|
{
|
||||||
|
public static class IReadOnlyDictionaryExtensions
|
||||||
|
{
|
||||||
public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dict, TKey key)
|
public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dict, TKey key)
|
||||||
{
|
{
|
||||||
TValue res = default;
|
TValue res = default(TValue);
|
||||||
if (key != null)
|
if (key != null)
|
||||||
dict.TryGetValue(key, out res);
|
dict.TryGetValue(key, out res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,10 @@ using Newtonsoft.Json;
|
|||||||
using Newtonsoft.Json.Serialization;
|
using Newtonsoft.Json.Serialization;
|
||||||
|
|
||||||
// ReSharper disable once CheckNamespace
|
// ReSharper disable once CheckNamespace
|
||||||
namespace JsonNet.PrivateSettersContractResolvers;
|
namespace JsonNet.PrivateSettersContractResolvers
|
||||||
|
|
||||||
public class PrivateSetterContractResolver : DefaultContractResolver
|
|
||||||
{
|
{
|
||||||
|
public class PrivateSetterContractResolver : DefaultContractResolver
|
||||||
|
{
|
||||||
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
||||||
{
|
{
|
||||||
var jProperty = base.CreateProperty(member, memberSerialization);
|
var jProperty = base.CreateProperty(member, memberSerialization);
|
||||||
@ -17,10 +17,10 @@ public class PrivateSetterContractResolver : DefaultContractResolver
|
|||||||
|
|
||||||
return jProperty;
|
return jProperty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PrivateSetterCamelCasePropertyNamesContractResolver : CamelCasePropertyNamesContractResolver
|
public class PrivateSetterCamelCasePropertyNamesContractResolver : CamelCasePropertyNamesContractResolver
|
||||||
{
|
{
|
||||||
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
|
||||||
{
|
{
|
||||||
var jProperty = base.CreateProperty(member, memberSerialization);
|
var jProperty = base.CreateProperty(member, memberSerialization);
|
||||||
@ -31,14 +31,15 @@ public class PrivateSetterCamelCasePropertyNamesContractResolver : CamelCaseProp
|
|||||||
|
|
||||||
return jProperty;
|
return jProperty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class MemberInfoExtensions
|
internal static class MemberInfoExtensions
|
||||||
{
|
{
|
||||||
internal static bool IsPropertyWithSetter(this MemberInfo member)
|
internal static bool IsPropertyWithSetter(this MemberInfo member)
|
||||||
{
|
{
|
||||||
var property = member as PropertyInfo;
|
var property = member as PropertyInfo;
|
||||||
|
|
||||||
return property?.GetSetMethod(true) != null;
|
return property?.GetSetMethod(true) != null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +0,0 @@
|
|||||||
global using System;
|
|
||||||
global using System.Collections.Generic;
|
|
||||||
global using System.Linq;
|
|
||||||
global using System.Threading;
|
|
||||||
global using System.Threading.Tasks;
|
|
||||||
global using Perfusion;
|
|
||||||
@ -1,126 +1,85 @@
|
|||||||
using JetKarmaBot.Commands;
|
using JetKarmaBot.Commands;
|
||||||
using JetKarmaBot.Models;
|
using JetKarmaBot.Models;
|
||||||
using JetKarmaBot.Services;
|
using JetKarmaBot.Services;
|
||||||
using JetKarmaBot.Services.Handling;
|
using Perfusion;
|
||||||
using NLog;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using Telegram.Bot;
|
using Telegram.Bot;
|
||||||
using Telegram.Bot.Polling;
|
using Telegram.Bot.Args;
|
||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
|
|
||||||
namespace JetKarmaBot;
|
namespace JetKarmaBot
|
||||||
|
|
||||||
public class JetKarmaBot : IDisposable
|
|
||||||
{
|
{
|
||||||
|
public class JetKarmaBot : IDisposable
|
||||||
|
{
|
||||||
[Inject] Config Config { get; set; }
|
[Inject] Config Config { get; set; }
|
||||||
[Inject] IContainer Container { get; set; }
|
[Inject] IContainer Container { get; set; }
|
||||||
[Inject] KarmaContextFactory Db { get; set; }
|
[Inject] KarmaContextFactory Db { get; set; }
|
||||||
[Inject] TimeoutManager Timeout { get; set; }
|
|
||||||
[Inject] Localization Locale { get; set; }
|
|
||||||
[Inject] Logger Log { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
TelegramBotClient Client { get; set; }
|
TelegramBotClient Client { get; set; }
|
||||||
ChatCommandRouter Commands;
|
ChatCommandRouter Commands;
|
||||||
RequestChain Chain;
|
Telegram.Bot.Types.User Me { get; set; }
|
||||||
Task timeoutWaitTask;
|
|
||||||
CancellationTokenSource timeoutWaitTaskToken;
|
|
||||||
private bool stopped = false;
|
|
||||||
|
|
||||||
public async Task Init()
|
public async Task Init()
|
||||||
{
|
{
|
||||||
using (KarmaContext db = Db.GetContext())
|
using (KarmaContext db = Db.GetContext())
|
||||||
await db.Database.EnsureCreatedAsync();
|
await db.Database.EnsureCreatedAsync();
|
||||||
|
var httpProxy = new WebProxy($"{Config.Proxy.Url}:{Config.Proxy.Port}")
|
||||||
|
{
|
||||||
|
Credentials = new NetworkCredential(Config.Proxy.Login, Config.Proxy.Password)
|
||||||
|
};
|
||||||
|
|
||||||
Client = new TelegramBotClient(Config.ApiKey);
|
Client = new TelegramBotClient(Config.ApiKey, httpProxy);
|
||||||
Container.AddInstance(Client);
|
Container.AddInstance(Client);
|
||||||
|
Me = await Client.GetMeAsync();
|
||||||
|
|
||||||
timeoutWaitTaskToken = new CancellationTokenSource();
|
InitCommands(Container);
|
||||||
timeoutWaitTask = Timeout.SaveLoop(timeoutWaitTaskToken.Token);
|
|
||||||
|
|
||||||
await InitCommands(Container);
|
Client.OnMessage += BotOnMessageReceived;
|
||||||
InitChain(Container);
|
Client.StartReceiving();
|
||||||
|
|
||||||
var receiverOptions = new ReceiverOptions { AllowedUpdates = new[] { UpdateType.Message } };
|
|
||||||
Client.StartReceiving(
|
|
||||||
HandleUpdateAsync,
|
|
||||||
HandleErrorAsync,
|
|
||||||
receiverOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Stop()
|
public async Task Stop()
|
||||||
{
|
{
|
||||||
if (stopped) return;
|
|
||||||
Client?.CloseAsync();
|
|
||||||
timeoutWaitTaskToken?.Cancel();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (timeoutWaitTask != null)
|
|
||||||
await timeoutWaitTask;
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException) { }
|
|
||||||
await Timeout?.Save();
|
|
||||||
Dispose();
|
Dispose();
|
||||||
stopped = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region service
|
#region service
|
||||||
|
|
||||||
Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
|
void BotOnMessageReceived(object sender, MessageEventArgs messageEventArgs)
|
||||||
{
|
|
||||||
Log.Error(exception, "Exception while handling API message");
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task HandleUpdateAsync(ITelegramBotClient sender, Update update, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (update.Type != UpdateType.Message || update?.Message?.Type != MessageType.Text)
|
|
||||||
return;
|
|
||||||
var message = update.Message!;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
|
var message = messageEventArgs.Message;
|
||||||
if (message == null || message.Type != MessageType.Text)
|
if (message == null || message.Type != MessageType.Text)
|
||||||
return;
|
return;
|
||||||
if (!CommandString.TryParse(message.Text, out var cmd))
|
using (KarmaContext db = Db.GetContext())
|
||||||
return;
|
|
||||||
if (cmd.UserName != null && cmd.UserName != Commands.Me.Username)
|
|
||||||
return;
|
|
||||||
|
|
||||||
RequestContext ctx = new RequestContext(Client, update, cmd);
|
|
||||||
await Chain.Handle(ctx);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
{
|
||||||
Log.Error(e, "Exception while handling message {0}", message);
|
if (!db.Users.Any(x => x.UserId == messageEventArgs.Message.From.Id))
|
||||||
|
db.Users.Add(new Models.User { UserId = messageEventArgs.Message.From.Id });
|
||||||
|
if (messageEventArgs.Message.ReplyToMessage != null)
|
||||||
|
if (!db.Users.Any(x => x.UserId == messageEventArgs.Message.ReplyToMessage.From.Id))
|
||||||
|
db.Users.Add(new Models.User { UserId = messageEventArgs.Message.ReplyToMessage.From.Id });
|
||||||
|
if (!db.Chats.Any(x => x.ChatId == messageEventArgs.Message.Chat.Id))
|
||||||
|
db.Chats.Add(new Models.Chat { ChatId = messageEventArgs.Message.Chat.Id });
|
||||||
|
db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
string s = message.Text;
|
||||||
|
long id = message.Chat.Id;
|
||||||
|
long from = message.From.Id;
|
||||||
|
Task.Run(() => Commands.Execute(sender, messageEventArgs));
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task InitCommands(IContainer c)
|
void InitCommands(IContainer c)
|
||||||
{
|
{
|
||||||
c.Add<HelpCommand>();
|
Commands = c.ResolveObject(new ChatCommandRouter(Me));
|
||||||
c.Add<AwardCommand>();
|
Commands.Add(c.ResolveObject(new HelpCommand(Commands)));
|
||||||
c.Add<StatusCommand>();
|
Commands.Add(c.ResolveObject(new AwardCommand(Me)));
|
||||||
c.Add<LocaleCommand>();
|
Commands.Add(c.ResolveObject(new StatusCommand()));
|
||||||
c.Add<CurrenciesCommand>();
|
Commands.Add(c.ResolveObject(new LocaleCommand()));
|
||||||
c.Add<LeaderboardCommand>();
|
Commands.Add(c.ResolveObject(new CurrenciesCommand()));
|
||||||
Commands = c.GetInstance<ChatCommandRouter>();
|
|
||||||
await Commands.Start();
|
|
||||||
foreach (IChatCommand cmd in c.GetInstances<IChatCommand>())
|
|
||||||
{
|
|
||||||
Commands.Add(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitChain(IContainer c)
|
|
||||||
{
|
|
||||||
Chain = c.ResolveObject(new RequestChain());
|
|
||||||
Chain.Add(c.GetInstance<TimeoutManager.PreDbThrowout>());
|
|
||||||
Chain.Add(c.GetInstance<DatabaseHandler>());
|
|
||||||
Chain.Add(Timeout);
|
|
||||||
Chain.Add(c.GetInstance<SaveData>());
|
|
||||||
Chain.Add(Commands);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -129,9 +88,9 @@ public class JetKarmaBot : IDisposable
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
timeoutWaitTaskToken?.Dispose();
|
Client.StopReceiving();
|
||||||
timeoutWaitTask?.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,31 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFrameworks>netcoreapp2.2;</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.2.4">
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<PackageReference Include="Telegram.Bot" Version="22.0.2" />
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||||
<PackageReference Include="NLog" Version="5.3.4" />
|
</PackageReference>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||||
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Telegram.Bot" Version="14.12.0" />
|
||||||
|
<PackageReference Include="NLog" Version="4.6.5" />
|
||||||
|
<PackageReference Include="NLog.Config" Version="4.6.5" />
|
||||||
<ProjectReference Include="..\perfusion\Perfusion\Perfusion.csproj" />
|
<ProjectReference Include="..\perfusion\Perfusion\Perfusion.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="karma.cfg.json">
|
<None Update="karma.cfg.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="lang\*">
|
<None Update="lang\be-BY.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="lang\en-US.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="lang\ru-RU.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Update="NLog.config">
|
<None Update="NLog.config">
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace JetKarmaBot.Models;
|
namespace JetKarmaBot.Models
|
||||||
|
|
||||||
public partial class Award
|
|
||||||
{
|
{
|
||||||
|
public partial class Award
|
||||||
|
{
|
||||||
public int AwardId { get; set; }
|
public int AwardId { get; set; }
|
||||||
public long ChatId { get; set; }
|
public long ChatId { get; set; }
|
||||||
public long FromId { get; set; }
|
public int FromId { get; set; }
|
||||||
public long ToId { get; set; }
|
public int ToId { get; set; }
|
||||||
public sbyte AwardTypeId { get; set; }
|
public sbyte AwardTypeId { get; set; }
|
||||||
public sbyte Amount { get; set; }
|
public sbyte Amount { get; set; }
|
||||||
public DateTime Date { get; set; }
|
public DateTime Date { get; set; }
|
||||||
@ -19,4 +21,5 @@ public partial class Award
|
|||||||
public virtual User From { get; set; }
|
public virtual User From { get; set; }
|
||||||
[ForeignKey("ToId")]
|
[ForeignKey("ToId")]
|
||||||
public virtual User To { get; set; }
|
public virtual User To { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
namespace JetKarmaBot.Models;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public partial class AwardType
|
namespace JetKarmaBot.Models
|
||||||
{
|
{
|
||||||
|
public partial class AwardType
|
||||||
|
{
|
||||||
public AwardType()
|
public AwardType()
|
||||||
{
|
{
|
||||||
Awards = new HashSet<Award>();
|
Awards = new HashSet<Award>();
|
||||||
@ -14,4 +17,5 @@ public partial class AwardType
|
|||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
||||||
public virtual ICollection<Award> Awards { get; set; }
|
public virtual ICollection<Award> Awards { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,19 @@
|
|||||||
namespace JetKarmaBot.Models;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
public partial class Chat
|
namespace JetKarmaBot.Models
|
||||||
{
|
{
|
||||||
|
public partial class Chat
|
||||||
|
{
|
||||||
public Chat()
|
public Chat()
|
||||||
{
|
{
|
||||||
Awards = new HashSet<Award>();
|
Awards = new HashSet<Award>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long ChatId { get; set; }
|
public long ChatId { get; set; }
|
||||||
public string Locale { get; set; } = "ru-RU";
|
public string Locale { get; set; }
|
||||||
public bool IsAdministrator { get; set; }
|
public bool IsAdministrator { get; set; }
|
||||||
|
|
||||||
public virtual ICollection<Award> Awards { get; set; }
|
public virtual ICollection<Award> Awards { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Perfusion;
|
||||||
|
|
||||||
namespace JetKarmaBot.Models;
|
namespace JetKarmaBot.Models
|
||||||
|
|
||||||
[Transient]
|
|
||||||
public partial class KarmaContext : DbContext
|
|
||||||
{
|
{
|
||||||
|
[Transient]
|
||||||
|
public partial class KarmaContext : DbContext
|
||||||
|
{
|
||||||
public KarmaContext()
|
public KarmaContext()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -31,20 +34,20 @@ public partial class KarmaContext : DbContext
|
|||||||
entity.ToTable("award");
|
entity.ToTable("award");
|
||||||
|
|
||||||
entity.HasIndex(e => e.AwardId)
|
entity.HasIndex(e => e.AwardId)
|
||||||
.HasDatabaseName("awardid_UNIQUE")
|
.HasName("awardid_UNIQUE")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
entity.HasIndex(e => e.AwardTypeId)
|
entity.HasIndex(e => e.AwardTypeId)
|
||||||
.HasDatabaseName("fk_awardtype_idx");
|
.HasName("fk_awardtype_idx");
|
||||||
|
|
||||||
entity.HasIndex(e => e.ChatId)
|
entity.HasIndex(e => e.ChatId)
|
||||||
.HasDatabaseName("fk_chat_idx");
|
.HasName("fk_chat_idx");
|
||||||
|
|
||||||
entity.HasIndex(e => e.FromId)
|
entity.HasIndex(e => e.FromId)
|
||||||
.HasDatabaseName("fk_from_idx");
|
.HasName("fk_from_idx");
|
||||||
|
|
||||||
entity.HasIndex(e => e.ToId)
|
entity.HasIndex(e => e.ToId)
|
||||||
.HasDatabaseName("fk_to_idx");
|
.HasName("fk_to_idx");
|
||||||
|
|
||||||
entity.Property(e => e.AwardId)
|
entity.Property(e => e.AwardId)
|
||||||
.HasColumnName("awardid")
|
.HasColumnName("awardid")
|
||||||
@ -106,11 +109,11 @@ public partial class KarmaContext : DbContext
|
|||||||
entity.ToTable("awardtype");
|
entity.ToTable("awardtype");
|
||||||
|
|
||||||
entity.HasIndex(e => e.AwardTypeId)
|
entity.HasIndex(e => e.AwardTypeId)
|
||||||
.HasDatabaseName("awardtypeid_UNIQUE")
|
.HasName("awardtypeid_UNIQUE")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
entity.HasIndex(e => e.CommandName)
|
entity.HasIndex(e => e.CommandName)
|
||||||
.HasDatabaseName("commandname_UNIQUE")
|
.HasName("commandname_UNIQUE")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
entity.Property(e => e.AwardTypeId)
|
entity.Property(e => e.AwardTypeId)
|
||||||
@ -169,11 +172,7 @@ public partial class KarmaContext : DbContext
|
|||||||
entity.Property(e => e.Username)
|
entity.Property(e => e.Username)
|
||||||
.HasColumnName("username")
|
.HasColumnName("username")
|
||||||
.HasColumnType("varchar(45)");
|
.HasColumnType("varchar(45)");
|
||||||
|
|
||||||
entity.Property(e => e.CooldownDate)
|
|
||||||
.HasColumnName("cooldowndate")
|
|
||||||
.HasColumnType("timestamp")
|
|
||||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,22 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace JetKarmaBot.Models;
|
namespace JetKarmaBot.Models
|
||||||
|
|
||||||
public partial class User
|
|
||||||
{
|
{
|
||||||
|
public partial class User
|
||||||
|
{
|
||||||
public User()
|
public User()
|
||||||
{
|
{
|
||||||
AwardsFrom = new HashSet<Award>();
|
AwardsFrom = new HashSet<Award>();
|
||||||
AwardsTo = new HashSet<Award>();
|
AwardsTo = new HashSet<Award>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long UserId { get; set; }
|
public int UserId { get; set; }
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
public DateTime CooldownDate { get; set; }
|
|
||||||
[InverseProperty("From")]
|
[InverseProperty("From")]
|
||||||
public virtual ICollection<Award> AwardsFrom { get; set; }
|
public virtual ICollection<Award> AwardsFrom { get; set; }
|
||||||
[InverseProperty("To")]
|
[InverseProperty("To")]
|
||||||
public virtual ICollection<Award> AwardsTo { get; set; }
|
public virtual ICollection<Award> AwardsTo { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using System;
|
||||||
using NLog;
|
using System.Threading;
|
||||||
using JetKarmaBot.Models;
|
using JetKarmaBot.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NLog;
|
||||||
|
using Perfusion;
|
||||||
|
|
||||||
namespace JetKarmaBot;
|
namespace JetKarmaBot
|
||||||
|
|
||||||
public static class Program
|
|
||||||
{
|
{
|
||||||
|
public static class Program
|
||||||
|
{
|
||||||
private static Logger log = LogManager.GetCurrentClassLogger();
|
private static Logger log = LogManager.GetCurrentClassLogger();
|
||||||
public enum ExitCode : int
|
public enum ExitCode : int
|
||||||
{
|
{
|
||||||
@ -23,11 +26,8 @@ public static class Program
|
|||||||
var cfg = new Config("karma.cfg.json");
|
var cfg = new Config("karma.cfg.json");
|
||||||
c.AddInstance(cfg);
|
c.AddInstance(cfg);
|
||||||
|
|
||||||
var connStr = cfg.ConnectionString + (cfg.ConnectionString.EndsWith(";") ? "" : ";") + "TreatTinyAsBoolean=false";
|
|
||||||
var serverVersion = ServerVersion.AutoDetect(connStr);
|
|
||||||
|
|
||||||
var dbOptions = new DbContextOptionsBuilder<KarmaContext>()
|
var dbOptions = new DbContextOptionsBuilder<KarmaContext>()
|
||||||
.UseMySql(connStr, serverVersion);
|
.UseMySql(cfg.ConnectionString + (cfg.ConnectionString.EndsWith(";") ? "" : ";") + "TreatTinyAsBoolean=false");
|
||||||
c.AddInfo<Logger>(new LogInfo());
|
c.AddInfo<Logger>(new LogInfo());
|
||||||
if (cfg.SqlDebug)
|
if (cfg.SqlDebug)
|
||||||
{
|
{
|
||||||
@ -40,13 +40,14 @@ public static class Program
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bot.Init().GetAwaiter().GetResult();
|
bot.Init().Wait();
|
||||||
log.Info("JetKarmaBot started. Press Ctrl-C to exit...");
|
log.Info("JetKarmaBot started. Press Ctrl-C to exit...");
|
||||||
|
Environment.ExitCode = (int)ExitCode.ErrorRunning;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log.Error(ex);
|
log.Error(ex);
|
||||||
return (int)ExitCode.ErrorException;
|
Environment.ExitCode = (int)ExitCode.ErrorException;
|
||||||
}
|
}
|
||||||
ManualResetEvent quitEvent = new ManualResetEvent(false);
|
ManualResetEvent quitEvent = new ManualResetEvent(false);
|
||||||
try
|
try
|
||||||
@ -56,18 +57,14 @@ public static class Program
|
|||||||
eArgs.Cancel = true;
|
eArgs.Cancel = true;
|
||||||
quitEvent.Set();
|
quitEvent.Set();
|
||||||
};
|
};
|
||||||
AppDomain.CurrentDomain.ProcessExit += (sender, args) =>
|
|
||||||
{
|
|
||||||
log.Info("Received stop request, waiting for exit...");
|
|
||||||
bot?.Stop()?.GetAwaiter().GetResult();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
quitEvent.WaitOne(Timeout.Infinite);
|
quitEvent.WaitOne(Timeout.Infinite);
|
||||||
log.Info("Waiting for exit...");
|
log.Info("Waiting for exit...");
|
||||||
bot?.Stop()?.GetAwaiter().GetResult();
|
bot?.Stop()?.Wait();
|
||||||
|
|
||||||
return (int)ExitCode.Ok;
|
return (int)ExitCode.Ok;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,105 +0,0 @@
|
|||||||
using NLog;
|
|
||||||
using Telegram.Bot;
|
|
||||||
using JetKarmaBot.Commands;
|
|
||||||
|
|
||||||
namespace JetKarmaBot.Services.Handling;
|
|
||||||
|
|
||||||
public class ChatCommandRouter : IRequestHandler
|
|
||||||
{
|
|
||||||
public class Feature
|
|
||||||
{
|
|
||||||
public Type CommandType;
|
|
||||||
public ChatCommandRouter Router;
|
|
||||||
public bool Succeded;
|
|
||||||
}
|
|
||||||
public Telegram.Bot.Types.User Me { get; private set; }
|
|
||||||
[Inject] private Logger log;
|
|
||||||
[Inject] private TelegramBotClient Client { get; set; }
|
|
||||||
|
|
||||||
public async Task Start()
|
|
||||||
{
|
|
||||||
Me = await Client.GetMeAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
|
||||||
{
|
|
||||||
log.Debug("Message received");
|
|
||||||
CommandString cmd = ctx.Command;
|
|
||||||
Feature feature = new Feature() { Router = this };
|
|
||||||
ctx.AddFeature(feature);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (commands.ContainsKey(cmd.Command))
|
|
||||||
{
|
|
||||||
feature.CommandType = commands[cmd.Command].GetType();
|
|
||||||
log.Debug($"Handling message via {feature.CommandType.Name}");
|
|
||||||
async Task processCommand() => feature.Succeded = await commands[cmd.Command].Execute(ctx);
|
|
||||||
return processCommand();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.Error($"Error while handling command {cmd.Command}!");
|
|
||||||
log.Error(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(IChatCommand c)
|
|
||||||
{
|
|
||||||
log.ConditionalTrace($"Adding command {c.GetType().Name}");
|
|
||||||
foreach (var name in c.Names)
|
|
||||||
{
|
|
||||||
log.ConditionalTrace($"Mounting {c.GetType().Name} to {name}");
|
|
||||||
if (commands.ContainsKey(name))
|
|
||||||
throw new Exception($"command collision for name {name}, commands {commands[name].GetType()} and {c.GetType()}");
|
|
||||||
commands[name] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal string GetHelpText(Locale loc)
|
|
||||||
{
|
|
||||||
List<string> pieces = new List<string>();
|
|
||||||
foreach (IChatCommand c in commands.Values.Distinct())
|
|
||||||
{
|
|
||||||
string build = "";
|
|
||||||
List<string> names = c.Names.ToList();
|
|
||||||
for (int i = 0; i < names.Count - 1; i++)
|
|
||||||
{
|
|
||||||
build = build + "/" + names[i] + "\n";
|
|
||||||
}
|
|
||||||
build += "/" + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>";
|
|
||||||
pieces.Add(build);
|
|
||||||
}
|
|
||||||
return string.Join("\n", pieces);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal string GetHelpTextFor(string commandname, Locale loc)
|
|
||||||
{
|
|
||||||
IChatCommand c = commands[commandname];
|
|
||||||
string build = "";
|
|
||||||
List<string> names = c.Names.ToList();
|
|
||||||
for (int i = 0; i < names.Count - 1; i++)
|
|
||||||
{
|
|
||||||
build = build + "/" + names[i] + "\n";
|
|
||||||
}
|
|
||||||
build += "/" + names[names.Count - 1] + " " + string.Join(" ", c.Arguments.Select(x => (!x.Required ? "[" : "") + x.Name + (!x.Required ? "]" : ""))) + " <i>" + getLocalizedCMDDesc(c, loc) + "</i>\n";
|
|
||||||
build += string.Join("\n", c.Arguments.Select(ca => (!ca.Required ? "[" : "") + ca.Name + (!ca.Required ? "]" : "") + ": <i>" + getLocalizedCMDArgDesc(ca, loc) + "</i>"));
|
|
||||||
return build;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string getLocalizedCMDDesc(IChatCommand cmd, Locale loc)
|
|
||||||
{
|
|
||||||
if (loc.ContainsKey(cmd.DescriptionID)) return loc[cmd.DescriptionID];
|
|
||||||
else return cmd.Description;
|
|
||||||
}
|
|
||||||
private string getLocalizedCMDArgDesc(ChatCommandArgument arg, Locale loc)
|
|
||||||
{
|
|
||||||
if (loc.ContainsKey(arg.DescriptionID)) return loc[arg.DescriptionID];
|
|
||||||
else return arg.Description;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<string, IChatCommand> commands = new Dictionary<string, IChatCommand>();
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
namespace JetKarmaBot.Services.Handling;
|
|
||||||
|
|
||||||
public class DatabaseHandler : IRequestHandler
|
|
||||||
{
|
|
||||||
[Inject] private KarmaContextFactory Db;
|
|
||||||
[Inject] private Localization Locale;
|
|
||||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
|
||||||
{
|
|
||||||
using (var db = Db.GetContext())
|
|
||||||
{
|
|
||||||
ctx.AddFeature(db); // KarmaContext
|
|
||||||
ctx.AddFeature(Locale[(await db.Chats.FindAsync(ctx.EventArgs.Message.Chat.Id))?.Locale ?? "ru-ru"]); // Locale
|
|
||||||
await next(ctx);
|
|
||||||
await db.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,37 +0,0 @@
|
|||||||
using NLog;
|
|
||||||
|
|
||||||
namespace JetKarmaBot.Services.Handling;
|
|
||||||
|
|
||||||
public interface IRequestHandler
|
|
||||||
{
|
|
||||||
Task Handle(RequestContext ctx, Func<RequestContext, Task> next);
|
|
||||||
}
|
|
||||||
public class RequestChain : IRequestHandler
|
|
||||||
{
|
|
||||||
[Inject] private Logger log;
|
|
||||||
List<IRequestHandler> handlerStack = new List<IRequestHandler>();
|
|
||||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next = null)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
Func<RequestContext, Task> chainNext = null;
|
|
||||||
chainNext = (newCtx) =>
|
|
||||||
{
|
|
||||||
if (i == handlerStack.Count)
|
|
||||||
{
|
|
||||||
log.ConditionalTrace("(next) End of request chain");
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
IRequestHandler handler = handlerStack[i++];
|
|
||||||
log.ConditionalTrace($"(next) Executing handler {handler.GetType().Name}");
|
|
||||||
return handler.Handle(newCtx, chainNext);
|
|
||||||
};
|
|
||||||
await chainNext(ctx);
|
|
||||||
if (next != null)
|
|
||||||
await next(ctx);
|
|
||||||
}
|
|
||||||
public void Add(IRequestHandler handler)
|
|
||||||
{
|
|
||||||
log.ConditionalTrace($"Adding {handler.GetType().Name} to reqchain");
|
|
||||||
handlerStack.Add(handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
using Telegram.Bot;
|
|
||||||
using Telegram.Bot.Types;
|
|
||||||
using JetKarmaBot.Commands;
|
|
||||||
|
|
||||||
namespace JetKarmaBot.Services.Handling;
|
|
||||||
|
|
||||||
public class RequestContext : IServiceProvider
|
|
||||||
{
|
|
||||||
public ITelegramBotClient Client { get; }
|
|
||||||
public Update EventArgs { get; }
|
|
||||||
public CommandString Command { get; }
|
|
||||||
public Dictionary<Type, object> Features { get; } = new Dictionary<Type, object>();
|
|
||||||
public RequestContext(ITelegramBotClient client, Update args, CommandString cmd)
|
|
||||||
{
|
|
||||||
Client = client;
|
|
||||||
EventArgs = args;
|
|
||||||
Command = cmd;
|
|
||||||
}
|
|
||||||
public object GetService(Type serviceType) => Features[serviceType];
|
|
||||||
public T GetFeature<T>() => (T)Features[typeof(T)];
|
|
||||||
public void AddFeature<T>(T feat) => Features[typeof(T)] = feat;
|
|
||||||
|
|
||||||
//Method to reduce WET in commands
|
|
||||||
public Task SendMessage(string text)
|
|
||||||
=> Client.SendMessage(
|
|
||||||
chatId: EventArgs.Message.Chat.Id,
|
|
||||||
text: text,
|
|
||||||
disableNotification: true,
|
|
||||||
parseMode: Telegram.Bot.Types.Enums.ParseMode.Html,
|
|
||||||
replyParameters: new ReplyParameters { MessageId = EventArgs.Message.MessageId }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using JetKarmaBot.Models;
|
|
||||||
|
|
||||||
namespace JetKarmaBot.Services.Handling;
|
|
||||||
|
|
||||||
public class SaveData : IRequestHandler
|
|
||||||
{
|
|
||||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
|
||||||
{
|
|
||||||
KarmaContext db = ctx.GetFeature<KarmaContext>();
|
|
||||||
await AddUserToDatabase(db, ctx.EventArgs.Message.From);
|
|
||||||
if (ctx.EventArgs.Message.ReplyToMessage != null)
|
|
||||||
await AddUserToDatabase(db, ctx.EventArgs.Message.ReplyToMessage.From);
|
|
||||||
if (!await db.Chats.AnyAsync(x => x.ChatId == ctx.EventArgs.Message.Chat.Id))
|
|
||||||
db.Chats.Add(new Models.Chat
|
|
||||||
{
|
|
||||||
ChatId = ctx.EventArgs.Message.Chat.Id
|
|
||||||
});
|
|
||||||
await next(ctx);
|
|
||||||
}
|
|
||||||
private async Task AddUserToDatabase(KarmaContext db, Telegram.Bot.Types.User u)
|
|
||||||
{
|
|
||||||
string un;
|
|
||||||
if (u.Username == null)
|
|
||||||
un = u.FirstName + (u.LastName != null ? " " + u.LastName : "");
|
|
||||||
else
|
|
||||||
un = "@" + u.Username;
|
|
||||||
if (!await db.Users.AnyAsync(x => x.UserId == u.Id))
|
|
||||||
await db.Users.AddAsync(new Models.User { UserId = u.Id, Username = un });
|
|
||||||
else
|
|
||||||
(await db.Users.FindAsync(u.Id)).Username = un;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,126 +0,0 @@
|
|||||||
using NLog;
|
|
||||||
using JetKarmaBot.Models;
|
|
||||||
|
|
||||||
namespace JetKarmaBot.Services.Handling;
|
|
||||||
|
|
||||||
[Singleton]
|
|
||||||
public class TimeoutManager : IRequestHandler
|
|
||||||
{
|
|
||||||
public class Feature
|
|
||||||
{
|
|
||||||
public double Multiplier = 1;
|
|
||||||
}
|
|
||||||
public class PreDbThrowout : IRequestHandler
|
|
||||||
{
|
|
||||||
public TimeoutManager Timeout { get; }
|
|
||||||
public PreDbThrowout(TimeoutManager timeout)
|
|
||||||
{
|
|
||||||
Timeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
|
||||||
{
|
|
||||||
var uid = ctx.EventArgs.Message.From.Id;
|
|
||||||
if (Timeout.TimeoutCache.TryGetValue(uid, out var stats))
|
|
||||||
{
|
|
||||||
DateTime debtLimit = DateTime.Now.AddSeconds(Timeout.cfg.Timeout.DebtLimitSeconds);
|
|
||||||
if (debtLimit < stats.CooldownDate && stats.TimeoutMessaged)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await next(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public class TimeoutStats
|
|
||||||
{
|
|
||||||
public DateTime CooldownDate;
|
|
||||||
public bool TimeoutMessaged;
|
|
||||||
public DateTime PreviousAwardDate;
|
|
||||||
}
|
|
||||||
[Inject] private KarmaContextFactory Db;
|
|
||||||
[Inject] private Config cfg;
|
|
||||||
[Inject] private Localization Locale;
|
|
||||||
[Inject] private Logger log;
|
|
||||||
public Dictionary<long, TimeoutStats> TimeoutCache = new ();
|
|
||||||
private async Task ApplyCost(string name, bool succeded, long uid, KarmaContext db, Feature feature)
|
|
||||||
{
|
|
||||||
if (feature.Multiplier == 0)
|
|
||||||
return;
|
|
||||||
if (!cfg.Timeout.CommandCostsSeconds.TryGetValue(name + (succeded ? " (OK)" : "(ERR)"), out var costSeconds))
|
|
||||||
if (!cfg.Timeout.CommandCostsSeconds.TryGetValue(name, out costSeconds))
|
|
||||||
if (!cfg.Timeout.CommandCostsSeconds.TryGetValue("Default", out costSeconds))
|
|
||||||
{
|
|
||||||
throw new LocalizationException("Default key not present");
|
|
||||||
}
|
|
||||||
await PopulateStats(uid, db);
|
|
||||||
DateTime debtLimit = DateTime.Now.AddSeconds(cfg.Timeout.DebtLimitSeconds);
|
|
||||||
if (TimeoutCache[uid].CooldownDate >= debtLimit)
|
|
||||||
//Programming error
|
|
||||||
throw new NotImplementedException();
|
|
||||||
TimeoutCache[uid].CooldownDate = (TimeoutCache[uid].CooldownDate <= DateTime.Now ? DateTime.Now : TimeoutCache[uid].CooldownDate)
|
|
||||||
.AddSeconds(feature.Multiplier * costSeconds);
|
|
||||||
TimeoutCache[uid].TimeoutMessaged = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PopulateStats(long uid, KarmaContext db)
|
|
||||||
{
|
|
||||||
if (!TimeoutCache.ContainsKey(uid))
|
|
||||||
{
|
|
||||||
log.ConditionalTrace($"User {uid} not present: saving to cache");
|
|
||||||
TimeoutCache[uid] = new TimeoutStats()
|
|
||||||
{
|
|
||||||
CooldownDate = (await db.Users.FindAsync(uid))?.CooldownDate ?? DateTime.Now
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public async Task Save(CancellationToken ct = default(CancellationToken))
|
|
||||||
{
|
|
||||||
log.Debug("Saving timeout info to database");
|
|
||||||
using (KarmaContext db = Db.GetContext())
|
|
||||||
{
|
|
||||||
foreach (var i in TimeoutCache.Keys)
|
|
||||||
{
|
|
||||||
(await db.Users.FindAsync(new object[] { i }, ct)).CooldownDate = TimeoutCache[i].CooldownDate;
|
|
||||||
}
|
|
||||||
await db.SaveChangesAsync(ct);
|
|
||||||
}
|
|
||||||
log.Debug("Saved timeout info to database");
|
|
||||||
}
|
|
||||||
public async Task SaveLoop(CancellationToken ct = default(CancellationToken))
|
|
||||||
{
|
|
||||||
while (!ct.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
await Task.Delay(cfg.Timeout.SaveIntervalSeconds * 1000, ct);
|
|
||||||
await Save(ct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
|
||||||
{
|
|
||||||
var uid = ctx.EventArgs.Message.From.Id;
|
|
||||||
KarmaContext db = ctx.GetFeature<KarmaContext>();
|
|
||||||
await PopulateStats(uid, db);
|
|
||||||
DateTime debtLimit = DateTime.Now.AddSeconds(cfg.Timeout.DebtLimitSeconds);
|
|
||||||
if (debtLimit < TimeoutCache[uid].CooldownDate)
|
|
||||||
{
|
|
||||||
if (!TimeoutCache[uid].TimeoutMessaged)
|
|
||||||
{
|
|
||||||
Locale currentLocale = ctx.GetFeature<Locale>();
|
|
||||||
await ctx.SendMessage(currentLocale["jetkarmabot.ratelimit"]);
|
|
||||||
TimeoutCache[uid].TimeoutMessaged = true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Feature feature = new Feature();
|
|
||||||
ctx.AddFeature(feature);
|
|
||||||
|
|
||||||
await next(ctx);
|
|
||||||
|
|
||||||
var routerFeature = ctx.GetFeature<ChatCommandRouter.Feature>();
|
|
||||||
await ApplyCost(getTypeName(routerFeature.CommandType), routerFeature.Succeded, uid, db, feature);
|
|
||||||
}
|
|
||||||
private string getTypeName(Type t)
|
|
||||||
{
|
|
||||||
return (t.DeclaringType == null ? t.Namespace + "." + t.Name : getTypeName(t.DeclaringType) + "." + t.Name)
|
|
||||||
+ (t.GenericTypeArguments.Length > 0 ? "<" + string.Join(",", t.GenericTypeArguments.Select(getTypeName)) + ">" : "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +1,12 @@
|
|||||||
using JetKarmaBot.Models;
|
using JetKarmaBot.Models;
|
||||||
|
using Perfusion;
|
||||||
|
|
||||||
namespace JetKarmaBot.Services;
|
namespace JetKarmaBot.Services
|
||||||
|
|
||||||
public class KarmaContextFactory
|
|
||||||
{
|
{
|
||||||
|
public class KarmaContextFactory
|
||||||
|
{
|
||||||
[Inject] IContainer C { get; set; }
|
[Inject] IContainer C { get; set; }
|
||||||
|
|
||||||
public KarmaContext GetContext() => C.GetInstance<KarmaContext>();
|
public KarmaContext GetContext() => C.GetInstance<KarmaContext>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,20 @@
|
|||||||
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using Perfusion;
|
||||||
|
|
||||||
namespace JetKarmaBot;
|
namespace JetKarmaBot
|
||||||
|
|
||||||
public class Localization : IReadOnlyDictionary<string, Locale>
|
|
||||||
{
|
{
|
||||||
|
public class Localization : IReadOnlyDictionary<string, Locale>
|
||||||
|
{
|
||||||
private Dictionary<string, Locale> locales = new Dictionary<string, Locale>();
|
private Dictionary<string, Locale> locales = new Dictionary<string, Locale>();
|
||||||
|
|
||||||
|
[Inject]
|
||||||
public Localization(IContainer c)
|
public Localization(IContainer c)
|
||||||
{
|
{
|
||||||
c.ResolveObject(this);
|
c.ResolveObject(this);
|
||||||
@ -105,9 +110,9 @@ public class Localization : IReadOnlyDictionary<string, Locale>
|
|||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
public class Locale : IReadOnlyDictionary<string, string>
|
public class Locale : IReadOnlyDictionary<string, string>
|
||||||
{
|
{
|
||||||
private Dictionary<string, string> locale;
|
private Dictionary<string, string> locale;
|
||||||
private string localeName;
|
private string localeName;
|
||||||
private string[] commonNames;
|
private string[] commonNames;
|
||||||
@ -132,7 +137,7 @@ public class Locale : IReadOnlyDictionary<string, string>
|
|||||||
|
|
||||||
public int Count => ((IReadOnlyDictionary<string, string>)locale).Count;
|
public int Count => ((IReadOnlyDictionary<string, string>)locale).Count;
|
||||||
|
|
||||||
public string this[string name] => locale.ContainsKey(name) ? locale[name] : "Unmapped locale key: " + name;
|
public string this[string name] => locale.ContainsKey(name) ? locale[name] : "unknown";
|
||||||
|
|
||||||
public bool ContainsKey(string key)
|
public bool ContainsKey(string key)
|
||||||
{
|
{
|
||||||
@ -153,14 +158,15 @@ public class Locale : IReadOnlyDictionary<string, string>
|
|||||||
{
|
{
|
||||||
return ((IReadOnlyDictionary<string, string>)locale).GetEnumerator();
|
return ((IReadOnlyDictionary<string, string>)locale).GetEnumerator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[System.Serializable]
|
[System.Serializable]
|
||||||
public class LocalizationException : Exception
|
public class LocalizationException : Exception
|
||||||
{
|
{
|
||||||
public LocalizationException() { }
|
public LocalizationException() { }
|
||||||
public LocalizationException(string message) : base(message) { }
|
public LocalizationException(string message) : base(message) { }
|
||||||
public LocalizationException(string message, Exception inner) : base(message, inner) { }
|
public LocalizationException(string message, Exception inner) : base(message, inner) { }
|
||||||
protected LocalizationException(
|
protected LocalizationException(
|
||||||
SerializationInfo info,
|
SerializationInfo info,
|
||||||
StreamingContext context) : base(info, context) { }
|
StreamingContext context) : base(info, context) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,11 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using Perfusion;
|
||||||
|
|
||||||
namespace JetKarmaBot;
|
namespace JetKarmaBot
|
||||||
|
|
||||||
public class LogInfo : ObjectInfo
|
|
||||||
{
|
{
|
||||||
public override ObjectInfo Clone() => new LogInfo();
|
public class LogInfo : ObjectInfo
|
||||||
|
{
|
||||||
public override object GetInstance(IContainer c, Type requester = null)
|
public override object GetInstance(IContainer c, Type requester = null)
|
||||||
{
|
{
|
||||||
return LogManager.GetLogger(requester != null ? getTypeName(requester) : "<type unspecified>");
|
return LogManager.GetLogger(requester != null ? getTypeName(requester) : "<type unspecified>");
|
||||||
@ -15,4 +16,5 @@ public class LogInfo : ObjectInfo
|
|||||||
return (t.DeclaringType == null ? t.Namespace + "." + t.Name : getTypeName(t.DeclaringType) + "." + t.Name)
|
return (t.DeclaringType == null ? t.Namespace + "." + t.Name : getTypeName(t.DeclaringType) + "." + t.Name)
|
||||||
+ (t.GenericTypeArguments.Length > 0 ? "<" + string.Join(",", t.GenericTypeArguments.Select(getTypeName)) + ">" : "");
|
+ (t.GenericTypeArguments.Length > 0 ? "<" + string.Join(",", t.GenericTypeArguments.Select(getTypeName)) + ">" : "");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,10 +1,12 @@
|
|||||||
|
using System;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using Perfusion;
|
||||||
|
|
||||||
namespace JetKarmaBot;
|
namespace JetKarmaBot
|
||||||
|
|
||||||
public class NLoggerFactory : ILoggerFactory
|
|
||||||
{
|
{
|
||||||
|
public class NLoggerFactory : ILoggerFactory
|
||||||
|
{
|
||||||
[Inject]
|
[Inject]
|
||||||
private NLoggerProvider c;
|
private NLoggerProvider c;
|
||||||
public void AddProvider(ILoggerProvider provider)
|
public void AddProvider(ILoggerProvider provider)
|
||||||
@ -16,9 +18,9 @@ public class NLoggerFactory : ILoggerFactory
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class NLoggerProvider : ILoggerProvider
|
public class NLoggerProvider : ILoggerProvider
|
||||||
{
|
{
|
||||||
[Inject]
|
[Inject]
|
||||||
private Container c;
|
private Container c;
|
||||||
|
|
||||||
@ -27,10 +29,10 @@ public class NLoggerProvider : ILoggerProvider
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LoggerVirtualizer : Microsoft.Extensions.Logging.ILogger
|
public class LoggerVirtualizer : Microsoft.Extensions.Logging.ILogger
|
||||||
{
|
{
|
||||||
private Logger logger;
|
private Logger logger;
|
||||||
|
|
||||||
public LoggerVirtualizer(Logger logger)
|
public LoggerVirtualizer(Logger logger)
|
||||||
@ -91,10 +93,11 @@ public class LoggerVirtualizer : Microsoft.Extensions.Logging.ILogger
|
|||||||
if (exception != null) logger.Log(getAppropriate(logLevel), exception, formatter(state, exception));
|
if (exception != null) logger.Log(getAppropriate(logLevel), exception, formatter(state, exception));
|
||||||
else logger.Log(getAppropriate(logLevel), state);
|
else logger.Log(getAppropriate(logLevel), state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class SomeDisposable : IDisposable
|
public class SomeDisposable : IDisposable
|
||||||
{
|
{
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -6,23 +6,21 @@
|
|||||||
],
|
],
|
||||||
"note": "This is a joke. And made with google translate.",
|
"note": "This is a joke. And made with google translate.",
|
||||||
"strings": {
|
"strings": {
|
||||||
"jetkarmabot.ratelimit": "Павольны, чувак!",
|
"jetkarmabot.award.errawardnoreply": "Калі ласка выкарыстоўвайце гэтую каманду ў адказе іншаму карыстальніку.",
|
||||||
"jetkarmabot.award.errawardnoreply": "Пра каго ты кажаш?",
|
|
||||||
"jetkarmabot.award.errbadusername": "Хто гэта?",
|
|
||||||
"jetkarmabot.award.errdup": "Калі ласка, спыніце батчіць ўзнагароды.",
|
|
||||||
"jetkarmabot.award.errawardself": "Хопіць з сабой гуляцца.",
|
"jetkarmabot.award.errawardself": "Хопіць з сабой гуляцца.",
|
||||||
"jetkarmabot.award.errawardbot": "Я бот, і мяне вашы нікчэмныя пузамеркі не вабяць.",
|
"jetkarmabot.award.errawardbot": "Я бот, і мяне вашы нікчэмныя пузамеркі не вабяць.",
|
||||||
"jetkarmabot.award.errrevokebot": "ಠ_ಠ",
|
"jetkarmabot.award.errrevokebot": "ಠ_ಠ",
|
||||||
"jetkarmabot.award.awardmessage": "Ўручыў \"{0}\" {1}!",
|
"jetkarmabot.award.awardmessage": "Ўручыў \"{0}\" {1}!",
|
||||||
"jetkarmabot.award.revokemessage": "Адабраў \"{0}\" у {1}!",
|
"jetkarmabot.award.revokemessage": "Адабраў \"{0}\" у {1}!",
|
||||||
"jetkarmabot.award.statustext": "У {0} цяпер {1}{2}.",
|
"jetkarmabot.award.statustext": "У {0} цяпер {1}{2}.",
|
||||||
|
"jetkarmabot.award.ratelimit": "Павольны, чувак!",
|
||||||
"jetkarmabot.award.help": "Уручае ачко карыстачу (або адымае)",
|
"jetkarmabot.award.help": "Уручае ачко карыстачу (або адымае)",
|
||||||
"jetkarmabot.award.awardtypehelp": "Тып ачкі",
|
"jetkarmabot.award.awardtypehelp": "Тып ачкі",
|
||||||
"jetkarmabot.award.tohelp": "Карыстальнік, якога ўзнагародзіць",
|
|
||||||
"jetkarmabot.status.listalltext": "У вас :",
|
"jetkarmabot.status.listalltext": "У вас :",
|
||||||
"jetkarmabot.status.listspecifictext": "У вас зараз {0}{1}.",
|
"jetkarmabot.status.listspecifictext": "У вас зараз {0}{1}.",
|
||||||
"jetkarmabot.status.havenothing": "У вас пакуль нічога няма.",
|
"jetkarmabot.status.havenothing": "У вас пакуль нічога няма.",
|
||||||
"jetkarmabot.status.help": "Паказвае справаздачу па ўзнагародах.",
|
"jetkarmabot.status.help": "Паказвае справаздачу па ўзнагародах.",
|
||||||
|
"jetkarmabot.status.awardtypehelp": "Тып ўзнагароды, па якой падасца справаздачу. Калі пуста, то падасца зводны справаздачу.",
|
||||||
"jetkarmabot.changelocale.justchanged": "Так дакладна.",
|
"jetkarmabot.changelocale.justchanged": "Так дакладна.",
|
||||||
"jetkarmabot.changelocale.getlocale": "Я зараз кажу па-беларускай.",
|
"jetkarmabot.changelocale.getlocale": "Я зараз кажу па-беларускай.",
|
||||||
"jetkarmabot.changelocale.listalltext": "Я ведаю:",
|
"jetkarmabot.changelocale.listalltext": "Я ведаю:",
|
||||||
@ -35,32 +33,17 @@
|
|||||||
"jetkarmabot.help.commandhelp": "Каманда, да якой трэба паказаць інструкцыю. Калі пуста, то паказваецца спіс каманд.",
|
"jetkarmabot.help.commandhelp": "Каманда, да якой трэба паказаць інструкцыю. Калі пуста, то паказваецца спіс каманд.",
|
||||||
"jetkarmabot.currencies.help": "Паказвае ўсе тыпы узнагарод",
|
"jetkarmabot.currencies.help": "Паказвае ўсе тыпы узнагарод",
|
||||||
"jetkarmabot.currencies.listtext": "Тыпы узнагарод:",
|
"jetkarmabot.currencies.listtext": "Тыпы узнагарод:",
|
||||||
"jetkarmabot.leaderboard.help": "Табліца лідэраў па колькасці ўзнагарод",
|
|
||||||
"jetkarmabot.leaderboard.awardtypehelp": "Тып ўзнагароды, па якой падасца справаздачу.",
|
|
||||||
"jetkarmabot.leaderboard.specifictext": "Перадавікі ў намінацыі \"{0}\":",
|
|
||||||
"jetkarmabot.awardtypes.nominative.star": "зорачка",
|
"jetkarmabot.awardtypes.nominative.star": "зорачка",
|
||||||
"jetkarmabot.awardtypes.nominative.pie": "з паліцы піражок",
|
"jetkarmabot.awardtypes.nominative.pie": "з паліцы піражок",
|
||||||
"jetkarmabot.awardtypes.nominative.dream": "мара",
|
"jetkarmabot.awardtypes.nominative.dream": "мара",
|
||||||
"jetkarmabot.awardtypes.nominative.banana": "стыкер-бананчык",
|
"jetkarmabot.awardtypes.nominative.banana": "стыкер-бананчык",
|
||||||
"jetkarmabot.awardtypes.nominative.determination": "DETERMINATION",
|
"jetkarmabot.awardtypes.nominative.determination": "DETERMINATION",
|
||||||
"jetkarmabot.awardtypes.nominative.raisin": "разынка",
|
"jetkarmabot.awardtypes.nominative.raisin": "разынка",
|
||||||
"jetkarmabot.awardtypes.nominative.touche": "touché",
|
|
||||||
"jetkarmabot.awardtypes.nominative.covid": "каронавірус",
|
|
||||||
"jetkarmabot.awardtypes.nominative.pony": "поніс",
|
|
||||||
"jetkarmabot.awardtypes.nominative.bellissimo": "беліссімо",
|
|
||||||
"jetkarmabot.awardtypes.nominative.based": "сярдзіта",
|
|
||||||
"jetkarmabot.awardtypes.nominative.redpill": "пілюля",
|
|
||||||
"jetkarmabot.awardtypes.accusative.star": "зорачку",
|
"jetkarmabot.awardtypes.accusative.star": "зорачку",
|
||||||
"jetkarmabot.awardtypes.accusative.pie": "з паліцы піражкі",
|
"jetkarmabot.awardtypes.accusative.pie": "з паліцы піражкі",
|
||||||
"jetkarmabot.awardtypes.accusative.dream": "мары",
|
"jetkarmabot.awardtypes.accusative.dream": "мары",
|
||||||
"jetkarmabot.awardtypes.accusative.banana": "стыкера-бананчыка",
|
"jetkarmabot.awardtypes.accusative.banana": "стыкера-бананчыка",
|
||||||
"jetkarmabot.awardtypes.accusative.determination": "DETERMINATION",
|
"jetkarmabot.awardtypes.accusative.determination": "DETERMINATION",
|
||||||
"jetkarmabot.awardtypes.accusative.raisin": "разыначкі",
|
"jetkarmabot.awardtypes.accusative.raisin": "разыначкі"
|
||||||
"jetkarmabot.awardtypes.accusative.touche": "touché",
|
|
||||||
"jetkarmabot.awardtypes.accusative.covid": "каронавірус",
|
|
||||||
"jetkarmabot.awardtypes.accusative.pony": "поніса",
|
|
||||||
"jetkarmabot.awardtypes.accusative.bellissimo": "беліссімо",
|
|
||||||
"jetkarmabot.awardtypes.accusative.based": "сярдзіта",
|
|
||||||
"jetkarmabot.awardtypes.accusative.redpill": "пілюлю"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,23 +5,21 @@
|
|||||||
"англійская"
|
"англійская"
|
||||||
],
|
],
|
||||||
"strings": {
|
"strings": {
|
||||||
"jetkarmabot.ratelimit": "Slow down there, turbo!",
|
"jetkarmabot.award.errawardnoreply": "Please use this command in reply to another user.",
|
||||||
"jetkarmabot.award.errawardnoreply": "Who are you talking about?",
|
|
||||||
"jetkarmabot.award.errbadusername": "I don't know who that is.",
|
|
||||||
"jetkarmabot.award.errdup": "Please stop batching awards.",
|
|
||||||
"jetkarmabot.award.errawardself": "Please stop playing with yourself.",
|
"jetkarmabot.award.errawardself": "Please stop playing with yourself.",
|
||||||
"jetkarmabot.award.errawardbot": "I am a bot, and have no use for your foolish fake internet points.",
|
"jetkarmabot.award.errawardbot": "I am a bot, and have no use for your foolish fake internet points.",
|
||||||
"jetkarmabot.award.errrevokebot": "ಠ_ಠ",
|
"jetkarmabot.award.errrevokebot": "ಠ_ಠ",
|
||||||
"jetkarmabot.award.awardmessage": "Awarded a {0} to {1}!",
|
"jetkarmabot.award.awardmessage": "Awarded a {0} to {1}!",
|
||||||
"jetkarmabot.award.revokemessage": "Revoked a {0} from {1}!",
|
"jetkarmabot.award.revokemessage": "Revoked a {0} from {1}!",
|
||||||
"jetkarmabot.award.statustext": "{0} is at {1}{2} now.",
|
"jetkarmabot.award.statustext": "{0} is at {1}{2} now.",
|
||||||
|
"jetkarmabot.award.ratelimit": "Slow down there, turbo!",
|
||||||
"jetkarmabot.award.help": "Awards/revokes an award to a user.",
|
"jetkarmabot.award.help": "Awards/revokes an award to a user.",
|
||||||
"jetkarmabot.award.awardtypehelp": "The award to grant to/strip of the specified user",
|
"jetkarmabot.award.awardtypehelp": "The award to grant to/strip of the specified user",
|
||||||
"jetkarmabot.award.tohelp": "The user to award",
|
|
||||||
"jetkarmabot.status.listalltext": "Your badges report:",
|
"jetkarmabot.status.listalltext": "Your badges report:",
|
||||||
"jetkarmabot.status.listspecifictext": "You are at {0}{1} now.",
|
"jetkarmabot.status.listspecifictext": "You are at {0}{1} now.",
|
||||||
"jetkarmabot.status.havenothing": "You don't have anything yet.",
|
"jetkarmabot.status.havenothing": "You don't have anything yet.",
|
||||||
"jetkarmabot.status.help": "Shows the amount of awards that you have",
|
"jetkarmabot.status.help": "Shows the amount of awards that you have",
|
||||||
|
"jetkarmabot.status.awardtypehelp": "The awardtype to show. If empty shows everything.",
|
||||||
"jetkarmabot.changelocale.justchanged": "Roger that.",
|
"jetkarmabot.changelocale.justchanged": "Roger that.",
|
||||||
"jetkarmabot.changelocale.getlocale": "I'm currently speaking English.",
|
"jetkarmabot.changelocale.getlocale": "I'm currently speaking English.",
|
||||||
"jetkarmabot.changelocale.listalltext": "I know:",
|
"jetkarmabot.changelocale.listalltext": "I know:",
|
||||||
@ -34,32 +32,17 @@
|
|||||||
"jetkarmabot.help.commandhelp": "The command to return help text for. If empty shows all commands.",
|
"jetkarmabot.help.commandhelp": "The command to return help text for. If empty shows all commands.",
|
||||||
"jetkarmabot.currencies.help": "Shows all award types",
|
"jetkarmabot.currencies.help": "Shows all award types",
|
||||||
"jetkarmabot.currencies.listtext": "Award types:",
|
"jetkarmabot.currencies.listtext": "Award types:",
|
||||||
"jetkarmabot.leaderboard.help": "Shows the people with the most of a specific award.",
|
|
||||||
"jetkarmabot.leaderboard.awardtypehelp": "The awardtype to show a leaderboard for.",
|
|
||||||
"jetkarmabot.leaderboard.specifictext": "Leaderboard for {0}:",
|
|
||||||
"jetkarmabot.awardtypes.nominative.star": "star",
|
"jetkarmabot.awardtypes.nominative.star": "star",
|
||||||
"jetkarmabot.awardtypes.nominative.pie": "pie from the shelf",
|
"jetkarmabot.awardtypes.nominative.pie": "pie from the shelf",
|
||||||
"jetkarmabot.awardtypes.nominative.dream": "dream",
|
"jetkarmabot.awardtypes.nominative.dream": "dream",
|
||||||
"jetkarmabot.awardtypes.nominative.banana": "banana sticker",
|
"jetkarmabot.awardtypes.nominative.banana": "banana sticker",
|
||||||
"jetkarmabot.awardtypes.nominative.determination": "DETERMINATION",
|
"jetkarmabot.awardtypes.nominative.determination": "DETERMINATION",
|
||||||
"jetkarmabot.awardtypes.nominative.raisin": "raisin",
|
"jetkarmabot.awardtypes.nominative.raisin": "raisin",
|
||||||
"jetkarmabot.awardtypes.nominative.touche": "touché",
|
|
||||||
"jetkarmabot.awardtypes.nominative.covid": "coronavirus",
|
|
||||||
"jetkarmabot.awardtypes.nominative.pony": "pony",
|
|
||||||
"jetkarmabot.awardtypes.nominative.bellissimo": "bellissimo",
|
|
||||||
"jetkarmabot.awardtypes.nominative.based": "based",
|
|
||||||
"jetkarmabot.awardtypes.nominative.redpill": "redpill",
|
|
||||||
"jetkarmabot.awardtypes.accusative.star": "star",
|
"jetkarmabot.awardtypes.accusative.star": "star",
|
||||||
"jetkarmabot.awardtypes.accusative.pie": "pie from the shelf",
|
"jetkarmabot.awardtypes.accusative.pie": "pie from the shelf",
|
||||||
"jetkarmabot.awardtypes.accusative.dream": "dream",
|
"jetkarmabot.awardtypes.accusative.dream": "dream",
|
||||||
"jetkarmabot.awardtypes.accusative.banana": "banana sticker",
|
"jetkarmabot.awardtypes.accusative.banana": "banana sticker",
|
||||||
"jetkarmabot.awardtypes.accusative.determination": "DETERMINATION",
|
"jetkarmabot.awardtypes.accusative.determination": "DETERMINATION",
|
||||||
"jetkarmabot.awardtypes.accusative.raisin": "raisin",
|
"jetkarmabot.awardtypes.accusative.raisin": "raisin"
|
||||||
"jetkarmabot.awardtypes.accusative.touche": "touché",
|
|
||||||
"jetkarmabot.awardtypes.accusative.covid": "coronavirus",
|
|
||||||
"jetkarmabot.awardtypes.accusative.pony": "pony",
|
|
||||||
"jetkarmabot.awardtypes.accusative.bellissimo": "bellissimo",
|
|
||||||
"jetkarmabot.awardtypes.accusative.based": "based",
|
|
||||||
"jetkarmabot.awardtypes.accusative.redpill": "redpill"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,23 +5,21 @@
|
|||||||
"руская"
|
"руская"
|
||||||
],
|
],
|
||||||
"strings": {
|
"strings": {
|
||||||
"jetkarmabot.ratelimit": "Помедленней, чувак!",
|
"jetkarmabot.award.errawardnoreply": "Пожалуйста используйте эту команду в ответе другому пользователю.",
|
||||||
"jetkarmabot.award.errawardnoreply": "О ком ты говоришь?",
|
|
||||||
"jetkarmabot.award.errbadusername": "Кто это?",
|
|
||||||
"jetkarmabot.award.errdup": "Пожалуйста, не батчайте награды.",
|
|
||||||
"jetkarmabot.award.errawardself": "Хватит с собой играться.",
|
"jetkarmabot.award.errawardself": "Хватит с собой играться.",
|
||||||
"jetkarmabot.award.errawardbot": "Я бот, и меня ваши жалкие пузомерки не интересуют.",
|
"jetkarmabot.award.errawardbot": "Я бот, и меня ваши жалкие пузомерки не интересуют.",
|
||||||
"jetkarmabot.award.errrevokebot": "ಠ_ಠ",
|
"jetkarmabot.award.errrevokebot": "ಠ_ಠ",
|
||||||
"jetkarmabot.award.awardmessage": "Вручил \"{0}\" {1}!",
|
"jetkarmabot.award.awardmessage": "Вручил \"{0}\" {1}!",
|
||||||
"jetkarmabot.award.revokemessage": "Отнял \"{0}\" у {1}!",
|
"jetkarmabot.award.revokemessage": "Отнял \"{0}\" у {1}!",
|
||||||
"jetkarmabot.award.statustext": "У {0} теперь {1}{2}.",
|
"jetkarmabot.award.statustext": "У {0} теперь {1}{2}.",
|
||||||
|
"jetkarmabot.award.ratelimit": "Помедленней, чувак!",
|
||||||
"jetkarmabot.award.help": "Вручает очко пользователю (или отнимает)",
|
"jetkarmabot.award.help": "Вручает очко пользователю (или отнимает)",
|
||||||
"jetkarmabot.award.awardtypehelp": "Тип очка",
|
"jetkarmabot.award.awardtypehelp": "Тип очка",
|
||||||
"jetkarmabot.award.tohelp": "Пользователь, которого наградить",
|
|
||||||
"jetkarmabot.status.listalltext": "У вас :",
|
"jetkarmabot.status.listalltext": "У вас :",
|
||||||
"jetkarmabot.status.listspecifictext": "У вас сейчас {0}{1}.",
|
"jetkarmabot.status.listspecifictext": "У вас сейчас {0}{1}.",
|
||||||
"jetkarmabot.status.havenothing": "У вас пока ничего нет.",
|
"jetkarmabot.status.havenothing": "У вас пока ничего нет.",
|
||||||
"jetkarmabot.status.help": "Показывает отчет по наградам.",
|
"jetkarmabot.status.help": "Показывает отчет по наградам.",
|
||||||
|
"jetkarmabot.status.awardtypehelp": "Тип награды, по которой покажется отчет. Если пусто, то покажется сводный отчет.",
|
||||||
"jetkarmabot.changelocale.justchanged": "Так точно.",
|
"jetkarmabot.changelocale.justchanged": "Так точно.",
|
||||||
"jetkarmabot.changelocale.getlocale": "Я сейчас говорю по-русски.",
|
"jetkarmabot.changelocale.getlocale": "Я сейчас говорю по-русски.",
|
||||||
"jetkarmabot.changelocale.listalltext": "Я знаю:",
|
"jetkarmabot.changelocale.listalltext": "Я знаю:",
|
||||||
@ -34,32 +32,17 @@
|
|||||||
"jetkarmabot.help.commandhelp": "Команда, к которой нужно показать инструкцию. Если пусто, то показывается список команд.",
|
"jetkarmabot.help.commandhelp": "Команда, к которой нужно показать инструкцию. Если пусто, то показывается список команд.",
|
||||||
"jetkarmabot.currencies.help": "Показывает все типы наград",
|
"jetkarmabot.currencies.help": "Показывает все типы наград",
|
||||||
"jetkarmabot.currencies.listtext": "Типы наград:",
|
"jetkarmabot.currencies.listtext": "Типы наград:",
|
||||||
"jetkarmabot.leaderboard.help": "Таблица лидеров по количеству наград",
|
|
||||||
"jetkarmabot.leaderboard.awardtypehelp": "Тип награды, по которой покажется отчет.",
|
|
||||||
"jetkarmabot.leaderboard.specifictext": "Передовики в номинации \"{0}\":",
|
|
||||||
"jetkarmabot.awardtypes.nominative.star": "звездочка",
|
"jetkarmabot.awardtypes.nominative.star": "звездочка",
|
||||||
"jetkarmabot.awardtypes.nominative.pie": "с полки пирожок",
|
"jetkarmabot.awardtypes.nominative.pie": "с полки пирожок",
|
||||||
"jetkarmabot.awardtypes.nominative.dream": "мечта",
|
"jetkarmabot.awardtypes.nominative.dream": "мечта",
|
||||||
"jetkarmabot.awardtypes.nominative.banana": "стикер-бананчик",
|
"jetkarmabot.awardtypes.nominative.banana": "стикер-бананчик",
|
||||||
"jetkarmabot.awardtypes.nominative.determination": "РЕШИТЕЛЬНОСТЬ",
|
"jetkarmabot.awardtypes.nominative.determination": "РЕШИТЕЛЬНОСТЬ",
|
||||||
"jetkarmabot.awardtypes.nominative.raisin": "изюм",
|
"jetkarmabot.awardtypes.nominative.raisin": "изюм",
|
||||||
"jetkarmabot.awardtypes.nominative.touche": "touché",
|
|
||||||
"jetkarmabot.awardtypes.nominative.covid": "коронавирус",
|
|
||||||
"jetkarmabot.awardtypes.nominative.pony": "понис",
|
|
||||||
"jetkarmabot.awardtypes.nominative.bellissimo": "белиссимо",
|
|
||||||
"jetkarmabot.awardtypes.nominative.based": "сердито",
|
|
||||||
"jetkarmabot.awardtypes.nominative.redpill": "пилюля",
|
|
||||||
"jetkarmabot.awardtypes.accusative.star": "звездочку",
|
"jetkarmabot.awardtypes.accusative.star": "звездочку",
|
||||||
"jetkarmabot.awardtypes.accusative.pie": "с полки пирожок",
|
"jetkarmabot.awardtypes.accusative.pie": "с полки пирожок",
|
||||||
"jetkarmabot.awardtypes.accusative.dream": "мечту",
|
"jetkarmabot.awardtypes.accusative.dream": "мечту",
|
||||||
"jetkarmabot.awardtypes.accusative.banana": "стикер-бананчик",
|
"jetkarmabot.awardtypes.accusative.banana": "стикер-бананчик",
|
||||||
"jetkarmabot.awardtypes.accusative.determination": "РЕШИТЕЛЬНОСТЬ",
|
"jetkarmabot.awardtypes.accusative.determination": "РЕШИТЕЛЬНОСТЬ",
|
||||||
"jetkarmabot.awardtypes.accusative.raisin": "изюм",
|
"jetkarmabot.awardtypes.accusative.raisin": "изюм"
|
||||||
"jetkarmabot.awardtypes.accusative.touche": "touché",
|
|
||||||
"jetkarmabot.awardtypes.accusative.covid": "коронавирус",
|
|
||||||
"jetkarmabot.awardtypes.accusative.pony": "пониса",
|
|
||||||
"jetkarmabot.awardtypes.accusative.bellissimo": "белиссимо",
|
|
||||||
"jetkarmabot.awardtypes.accusative.based": "сердито",
|
|
||||||
"jetkarmabot.awardtypes.accusative.redpill": "пилюлю"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
41
karma.sql
41
karma.sql
@ -1,41 +0,0 @@
|
|||||||
-- Example JetKarmaBot database
|
|
||||||
-- (taken from mysqldump)
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `awardtype`;
|
|
||||||
CREATE TABLE `awardtype` (
|
|
||||||
`awardtypeid` tinyint(3) NOT NULL PRIMARY KEY,
|
|
||||||
`commandname` varchar(35) NOT NULL UNIQUE,
|
|
||||||
`name` varchar(32) NOT NULL,
|
|
||||||
`symbol` varchar(16) NOT NULL,
|
|
||||||
`description` text NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
LOCK TABLES `awardtype` WRITE;
|
|
||||||
INSERT INTO `awardtype` VALUES (1,'example','Example','Examples','An example');
|
|
||||||
UNLOCK TABLES;
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `chat`;
|
|
||||||
CREATE TABLE `chat` (
|
|
||||||
`chatid` bigint(20) NOT NULL PRIMARY KEY,
|
|
||||||
`locale` varchar(10) NOT NULL DEFAULT 'ru-RU',
|
|
||||||
`isadministrator` tinyint(1) NOT NULL DEFAULT 0
|
|
||||||
);
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `user`;
|
|
||||||
CREATE TABLE `user` (
|
|
||||||
`userid` bigint(20) NOT NULL,
|
|
||||||
`username` varchar(45) DEFAULT NULL,
|
|
||||||
`cooldowndate` timestamp NOT NULL DEFAULT current_timestamp(),
|
|
||||||
PRIMARY KEY (`userid`)
|
|
||||||
);
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `award`;
|
|
||||||
CREATE TABLE `award` (
|
|
||||||
`awardid` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
`chatid` bigint(20) NOT NULL REFERENCES `chat` (`chatid`),
|
|
||||||
`fromid` bigint(20) NOT NULL REFERENCES `user` (`userid`),
|
|
||||||
`toid` bigint(20) NOT NULL REFERENCES `user` (`userid`),
|
|
||||||
`awardtypeid` tinyint(3) NOT NULL REFERENCES `awardtype` (`awardtypeid`),
|
|
||||||
`amount` tinyint(3) NOT NULL DEFAULT 1,
|
|
||||||
`date` datetime NOT NULL DEFAULT current_timestamp()
|
|
||||||
);
|
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 115f59eecb2a4a74c63770866539502cde28d881
|
Subproject commit 40e8f8871f42f1f32c29480505cf5ac6ba61c393
|
||||||
Loading…
Reference in New Issue
Block a user