Ajout d'une base sqlite, gestion des réactions directes ou sur commandes blame/reward, ajout de tops sur périodes, ...

This commit is contained in:
Christophe Chailloleau-Leclerc 2019-05-29 22:50:41 +02:00
parent e75cb67fe7
commit e97e40e7f3
14 changed files with 645 additions and 65 deletions

1
.gitignore vendored
View File

@ -338,3 +338,4 @@ ASALocalRun/
# BeatPulse healthcheck temp database # BeatPulse healthcheck temp database
healthchecksdb healthchecksdb
/Sean/Sean.db

View File

@ -1,8 +1,13 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using Sean.Models;
using Sean.Services;
using System; using System;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Sean namespace Sean
@ -31,6 +36,50 @@ namespace Sean
_client.MessageReceived += HandleCommandAsync; _client.MessageReceived += HandleCommandAsync;
_client.ReactionAdded += HandleReactionAddedAsync; _client.ReactionAdded += HandleReactionAddedAsync;
_client.ReactionRemoved += HandleReactionRemovedAsync; _client.ReactionRemoved += HandleReactionRemovedAsync;
_client.Ready += _client_Ready;
_client.ChannelCreated += _client_ChannelCreated;
_client.ChannelDestroyed += _client_ChannelDestroyed;
_client.ChannelUpdated += _client_ChannelUpdated;
_client.Connected += _client_Connected;
_client.CurrentUserUpdated += _client_CurrentUserUpdated;
_client.Disconnected += _client_Disconnected;
_client.GuildAvailable += _client_GuildAvailable;
_client.GuildMembersDownloaded += _client_GuildMembersDownloaded;
_client.GuildMemberUpdated += _client_GuildMemberUpdated;
_client.GuildUnavailable += _client_GuildUnavailable;
_client.GuildUpdated += _client_GuildUpdated;
_client.JoinedGuild += _client_JoinedGuild;
_client.LatencyUpdated += _client_LatencyUpdated;
_client.LeftGuild += _client_LeftGuild;
_client.LoggedIn += _client_LoggedIn;
_client.LoggedOut += _client_LoggedOut;
_client.MessageDeleted += _client_MessageDeleted;
_client.MessagesBulkDeleted += _client_MessagesBulkDeleted;
_client.MessageUpdated += _client_MessageUpdated;
_client.ReactionsCleared += _client_ReactionsCleared;
_client.RecipientAdded += _client_RecipientAdded;
_client.RecipientRemoved += _client_RecipientRemoved;
_client.RoleCreated += _client_RoleCreated;
_client.RoleDeleted += _client_RoleDeleted;
_client.RoleUpdated += _client_RoleUpdated;
_client.UserBanned += _client_UserBanned;
_client.UserIsTyping += _client_UserIsTyping;
_client.UserJoined += _client_UserJoined;
_client.UserLeft += _client_UserLeft;
_client.UserUnbanned += _client_UserUnbanned;
_client.UserUpdated += _client_UserUpdated;
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
_client.VoiceServerUpdated += _client_VoiceServerUpdated;
// Here we discover all of the command modules in the entry // Here we discover all of the command modules in the entry
// assembly and load them. Starting from Discord.NET 2.0, a // assembly and load them. Starting from Discord.NET 2.0, a
@ -44,8 +93,118 @@ namespace Sean
services: _services); services: _services);
} }
private Task _client_VoiceServerUpdated(SocketVoiceServer arg) => LogMe();
private Task _client_UserVoiceStateUpdated(SocketUser arg1, SocketVoiceState arg2, SocketVoiceState arg3) => LogMe();
private Task _client_UserUpdated(SocketUser arg1, SocketUser arg2) => LogMe(message: $"Avant : {arg1}, après : {arg2}");
private Task _client_UserUnbanned(SocketUser arg1, SocketGuild arg2) => LogMe();
private Task _client_UserLeft(SocketGuildUser arg) => LogMe();
private Task _client_UserJoined(SocketGuildUser arg) => LogMe();
private Task _client_UserIsTyping(SocketUser arg1, ISocketMessageChannel arg2) => LogMe();
private Task _client_UserBanned(SocketUser arg1, SocketGuild arg2) => LogMe();
private Task _client_RoleUpdated(SocketRole arg1, SocketRole arg2) => LogMe();
private Task _client_RoleDeleted(SocketRole arg) => LogMe();
private Task _client_RoleCreated(SocketRole arg) => LogMe();
private Task _client_RecipientRemoved(SocketGroupUser arg) => LogMe();
private Task _client_RecipientAdded(SocketGroupUser arg) => LogMe();
private Task _client_ReactionsCleared(Cacheable<IUserMessage, ulong> arg1, ISocketMessageChannel arg2) => LogMe();
private Task _client_MessageUpdated(Cacheable<IMessage, ulong> arg1, SocketMessage arg2, ISocketMessageChannel arg3) => LogMe();
private Task _client_MessagesBulkDeleted(System.Collections.Generic.IReadOnlyCollection<Cacheable<IMessage, ulong>> arg1, ISocketMessageChannel arg2) => LogMe();
private Task _client_MessageDeleted(Cacheable<IMessage, ulong> arg1, ISocketMessageChannel arg2) => LogMe();
private Task _client_LoggedOut() => LogMe();
private Task _client_LoggedIn() => LogMe();
private Task _client_LeftGuild(SocketGuild arg) => LogMe();
private Task _client_LatencyUpdated(int arg1, int arg2) => LogMe();
private Task _client_JoinedGuild(SocketGuild arg) => LogMe();
private Task _client_GuildUpdated(SocketGuild arg1, SocketGuild arg2) => LogMe();
private Task _client_GuildUnavailable(SocketGuild arg) => LogMe();
private async Task _client_GuildMemberUpdated(SocketGuildUser arg1, SocketGuildUser arg2)
{
await LogMe();
//message: $"Avant : {arg1.Id} - {arg1.Nickname}, après : {arg2.Id} - {arg2.Nickname}");
// if (arg1.Nickname != arg2.Nickname)
// {
// IDMChannel chan = await arg2.GetOrCreateDMChannelAsync();
// await chan.SendMessageAsync("Bien essayé petit malin, tu crois qu'on ne te reconnaîtra pas ? :-P");
// }
}
private async Task UpdateUserAsync(SocketGuildUser user)
{
DbService db = _services.GetService(typeof(DbService)) as DbService;
ScoreUtilisateur score = await db.Scores.SingleOrDefaultAsync(s => s.UserId == user.Id && s.Date == DateTime.Today);
if (score == default)
{
score = new ScoreUtilisateur { UserId = user.Id, Date = DateTime.Today, Name = user.Nick(), Score = 0 };
await db.Scores.AddAsync(score);
}
else
{
if (score.Name != user.Nick())
score.Name = user.Nick();
}
await db.SaveChangesAsync();
}
private async Task _client_GuildMembersDownloaded(SocketGuild arg)
{
await LogMe();
foreach (SocketGuildUser user in arg.Users)
{
await UpdateUserAsync(user);
}
}
private Task _client_GuildAvailable(SocketGuild arg) => LogMe();
private Task _client_Disconnected(Exception arg) => LogMe();
private Task _client_CurrentUserUpdated(SocketSelfUser arg1, SocketSelfUser arg2) => LogMe();
private Task _client_Connected() => LogMe();
private Task _client_ChannelUpdated(SocketChannel arg1, SocketChannel arg2) => LogMe();
private Task _client_ChannelDestroyed(SocketChannel arg) => LogMe();
private Task _client_ChannelCreated(SocketChannel arg) => LogMe();
private Task LogMe([CallerMemberName] string name = "", string message = "called")
{
Console.WriteLine($"{name} : {message}"); return Task.CompletedTask;
}
private async Task _client_Ready()
{
await LogMe();
foreach (SocketGuild g in _client.Guilds)
{
foreach (SocketTextChannel c in g.TextChannels)
{
await c.SendMessageAsync("I'm back !");
}
}
}
private async Task HandleCommandAsync(SocketMessage messageParam) private async Task HandleCommandAsync(SocketMessage messageParam)
{ {
await LogMe();
// Don't process the command if it was a system message // Don't process the command if it was a system message
var message = messageParam as SocketUserMessage; var message = messageParam as SocketUserMessage;
if (message == null) return; if (message == null) return;
@ -79,13 +238,161 @@ namespace Sean
// if (!result.IsSuccess) // if (!result.IsSuccess)
// await context.Channel.SendMessageAsync(result.ErrorReason); // await context.Channel.SendMessageAsync(result.ErrorReason);
} }
private bool IsBlame(IMessage m) => m.Content.StartsWith("!blame") || m.Content.StartsWith("!bash");
private bool IsReward(IMessage m) => m.Content.StartsWith("!great") || m.Content.StartsWith("!reward");
private async Task HandleReactionAddedAsync(Cacheable<IUserMessage, ulong> message, ISocketMessageChannel channel, SocketReaction reaction) private async Task HandleReactionAddedAsync(Cacheable<IUserMessage, ulong> message, ISocketMessageChannel channel, SocketReaction reaction)
{ {
await channel.SendMessageAsync($"Ajout de {reaction.Emote.Name}"); await LogMe();
DbService db = _services.GetService(typeof(DbService)) as DbService;
IMessage m = message.HasValue ? message.Value : await channel.GetMessageAsync(message.Id);
if (reaction.Emote.Name == "👍")
{
if (reaction.User.Value != m.Author)
{
if (IsBlame(m))
{
foreach (ulong id in m.MentionedUserIds)
{
IUser userMentionne = await channel.GetUserAsync(id);
await db.UpdateScore(userMentionne, -1);
}
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} n'a pas aimé non plus !");
}
else if (IsReward(m))
{
foreach (ulong id in m.MentionedUserIds)
{
IUser userMentionne = await channel.GetUserAsync(id);
await db.UpdateScore(userMentionne, 1);
}
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} valide aussi !");
}
else
{
await db.UpdateScore(m.Author, 1);
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} fayotte envers {m.Author.Nick()}");
}
}
else
{
await db.UpdateScore(m.Author, -1);
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} voudrait s'auto-congratuler... Désolé, ce sera une punition !");
}
}
else if (reaction.Emote.Name == "👎")
{
if (reaction.User.Value != m.Author)
{
if (IsBlame(m))
{
foreach (ulong id in m.MentionedUserIds)
{
IUser userMentionne = await channel.GetUserAsync(id);
await db.UpdateScore(userMentionne, 1);
}
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} n'est pas d'accord !");
}
else if (IsReward(m))
{
foreach (ulong id in m.MentionedUserIds)
{
IUser userMentionne = await channel.GetUserAsync(id);
await db.UpdateScore(userMentionne, -1);
}
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} n'a pas apprécié, lui !");
}
else
{
await db.UpdateScore(m.Author, -1);
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} a quelque chose contre {m.Author.Nick()}");
}
}
else
{
await db.UpdateScore(m.Author, -1);
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} aime l'auto-flagellation...");
}
}
} }
private async Task HandleReactionRemovedAsync(Cacheable<IUserMessage, ulong> message, ISocketMessageChannel channel, SocketReaction reaction) private async Task HandleReactionRemovedAsync(Cacheable<IUserMessage, ulong> message, ISocketMessageChannel channel, SocketReaction reaction)
{ {
await channel.SendMessageAsync($"Retrait de {reaction.Emote.Name}"); await LogMe();
IUser userReaction = reaction.User.IsSpecified ? reaction.User.Value : await channel.GetUserAsync(reaction.UserId);
IMessage m = message.HasValue ? message.Value : await channel.GetMessageAsync(message.Id);
DbService db = _services.GetService(typeof(DbService)) as DbService;
if (reaction.Emote.Name == "👍")
{
if (userReaction != m.Author)
{
if (IsBlame(m))
{
foreach (ulong id in m.MentionedUserIds)
{
IUser userMentionne = await channel.GetUserAsync(id);
await db.UpdateScore(userMentionne, 1);
}
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} n'était pas vraiment pour la punition, en fait...");
}
else if (IsReward(m))
{
foreach (ulong id in m.MentionedUserIds)
{
IUser userMentionne = await channel.GetUserAsync(id);
await db.UpdateScore(userMentionne, -1);
}
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} n'approuve pas, finalement !");
}
else
{
await db.UpdateScore(m.Author, -1);
await channel.SendMessageAsync($"{userReaction.Nick()} n'assume pas sa gentillesse envers {m.Author.Nick()}");
}
}
else
{
await channel.SendMessageAsync($"{userReaction.Nick()} bien essayé, mais la punition est déjà tombée !");
}
}
else if (reaction.Emote.Name == "👎")
{
if (reaction.User.Value != m.Author)
{
if (IsBlame(m))
{
foreach (ulong id in m.MentionedUserIds)
{
IUser userMentionne = await channel.GetUserAsync(id);
await db.UpdateScore(userMentionne, -1);
}
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} ne désapprouve plus vraiment...");
}
else if (IsReward(m))
{
foreach (ulong id in m.MentionedUserIds)
{
IUser userMentionne = await channel.GetUserAsync(id);
await db.UpdateScore(userMentionne, 1);
}
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} a peut êre un peu apprécié, finalement...");
}
else
{
await db.UpdateScore(m.Author, 1);
await channel.SendMessageAsync($"{reaction.User.Value.Nick()} n'assume pas sa méchanceté contre {m.Author.Nick()}");
}
}
else
{
await channel.SendMessageAsync($"{userReaction.Nick()} trop tard pour réfléchir... Encore quelques coups de fouet ?");
}
}
} }
#endregion Methods #endregion Methods
} }

