Merge branch 'develop' into 'master'

Develop

See merge request discord-bots/chaosbot!1
This commit is contained in:
Sean "Solao Bajiuik" Stoves 2020-08-06 20:32:04 -04:00
commit 3ea10e5395
9 changed files with 434 additions and 13 deletions

View File

@ -6,6 +6,7 @@ using System.Text;
using ChaosBot.Discord.PreConditions; using ChaosBot.Discord.PreConditions;
using ChaosBot.Models; using ChaosBot.Models;
using ChaosBot.Repositories; using ChaosBot.Repositories;
using ChaosBot.Services;
using Discord; using Discord;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -78,20 +79,23 @@ namespace ChaosBot.Discord.Modules.Admin
{ {
try try
{ {
if ((key != null) && (value != null)) if ((key != null) && (value != null) )
{ {
using (ChaosbotContext dbContext = new ChaosbotContext()) if(await RestrictedConfig.IsAllowed(key))
{ {
Configuration cnfSet = new Configuration(); using (ChaosbotContext dbContext = new ChaosbotContext())
{
Configuration cnfSet = new Configuration();
cnfSet.Key = key; cnfSet.Key = key;
cnfSet.DiscordGuildId = Context.Guild.Id; cnfSet.DiscordGuildId = Context.Guild.Id;
cnfSet.SerializedValue = JsonConvert.SerializeObject(value); cnfSet.SerializedValue = JsonConvert.SerializeObject(value);
await dbContext.Configuration.Upsert(cnfSet) await dbContext.Configuration.Upsert(cnfSet)
.On(x => new {x.Key, x.DiscordGuildId}).RunAsync(); .On(x => new {x.Key, x.DiscordGuildId}).RunAsync();
await ConfigGet(key, true); await ConfigGet(key, true);
}
} }
} }
else else
@ -111,7 +115,7 @@ namespace ChaosBot.Discord.Modules.Admin
{ {
try try
{ {
if (key != null) if ((key != null) && (await RestrictedConfig.IsAllowed(key)))
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
EmbedBuilder embed = new EmbedBuilder(); EmbedBuilder embed = new EmbedBuilder();

View File

@ -0,0 +1,110 @@
using System;
using Discord;
using Discord.Commands;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text;
using Antlr4.Runtime.Misc;
using ChaosBot.Discord.PreConditions;
using ChaosBot.Lodestone;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using NLog;
namespace ChaosBot.Discord.Modules.Admin
{
public class RankCheck : ModuleBase
{
private static readonly ILogger _logger = Program.Logger;
[Command("rankCheck")]
[Alias("rc")]
[CheckCommandPerm("Admin")]
public async Task rankCheck()
{
try
{
List<LodestoneRank> ranks = await GetRank();
var sb = new StringBuilder();
var embed = new EmbedBuilder();
embed.WithColor(new Color(255, 255, 0));
embed.Title = $"Pending Promotions";
sb.AppendLine();
sb.AppendLine();
sb.AppendLine($"**Recruits Pending Promotion to Initiate**");
if(ranks.FindAll(x => x.IngameRole == ERole.Recruit).Any())
{
foreach (var lsID in ranks.FindAll(x => x.IngameRole == ERole.Recruit))
{
if ((lsID.ShouldBeRole != lsID.IngameRole) && (lsID.ShouldBeRole != null))
sb.AppendLine(string.Format("{0} {1}", lsID.DisplayName, $"linked to <@{lsID.DiscordId}>"));
}
}
else
sb.AppendLine($"None at this time.");
sb.AppendLine();
sb.AppendLine($"**Initiates Pending Promotion to Member**");
if (ranks.FindAll(x => x.IngameRole == ERole.Initiate).Any())
{
foreach (var lsID in ranks.FindAll(x => x.IngameRole == ERole.Initiate))
{
if ((lsID.ShouldBeRole != lsID.IngameRole) && (lsID.ShouldBeRole != null))
sb.AppendLine(string.Format("{0} {1}", lsID.DisplayName, $"linked to <@{lsID.DiscordId}>"));
}
}
else
sb.AppendLine($"None at this time.");
sb.AppendLine();
sb.AppendLine($"Report Generated by {Context.User.Mention} at {DateTime.Now.ToString("dddd, dd MMMM yyyy h:mm tt")}.");
/*
* Add the string to the Embed
*/
embed.Description = sb.ToString();
/*
* Reply with the Embed created above
*/
await ReplyAsync(null, false, embed.Build());
}
catch (Exception ex)
{
_logger.Error($"{MethodBase.GetCurrentMethod().ReflectedType.FullName}: Exception [{ex}] thrown, <[{ex.Message}]>.");
}
}
public async Task<List<LodestoneRank>> GetRank()
{
string response = null;
try
{
using (var client = new HttpClient())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13;
var result = await client.GetAsync("https://www.ffxivhelix.com/rapi/clogiclodestone/v1/users");
result.EnsureSuccessStatusCode();
response = await result.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
_logger.Error(
$"{MethodBase.GetCurrentMethod().ReflectedType.FullName}: Exception [{ex}] thrown, <[{ex.Message}]>.");
}
return JsonConvert.DeserializeObject<List<LodestoneRank>>(JsonConvert.SerializeObject(JsonConvert.DeserializeObject<LodestoneRankApi>(response).Data));
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using ChaosBot.Discord.PreConditions;
using ChaosBot.Repositories;
using Discord;
using Discord.Commands;
using Microsoft.Extensions.Configuration;
using NLog;
namespace ChaosBot.Discord.Modules.User
{
public class Info : ModuleBase
{
private static readonly ILogger Logger = Program.Logger;
[Command("info")]
[Alias("version")]
[CheckCommandPerm("User")]
public async Task ShowInfo()
{
try
{
var sb = new StringBuilder();
var embed = new EmbedBuilder();
embed.WithColor(new Color(255, 255, 0));
embed.Title = $"Information {Program.AppSettingsHandler.GetValue<string>("Bot:Name")} v{Program.AppSettingsHandler.GetValue<string>("Bot:Version")}";
sb.AppendLine($"Prefix: {ConfigurationRepository.GetValue<string>("Discord:Prefix", Context.Guild.Id)}");
/*
* Add the string to the Embed
*/
embed.Description = sb.ToString();
/*
* Reply with the Embed created above
*/
await ReplyAsync(null, false, embed.Build());
}
catch(Exception ex)
{
Logger.Error(
$"{MethodBase.GetCurrentMethod().ReflectedType.FullName}: Exception [{ex}] thrown, <[{ex.Message}]>.");
}
}
}
}

View File

@ -56,8 +56,15 @@ namespace ChaosBot.Discord.Services
int argPos = 0; int argPos = 0;
string prefix = ConfigurationRepository.GetValue<string>("Discord:Prefix", context.Guild.Id, "!"); string prefix = ConfigurationRepository.GetValue<string>("Discord:Prefix", context.Guild.Id, "!");
if (!(message.HasMentionPrefix(_client.CurrentUser, ref argPos) || message.HasStringPrefix(prefix, ref argPos))) if (!(message.HasMentionPrefix(_client.CurrentUser, ref argPos) ||
message.HasStringPrefix(prefix, ref argPos)))
{
ExperienceHandler.addXP(context.Guild.Id, context.User.Id);
return; return;
}
if(Convert.ToBoolean(ConfigurationRepository.GetValue<string>("Experience:Commands", context.Guild.Id, "false")))
ExperienceHandler.addXP(context.Guild.Id, context.User.Id);
await _commands.ExecuteAsync(context, argPos, _services); await _commands.ExecuteAsync(context, argPos, _services);
} }

View File

@ -0,0 +1,51 @@
using System;
using System.Linq;
using System.Reflection;
using ChaosBot.Models;
using ChaosBot.Repositories;
using Microsoft.EntityFrameworkCore;
using NLog;
namespace ChaosBot.Discord.Services
{
public class ExperienceHandler
{
private static readonly ILogger _logger = Program.Logger;
public static async void addXP(ulong DiscordGuildId, ulong DiscordUserId)
{
try
{
using (ChaosbotContext dbContext = new ChaosbotContext())
{
IQueryable<Experience> ctxUser = dbContext.ExperiencePoints;
IQueryable<Experience> usrXp = ctxUser
.Where(p => p.DiscordGuildId.Equals(DiscordGuildId))
.Where(p => p.DiscordUserId.Equals(DiscordUserId));
Experience usrNewXp;
if (usrXp.Any())
{
usrNewXp = usrXp.First();
usrNewXp.Amount = usrNewXp.Amount + Convert.ToUInt64(ConfigurationRepository.GetValue<string>("Experience:PerMsg", DiscordGuildId, "0"));
}
else
{
usrNewXp = new Experience();
usrNewXp.Amount = Convert.ToUInt64(ConfigurationRepository.GetValue<string>("Experience:PerMsg", DiscordGuildId, "0"));
}
usrNewXp.DiscordGuildId = DiscordGuildId;
usrNewXp.DiscordUserId = DiscordUserId;
await dbContext.ExperiencePoints.Upsert(usrNewXp)
.On(x => new { x.DiscordGuildId, x.DiscordUserId}).RunAsync();
}
}
catch (Exception ex)
{
_logger.Error(
$"{MethodBase.GetCurrentMethod().ReflectedType.FullName}: Exception [{ex}] thrown, <[{ex.Message}]>.");
}
}
}
}

View File

@ -0,0 +1,155 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace ChaosBot.Lodestone
{
public partial class LodestoneRankApi
{
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("error")]
public object Error { get; set; }
[JsonProperty("data")]
public List<LodestoneRank> Data { get; set; }
}
public partial class LodestoneRank
{
[JsonProperty("lodestoneId")]
[JsonConverter(typeof(ParseStringConverter))]
public long LodestoneId { get; set; }
[JsonProperty("ingameRole")]
public ERole IngameRole { get; set; }
[JsonProperty("firstSeen")]
public DateTimeOffset FirstSeen { get; set; }
[JsonProperty("displayName")]
public string DisplayName { get; set; }
[JsonProperty("shouldBeRole")]
public ERole? ShouldBeRole { get; set; }
[JsonProperty("discordId")]
public string DiscordId { get; set; }
}
public enum ERole { Council, Initiate, Member, Mentor, Recruit };
public partial class LodestoneRankApi
{
public static LodestoneRankApi FromJson(string json) => JsonConvert.DeserializeObject<LodestoneRankApi>(json, ChaosBot.Lodestone.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this LodestoneRankApi self) => JsonConvert.SerializeObject(self, ChaosBot.Lodestone.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
ERoleConverter.Singleton,
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class ERoleConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(ERole) || t == typeof(ERole?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
switch (value)
{
case "Council":
return ERole.Council;
case "Initiate":
return ERole.Initiate;
case "Member":
return ERole.Member;
case "Mentor":
return ERole.Mentor;
case "Recruit":
return ERole.Recruit;
}
throw new Exception("Cannot unmarshal type ERole");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (ERole)untypedValue;
switch (value)
{
case ERole.Council:
serializer.Serialize(writer, "Council");
return;
case ERole.Initiate:
serializer.Serialize(writer, "Initiate");
return;
case ERole.Member:
serializer.Serialize(writer, "Member");
return;
case ERole.Mentor:
serializer.Serialize(writer, "Mentor");
return;
case ERole.Recruit:
serializer.Serialize(writer, "Recruit");
return;
}
throw new Exception("Cannot marshal type ERole");
}
public static readonly ERoleConverter Singleton = new ERoleConverter();
}
internal class ParseStringConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
long l;
if (Int64.TryParse(value, out l))
{
return l;
}
throw new Exception("Cannot unmarshal type long");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (long)untypedValue;
serializer.Serialize(writer, value.ToString());
return;
}
public static readonly ParseStringConverter Singleton = new ParseStringConverter();
}
}

View File

@ -11,6 +11,7 @@ namespace ChaosBot.Models
public DbSet<Raffle> Raffles { get; set; } public DbSet<Raffle> Raffles { get; set; }
public DbSet<CommandPermission> CommandPermissions { get; set; } public DbSet<CommandPermission> CommandPermissions { get; set; }
public DbSet<Configuration> Configuration { get; set; } public DbSet<Configuration> Configuration { get; set; }
public DbSet<Experience> ExperiencePoints { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
@ -41,6 +42,8 @@ namespace ChaosBot.Models
.HasKey(x => new {x.DiscordGuildId, x.LodestoneId}); .HasKey(x => new {x.DiscordGuildId, x.LodestoneId});
modelBuilder.Entity<Point>() modelBuilder.Entity<Point>()
.HasKey(x => new {x.DiscordGuildId, x.DiscordUserId}); .HasKey(x => new {x.DiscordGuildId, x.DiscordUserId});
modelBuilder.Entity<Experience>()
.HasKey(x => new {x.DiscordGuildId, x.DiscordUserId});
modelBuilder.Entity<Configuration>() modelBuilder.Entity<Configuration>()
.HasKey(x => new {x.DiscordGuildId, x.Key}); .HasKey(x => new {x.DiscordGuildId, x.Key});
} }

View File

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
namespace ChaosBot.Models
{
#region Required
public class Experience
{
[Required]
public ulong DiscordUserId { get; set; }
[Required]
public ulong DiscordGuildId { get; set; }
public ulong Amount { get; set; }
}
#endregion
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ChaosBot.Models;
using ChaosBot.Repositories;
using Discord.Commands;
using Discord.WebSocket;
using NLog;
namespace ChaosBot.Services
{
public class RestrictedConfig
{
private static ILogger _logger = Program.Logger;
public static async Task<Boolean> IsAllowed(string key)
{
List<string> restrictedCfg = new List<string> {"Database:Host", "Database:Port", "Database:Name", "Database:User", "Database:Pass", "Bot:Version", "NLog", "WebServer", "Discord:Token"};
if (restrictedCfg.Contains(key))
return false;
return true;
}
}
}