View File

@ -0,0 +1,38 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sean.Services;
namespace Sean.Migrations
{
[DbContext(typeof(DbService))]
[Migration("20190529160453_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.4-servicing-10062");
modelBuilder.Entity("Sean.Models.ScoreUtilisateur", b =>
{
b.Property<ulong>("UserId");
b.Property<DateTime>("Date");
b.Property<string>("Name");
b.Property<int>("Score");
b.HasKey("UserId", "Date");
b.ToTable("Scores");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Sean.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Scores",
columns: table => new
{
UserId = table.Column<ulong>(nullable: false),
Date = table.Column<DateTime>(nullable: false),
Score = table.Column<int>(nullable: false),
Name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Scores", x => new { x.UserId, x.Date });
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Scores");
}
}
}

View File

@ -0,0 +1,36 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Sean.Services;
namespace Sean.Migrations
{
[DbContext(typeof(DbService))]
partial class DbServiceModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.4-servicing-10062");
modelBuilder.Entity("Sean.Models.ScoreUtilisateur", b =>
{
b.Property<ulong>("UserId");
b.Property<DateTime>("Date");
b.Property<string>("Name");
b.Property<int>("Score");
b.HasKey("UserId", "Date");
b.ToTable("Scores");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Sean.Models
{
public class ScoreUtilisateur
{
public ulong UserId { get; set; }
public DateTime Date { get; set; }
public int Score { get; set; }
public string Name { get; set; }
}
}

View File

@ -1,41 +1,99 @@
using Discord.Commands; using Discord;
using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using Microsoft.EntityFrameworkCore;
using Sean.Models;
using Sean.Services; using Sean.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Sean.Modules namespace Sean.Modules
{ {
[RequireContext(ContextType.Guild)]
public class AwardsModule : ModuleBase<SocketCommandContext> public class AwardsModule : ModuleBase<SocketCommandContext>
{ {
#region Properties #region Properties
public AwardsPersistencyService persistencyService { get; set; } public DbService dbService { get; set; }
#endregion Properties #endregion Properties
#region Methods #region Methods
[Command("blame")] [Command("blame")]
[Summary("Blames the user and removes him one point")] [Summary("Blames the user and removes him one point")]
[Alias("bash")] [Alias("bash")]
public async Task BlameUserAsync([Summary("The user to blame")] SocketUser user) public async Task BlameUserAsync([Summary("The user to blame")] SocketUser user, [Remainder]string commentaire = "")
{ {
var userInfo = user; await dbService.UpdateScore(user, -1);
int score = persistencyService.RemovePoint(user); if (user == Context.User)
await ReplyAsync($"Nice job {userInfo.Username}#{userInfo.Discriminator}, your score is now {score}"); await ReplyAsync($"{Context.User.Nick()} aime l'auto-flagellation...");
else
await ReplyAsync($"{Context.User.Nick()} a quelque chose contre {user.Nick()}");
} }
[Command("board")] [Command("board")]
[Summary("Give the leader board")] [Summary("Give the leader board")]
[Alias("top")] [Alias("top")]
public async Task BoardAsync() public async Task BoardAsync([Remainder] string portee = "")
{ {
await ReplyAsync(persistencyService.LeaderBoard()); string duree = string.Empty;
DateTime depuis;
switch (portee)
{
case "week": duree = "de la semaine"; depuis = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek); break;
case "month": duree = "du mois"; depuis = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1); break;
case "year": duree = "de l'année"; depuis = new DateTime(DateTime.Now.Year, 1, 1); break;
case "ever": duree = "de tous les temps"; depuis = DateTime.MinValue; break;
default: duree = "du jour"; depuis = DateTime.Today; break;
} }
EmbedBuilder builder = new EmbedBuilder
{
Title = $"Le top des nazes {duree} !",
ThumbnailUrl = "https://icon-icons.com/descargaimagen.php?id=62269&root=716/PNG/512/&file=Cup_icon-icons.com_62269.png"
};
builder.Footer = new EmbedFooterBuilder { Text = "Allez, au boulot, on peut encore faire pire !" };
int place = 1;
var liste = await dbService.Scores.Where(s => s.Date >= depuis).GroupBy(s => s.Score).OrderByDescending(s => s.Key).ToListAsync();
foreach (var groupe in liste)
{
string nom = string.Empty;
if (place == 1) nom += ":first_place: ";
else if (place == 2) nom += ":second_place: ";
else if (place == 3) nom += ":third_place: ";
else if (place == liste.Count) nom += ":poop: ";
nom += string.Join(", ", groupe.Select(g => g.Name));
builder.AddField(nom, groupe.Key, true);
place++;
}
await ReplyAsync(embed: builder.Build());
}
[Command("great")] [Command("great")]
[Summary("Greats the user and give him one point")] [Summary("Greats the user and give him one point")]
[Alias("reward")] [Alias("reward")]
public async Task GreatUserAsync([Summary("The user to great")] SocketUser user) public async Task GreatUserAsync([Summary("The user to great")] SocketUser user, [Remainder]string commentaire = "")
{ {
var userInfo = user; if (user != Context.User)
int score = persistencyService.AddPoint(user); {
await ReplyAsync($"{userInfo.Username}#{userInfo.Discriminator} have now a score of {score}"); await dbService.UpdateScore(user, 1);
await ReplyAsync($"{Context.User.Nick()} fayotte envers {user.Nick()}");
}
else
{
await dbService.UpdateScore(user, -1);
await ReplyAsync($"{Context.User.Nick()} voudrait s'auto-congratuler... Désolé, ce sera une punition !");
}
}
[Command("help")]
[Summary("Help !")]
public async Task HelpAsync()
{
IDMChannel channel = await Context.User.GetOrCreateDMChannelAsync();
await channel.SendMessageAsync($"D'après le site wikipedia.fr, Help! est une chanson des Beatles parue en single en juillet 1965, puis utilisée comme chanson-titre de leur cinquième album et du film dont ils sont les vedettes... Oh, tu m'as pris pour l'assistant Google ?");
} }
#endregion Methods #endregion Methods
} }

37
Sean/Modules/DMModule.cs Normal file
View File

@ -0,0 +1,37 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using Sean.Services;
using System;
using System.Threading.Tasks;
namespace Sean.Modules
{
[RequireContext(ContextType.DM)]
public class DMModule : ModuleBase<SocketCommandContext>
{
#region Methods
[Command("echo")]
[Summary("Echoes parameter")]
[Alias("say")]
public async Task EchoAsync([Summary("The text to echo")] [Remainder]string text)
{
await ReplyAsync(text);
}
[Command("exit")]
[Summary("Quit")]
[Alias("quit")]
public async Task ExitAsync()
{
foreach (SocketGuild guild in Context.Client.Guilds)
{
await guild.DefaultChannel.SendMessageAsync("Ciao les nazes !");
}
await Context.Client.StopAsync();
}
#endregion Methods
}
}

View File

@ -1,4 +1,5 @@
using Discord.Commands; using Discord;
using Discord.Commands;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Sean.Modules namespace Sean.Modules
@ -9,6 +10,16 @@ namespace Sean.Modules
[Command("ping")] [Command("ping")]
[Summary("Ping pong !")] [Summary("Ping pong !")]
public Task PongAsync() => ReplyAsync("Pong !"); public Task PongAsync() => ReplyAsync("Pong !");
[Command("hey")]
[Summary("Asks for a private channel with the bot")]
[Alias("listen")]
public async Task HeyAsync()
{
IDMChannel channel = await Context.User.GetOrCreateDMChannelAsync();
await channel.SendMessageAsync("Your command, master ?");
await ReplyAsync("Jude !");
}
#endregion Methods #endregion Methods
} }
} }

View File

@ -3,6 +3,7 @@ using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Sean.Services; using Sean.Services;
using Sentry;
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -24,7 +25,7 @@ namespace Sean
.AddSingleton(client) .AddSingleton(client)
.AddSingleton(commandService) .AddSingleton(commandService)
.AddSingleton<CommandHandler>() .AddSingleton<CommandHandler>()
.AddSingleton<AwardsPersistencyService>() .AddSingleton<DbService>()
.BuildServiceProvider(); .BuildServiceProvider();
public async Task MainAsync() public async Task MainAsync()
{ {
@ -35,7 +36,7 @@ namespace Sean
}; };
commandService = new CommandService(commandServiceConfig); commandService = new CommandService(commandServiceConfig);
client = new DiscordSocketClient(); client = new DiscordSocketClient(new DiscordSocketConfig { MessageCacheSize = 100, AlwaysDownloadUsers = true/*, LogLevel = LogSeverity.Debug */});
client.Log += Log; client.Log += Log;
IServiceProvider provider = BuildServiceProvider(); IServiceProvider provider = BuildServiceProvider();
@ -46,11 +47,32 @@ namespace Sean
await client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("DiscordToken_Sean")); await client.LoginAsync(TokenType.Bot, Environment.GetEnvironmentVariable("DiscordToken_Sean"));
await client.StartAsync(); await client.StartAsync();
client.Disconnected += Client_Disconnected;
// Block this task until the program is closed. // Block this task until the program is closed.
await Task.Delay(-1); await Task.Delay(-1);
} }
private Task Client_Disconnected(Exception arg)
{
Environment.Exit(0);
return Task.CompletedTask;
}
private static void Main(string[] args) private static void Main(string[] args)
=> new Program().MainAsync().GetAwaiter().GetResult(); {
using (SentrySdk.Init(Environment.GetEnvironmentVariable("SentryURL_Sean")))
{
try
{
new Program().MainAsync().GetAwaiter().GetResult();
}
catch (Exception e)
{
SentrySdk.CaptureException(e);
}
}
}
private Task Log(LogMessage msg) private Task Log(LogMessage msg)
{ {
Console.WriteLine(msg.ToString()); Console.WriteLine(msg.ToString());

View File

@ -1,12 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.2</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Discord.Net" Version="2.1.0" /> <PackageReference Include="Discord.Net" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.4" />
<PackageReference Include="Sentry" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<None Update="Sean.db">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,44 +0,0 @@
using Discord;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Sean.Services
{
public class AwardsPersistencyService
{
#region Fields
private Dictionary<string, int> scores = new Dictionary<string, int>();
#endregion Fields
#region Methods
public int AddPoint(IUser user)
{
if (!scores.ContainsKey($"{user.Username}#{user.Discriminator}"))
scores.Add($"{user.Username}#{user.Discriminator}", 1);
else
scores[$"{user.Username}#{user.Discriminator}"]++;
return scores[$"{user.Username}#{user.Discriminator}"];
}
public string LeaderBoard()
{
string board = string.Empty;
foreach (KeyValuePair<string, int> score in scores.OrderByDescending(s => s.Value))
{
board += $@"{score.Key} => {score.Value}" + Environment.NewLine;
}
return board;
}
public int RemovePoint(IUser user)
{
if (!scores.ContainsKey($"{user.Username}#{user.Discriminator}"))
scores.Add($"{user.Username}#{user.Discriminator}", -1);
else
scores[$"{user.Username}#{user.Discriminator}"]--;
return scores[$"{user.Username}#{user.Discriminator}"];
}
#endregion Methods
}
}

View File

@ -0,0 +1,42 @@
using Discord;
using Microsoft.EntityFrameworkCore;
using Sean.Models;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Sean.Services
{
public class DbService : DbContext
{
public DbSet<ScoreUtilisateur> Scores { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=Sean.db");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ScoreUtilisateur>()
.HasKey(o => new { o.UserId, o.Date });
}
public async Task UpdateScore(IUser user, int change)
{
ScoreUtilisateur score = await Scores.SingleOrDefaultAsync(s => s.UserId == user.Id && s.Date == DateTime.Today);
if (score == default)
{
score = new ScoreUtilisateur { UserId = user.Id, Date = DateTime.Today, Score = change, Name = user.Nick() };
await Scores.AddAsync(score);
}
else
score.Score += change;
await SaveChangesAsync();
}
}
}

17
Sean/UserExtensions.cs Normal file
View File

@ -0,0 +1,17 @@
using Discord;
using System;
using System.Collections.Generic;
using System.Text;
namespace Sean
{
public static class UserExtensions
{
public static string Nick(this IUser user) {
if (user is IGuildUser gu)
return gu.Nickname ?? gu.Username;
else
return user.Username;
}
}
}