lots more work. dbcontext is now singleton

This commit is contained in:
Ben Harris 2017-12-09 00:59:43 -05:00
parent dec0423a99
commit ed808f938b
19 changed files with 188 additions and 184 deletions

View File

@ -1,24 +1,19 @@
using Discord.Commands;
using dotbot.Core;
using dotbot.Services;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
namespace dotbot.Commands
{
public class CleverBot : ModuleBase<SocketCommandContext>
{
private readonly IConfigurationRoot _config;
private Dictionary<ulong, string> _cache;
private string CleverBotApiUrl = "https://www.cleverbot.com/getreply";
public CleverBotCacheService _cacheService { get; set; }
private string CleverBotApiUrl;
public CleverBot(IConfigurationRoot config, CleverBotCacheService cache)
public CleverBot(IConfigurationRoot config)
{
_config = config;
_cache = cache.Cache;
CleverBotApiUrl += $"?key={_config["tokens:cleverbot"]}&input=";
CleverBotApiUrl = $"{config["endpoints:cleverbot"]}?key={config["tokens:cleverbot"]}&input=";
}
class CleverBotResponse
@ -33,12 +28,11 @@ namespace dotbot.Commands
[Summary("talk to the bot")]
public async Task ChatWithCleverBot([Remainder] [Summary("what you want to say to benbot")] string message)
{
var url = $"{CleverBotApiUrl}{message}";
if (_cache.ContainsKey(Context.Channel.Id))
url += $"&cs={_cache[Context.Channel.Id]}";
var json = (new WebClient { Proxy = null }).DownloadString(url);
var response = JsonConvert.DeserializeObject<CleverBotResponse>(json);
_cache[Context.Channel.Id] = response.cs;
await Context.Channel.TriggerTypingAsync();
var cache = _cacheService.Cache;
var id = Context.Channel.Id;
var response = Utils.GetJson<CleverBotResponse>($"{CleverBotApiUrl}{message}{(cache.ContainsKey(id) ? $"&cs={cache[id]}" : "")}");
cache[id] = response.cs;
await ReplyAsync(response.output);
}

View File

@ -1,76 +1,50 @@
using Discord.Commands;
using dotbot.Core;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace dotbot.Commands
{
public class Definitions : ModuleBase<SocketCommandContext>
{
public DotbotDb db { get; set; }
[Command("set")]
[Alias("define")]
[Summary("save some text for later")]
public async Task SetDefinition([Summary("key to set")] string Key, [Remainder] [Summary("what to set it to")] string Value)
{
using (var db = new DotbotDbContext())
{
if (db.Defs.Any(d => d.Id == Key))
db.Defs.Find(Key).Def = Value;
else
db.Defs.Add(new Definition { Id = Key, Def = Value });
db.SaveChanges();
await ReplyAsync($"`{Key}` set to `{Value}`");
}
if (db.Defs.Any(d => d.Id == Key))
db.Defs.Find(Key).Def = Value;
else
db.Defs.Add(new Definition { Id = Key, Def = Value });
db.SaveChanges();
await ReplyAsync($"`{Key}` set to `{Value}`");
}
[Command("get")]
[Summary("get some text that was saved")]
public async Task GetDefinition([Summary("key to look for")] string Key)
{
using (var db = new DotbotDbContext())
{
var def = db.Defs.Find(Key);
await ReplyAsync($"**{Key}**: {def?.Def ?? "not set"}");
}
}
public async Task GetDefinition([Summary("key to look for")] string Key) => await base.ReplyAsync($"**{Key}**: {db.Defs.Find(Key)?.Def ?? "not set"}");
[Command("unset")]
[Summary("remove something you saved before")]
public async Task RemoveDefinition([Summary("key to remove")] string Key)
{
using (var db = new DotbotDbContext())
if (db.Defs.Any(d => d.Id == Key))
{
if (db.Defs.Any(d => d.Id == Key))
{
db.Defs.Remove(db.Defs.Find(Key));
db.SaveChanges();
await ReplyAsync($"**{Key}** removed successfully");
}
else
{
await ReplyAsync($"**{Key}** doesn't exist");
}
db.Defs.Remove(db.Defs.Find(Key));
db.SaveChanges();
await ReplyAsync($"**{Key}** removed successfully");
}
else await ReplyAsync($"**{Key}** doesn't exist");
}
[Command("defs")]
[Summary("print all saved definitions")]
public async Task GetAllDefinitions()
{
using (var db = new DotbotDbContext())
{
var res = new StringBuilder();
foreach (var def in db.Defs)
{
res.AppendLine($"`{def.Id}`: {def.Def}");
}
await ReplyAsync(res.ToString());
}
}
public async Task AllDefs() => await ReplyAsync(string.Join("\n", db.Defs.Select(i => $"`{i.Id}`: {i.Def}")));
}

View File

@ -12,10 +12,12 @@ namespace dotbot.Commands
[Group("email")]
public class Emails : ModuleBase<SocketCommandContext>
{
private readonly IConfigurationRoot _config;
public DotbotDb db { get; set; }
private NetworkCredential EmailCredential;
public Emails(IConfigurationRoot config)
{
_config = config;
EmailCredential = new NetworkCredential(config["gmail_login"], config["tokens:gmail"]);
}
@ -24,32 +26,29 @@ namespace dotbot.Commands
[Summary("user to send to")] IUser recipient,
[Summary("message to send")] [Remainder] string message
) {
using (var db = new DotbotDbContext())
if (!db.Emails.Any(e => e.Id == recipient.Id))
{
if (!db.Emails.Any(e => e.Id == recipient.Id))
{
await ReplyAsync($"{recipient.Mention} does not have a saved email");
return;
}
var status = await ReplyAsync($"sending message");
var smtp = new SmtpClient("smtp.gmail.com")
{
EnableSsl = true,
Port = 587,
Credentials = new NetworkCredential(_config["gmail_login"], _config["tokens:gmail"])
};
smtp.Send(
$"{Context.User.Username}-{Context.Guild.Name}@benbot.tilde.team",
db.Emails.Find(recipient.Id).EmailAddress,
$"benbot message from {Context.User.Username}",
message
);
await Context.Message.DeleteAsync();
await status.ModifyAsync(m => m.Content = $"message sent to {recipient.Mention}!");
await ReplyAsync($"{recipient.Mention} does not have a saved email");
return;
}
var status = await ReplyAsync($"sending message");
(new SmtpClient("smtp.gmail.com")
{
EnableSsl = true,
Port = 587,
Credentials = EmailCredential,
})
.Send(
from: $"{Context.User.Username}-{Context.Guild.Name}@benbot.tilde.team",
recipients: db.Emails.Find(recipient.Id).EmailAddress,
subject: $"benbot message from {Context.User.Username}",
body: message
);
await Context.Message.DeleteAsync();
await status.ModifyAsync(m => m.Content = $"message sent to {recipient.Mention}!");
}
@ -57,21 +56,18 @@ namespace dotbot.Commands
[Summary("saves an email address to your profile")]
public async Task SaveEmail([Summary("email to save")] string email)
{
using (var db = new DotbotDbContext())
{
var id = Context.User.Id;
await Context.Message.DeleteAsync();
if (db.Emails.Any(e => e.Id == id))
db.Emails.Find(id).EmailAddress = email;
else
db.Emails.Add(new Email
{
Id = id,
EmailAddress = email
});
db.SaveChanges();
await ReplyAsync("your email has been saved");
}
var id = Context.User.Id;
await Context.Message.DeleteAsync();
if (db.Emails.Any(e => e.Id == id))
db.Emails.Find(id).EmailAddress = email;
else
db.Emails.Add(new Email
{
Id = id,
EmailAddress = email
});
db.SaveChanges();
await ReplyAsync("your email has been saved");
}
@ -79,11 +75,8 @@ namespace dotbot.Commands
[Summary("shows your saved email address")]
public async Task ShowEmail()
{
using (var db = new DotbotDbContext())
{
await Context.Message.DeleteAsync();
await ReplyAsync($"{Context.User.Mention}, your saved email is {db.Emails.Find(Context.User.Id)?.EmailAddress ?? "non existent"}");
}
await Context.Message.DeleteAsync();
await ReplyAsync($"{Context.User.Mention}, your saved email is {db.Emails.Find(Context.User.Id)?.EmailAddress ?? "non existent"}");
}
}

View File

@ -9,12 +9,37 @@ namespace dotbot.Commands
[Group("img")]
public class Images : ModuleBase<SocketCommandContext>
{
public DotbotDb db { get; set; }
[Command]
[Alias("image", "pic")]
[Priority(0)]
[Summary("get a saved image")]
public async Task GetImage([Summary("image name")] string name)
{
}
[Command("list")]
[Alias("ls")]
[Priority(1)]
[Summary("list all saved images")]
public async Task ListImages()
{
}
[Command("save")]
[Priority(1)]
[Summary("save an image for later")]
public async Task SaveImage([Summary("image name")] string name)
{
}
}
}

View File

@ -9,6 +9,7 @@ namespace dotbot.Commands
{
public class Location : ModuleBase<SocketCommandContext>
{
public DotbotDb db { get; set; }
private string OwmUrl;
private string GeoNamesUrl;
@ -23,34 +24,33 @@ namespace dotbot.Commands
[Summary("save your location so benbot can look up your weather and timezone")]
public async Task SaveUserLocation([Remainder] [Summary("location")] string location)
{
await Context.Channel.TriggerTypingAsync();
var owm = Utils.GetJson<OwmApiResult>($"{OwmUrl}&q={HttpUtility.UrlEncode(location)}");
var geo = Utils.GetJson<GeonamesApiResult>($"{GeoNamesUrl}&lat={owm.coord.lat}&lng={owm.coord.lon}");
using (var db = new DotbotDbContext())
{
if (db.UserLocations.Any(u => u.Id == Context.User.Id))
{ // update existing city
var loc = db.UserLocations.Find(Context.User.Id);
loc.CityId = owm.id;
loc.Lat = owm.coord.lat;
loc.Lng = owm.coord.lon;
loc.City = owm.name;
loc.TimeZone = geo.timezoneId;
}
else
{ // save new location
db.UserLocations.Add(new UserLocation
{
Id = Context.User.Id,
CityId = owm.id,
Lat = owm.coord.lat,
Lng = owm.coord.lon,
City = owm.name,
TimeZone = geo.timezoneId,
});
}
db.SaveChanges();
await ReplyAsync($"your location has been set to {owm.name}");
if (db.UserLocations.Any(u => u.Id == Context.User.Id))
{ // update existing city
var loc = db.UserLocations.Find(Context.User.Id);
loc.CityId = owm.id;
loc.Lat = owm.coord.lat;
loc.Lng = owm.coord.lon;
loc.City = owm.name;
loc.TimeZone = geo.timezoneId;
}
else
{ // save new location
db.UserLocations.Add(new UserLocation
{
Id = Context.User.Id,
CityId = owm.id,
Lat = owm.coord.lat,
Lng = owm.coord.lon,
City = owm.name,
TimeZone = geo.timezoneId,
});
}
db.SaveChanges();
await ReplyAsync($"your location has been set to {owm.name}");
}
}
}

View File

@ -1,6 +1,5 @@
using Discord;
using Discord.Commands;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;

View File

@ -3,7 +3,6 @@ using Discord.WebSocket;
using System;
using System.Threading.Tasks;
using Discord;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;

View File

@ -6,13 +6,13 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using System.Web;
using NodaTime;
namespace dotbot.Commands
{
[Group("time")]
public class Time : ModuleBase<SocketCommandContext>
{
public DotbotDb db { get; set; }
private readonly IConfigurationRoot _config;
private string OwmUrl;
private string GeoNamesUrl;
@ -29,15 +29,13 @@ namespace dotbot.Commands
[Summary("get the time at your location (or bot's location if you don't have one saved)")]
public async Task GetTime()
{
using (var db = new DotbotDbContext())
await Context.Channel.TriggerTypingAsync();
if (db.UserLocations.Any(u => u.Id == Context.User.Id))
{
if (db.UserLocations.Any(u => u.Id == Context.User.Id))
{
var ul = db.UserLocations.Find(Context.User.Id);
await ReplyAsync($"it's {Utils.IanaIdToDateTime(ul.TimeZone):g} in {ul.City}");
}
else await ReplyAsync($"it's {DateTime.Now:g} Eastern Time (where the bot is hosted)\n\nyou can save your location/timezone with `{_config["prefix"]}savelocation <city>`");
var ul = db.UserLocations.Find(Context.User.Id);
await ReplyAsync($"it's {Utils.IanaIdToDateTime(ul.TimeZone):g} in {ul.City}");
}
else await ReplyAsync($"it's {DateTime.Now:g} Eastern Time (where the bot is hosted)\n\nyou can save your location/timezone with `{_config["prefix"]}savelocation <city>`");
}
@ -45,15 +43,13 @@ namespace dotbot.Commands
[Summary("get the time for a user (if they have a location saved)")]
public async Task GetUserLocationTime([Summary("user to get time for")] IUser user)
{
using (var db = new DotbotDbContext())
await Context.Channel.TriggerTypingAsync();
if (db.UserLocations.Any(u => u.Id == user.Id))
{
if (db.UserLocations.Any(u => u.Id == user.Id))
{
var ul = db.UserLocations.Find(user.Id);
await ReplyAsync($"the time for {user.Mention} in {ul.City} is {Utils.IanaIdToDateTime(ul.TimeZone):g}");
}
else await ReplyAsync($"{user.Mention} does not have a saved location\nit's {DateTime.Now:g} Eastern Time (US)");
var ul = db.UserLocations.Find(user.Id);
await ReplyAsync($"the time for {user.Mention} in {ul.City} is {Utils.IanaIdToDateTime(ul.TimeZone):g}");
}
else await ReplyAsync($"{user.Mention} does not have a saved location\nit's {DateTime.Now:g} Eastern Time (US)");
}

17
Commands/Util.cs Normal file
View File

@ -0,0 +1,17 @@
using Discord.Commands;
using System;
using System.Threading.Tasks;
namespace dotbot.Commands
{
public class Util : ModuleBase<SocketCommandContext>
{
[Command("exit")]
[Alias("die", "shutdown")]
[RequireOwner]
public async Task ShutDown()
{
Environment.Exit(0);
}
}
}

View File

@ -12,6 +12,7 @@ namespace dotbot.Commands
[Group("weather")]
public class Weather : ModuleBase<SocketCommandContext>
{
public DotbotDb db { get; set; }
private IConfigurationRoot _config;
private string OwmUrl;
@ -26,15 +27,13 @@ namespace dotbot.Commands
[Summary("gets the weather for your location")]
public async Task GetWeather()
{
using (var db = new DotbotDbContext())
await Context.Channel.TriggerTypingAsync();
if (db.UserLocations.Any(u => u.Id == Context.User.Id))
{
if (db.UserLocations.Any(u => u.Id == Context.User.Id))
{
var url = $"{OwmUrl}&id={db.UserLocations.Find(Context.User.Id).CityId}";
await ReplyAsync("", embed: WeatherEmbed(Utils.GetJson<OwmApiResult>(url)));
}
else await ReplyAsync($"you don't have a location saved. look one up with `{_config["prefix"]}weather <search term>` or save a location for yourself with `{_config["prefix"]}savelocation <city>`");
var url = $"{OwmUrl}&id={db.UserLocations.Find(Context.User.Id).CityId}";
await ReplyAsync("", embed: WeatherEmbed(Utils.GetJson<OwmApiResult>(url)));
}
else await ReplyAsync($"you don't have a location saved. look one up with `{_config["prefix"]}weather <search term>` or save a location for yourself with `{_config["prefix"]}savelocation <city>`");
}
@ -42,15 +41,13 @@ namespace dotbot.Commands
[Summary("look up the weather at a mentioned user's saved location")]
public async Task LookupWeatherForUser([Summary("user to check time for")] IUser user)
{
using (var db = new DotbotDbContext())
await Context.Channel.TriggerTypingAsync();
if (db.UserLocations.Any(u => u.Id == user.Id))
{
if (db.UserLocations.Any(u => u.Id == user.Id))
{
var url = $"{OwmUrl}&id={db.UserLocations.Find(user.Id).CityId}";
await ReplyAsync("", embed: WeatherEmbed(Utils.GetJson<OwmApiResult>(url)));
}
else await ReplyAsync($"{user.Mention} doesn't have a location saved. look one up with `{_config["prefix"]}weather <search term>` or save a location for yourself with `{_config["prefix"]}savelocation <city>`");
var url = $"{OwmUrl}&id={db.UserLocations.Find(user.Id).CityId}";
await ReplyAsync("", embed: WeatherEmbed(Utils.GetJson<OwmApiResult>(url)));
}
else await ReplyAsync($"{user.Mention} doesn't have a location saved. look one up with `{_config["prefix"]}weather <search term>` or save a location for yourself with `{_config["prefix"]}savelocation <city>`");
}
@ -58,6 +55,7 @@ namespace dotbot.Commands
[Summary("look up the weather at a specified location")]
public async Task LookupWeather([Remainder] [Summary("location")] string location)
{
await Context.Channel.TriggerTypingAsync();
var url = $"{OwmUrl}&q={HttpUtility.UrlEncode(location)}";
await ReplyAsync("", embed: WeatherEmbed(Utils.GetJson<OwmApiResult>(url)));
}

View File

@ -2,7 +2,7 @@
namespace dotbot.Core
{
public class DotbotDbContext : DbContext
public class DotbotDb : DbContext
{
public DbSet<Definition> Defs { get; set; }
public DbSet<Email> Emails { get; set; }

View File

@ -9,7 +9,7 @@ using System;
namespace dotbot.Migrations
{
[DbContext(typeof(DotbotDbContext))]
[DbContext(typeof(DotbotDb))]
[Migration("20171205032404_Init")]
partial class Init
{

View File

@ -9,7 +9,7 @@ using System;
namespace dotbot.Migrations
{
[DbContext(typeof(DotbotDbContext))]
[DbContext(typeof(DotbotDb))]
[Migration("20171205052158_AddEmailTable")]
partial class AddEmailTable
{

View File

@ -9,7 +9,7 @@ using System;
namespace dotbot.Migrations
{
[DbContext(typeof(DotbotDbContext))]
[DbContext(typeof(DotbotDb))]
[Migration("20171206050609_UserLocations")]
partial class UserLocations
{

View File

@ -9,7 +9,7 @@ using System;
namespace dotbot.Migrations
{
[DbContext(typeof(DotbotDbContext))]
[DbContext(typeof(DotbotDb))]
[Migration("20171209043817_AddImageTable")]
partial class AddImageTable
{

View File

@ -9,7 +9,7 @@ using System;
namespace dotbot.Migrations
{
[DbContext(typeof(DotbotDbContext))]
[DbContext(typeof(DotbotDb))]
partial class DotbotDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)

View File

@ -1,11 +1,11 @@
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using dotbot.Core;
using dotbot.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Reflection;
using System.Threading.Tasks;
namespace dotbot
@ -39,6 +39,7 @@ namespace dotbot
.AddSingleton<LoggingService>()
.AddSingleton<StartupService>()
.AddSingleton<CleverBotCacheService>()
.AddSingleton<DotbotDb>()
.AddSingleton<Random>()
.AddSingleton(_config);

View File

@ -10,33 +10,36 @@ namespace dotbot.Services
{
public class CommandHandlerService
{
private DotbotDb _db;
private readonly DiscordSocketClient _discord;
private readonly CommandService _commands;
private readonly IConfigurationRoot _config;
private readonly IServiceProvider _provider;
// DiscordSocketClient, CommandService, IConfigurationRoot, and IServiceProvider are injected automatically from the IServiceProvider
public CommandHandlerService(
DiscordSocketClient discord,
CommandService commands,
IConfigurationRoot config,
IServiceProvider provider)
{
IServiceProvider provider,
DotbotDb db
) {
_discord = discord;
_commands = commands;
_config = config;
_provider = provider;
_db = db;
_discord.MessageReceived += OnMessageReceivedAsync;
}
private async Task OnMessageReceivedAsync(SocketMessage s)
{
var msg = s as SocketUserMessage; // Ensure the message is from a user/bot
var msg = s as SocketUserMessage;
if (msg == null) return;
if (msg.Author.Id == _discord.CurrentUser.Id) return; // Ignore self when checking commands
// Ignore self and other bots when checking commands
if (msg.Author.Id == _discord.CurrentUser.Id || msg.Author.IsBot) return;
var context = new SocketCommandContext(_discord, msg); // Create the command context
var context = new SocketCommandContext(_discord, msg);
int argPos = 0; // Check if the message has a valid command prefix
if (msg.HasStringPrefix(_config["prefix"], ref argPos) || msg.HasMentionPrefix(_discord.CurrentUser, ref argPos))
@ -46,21 +49,25 @@ namespace dotbot.Services
if (msg.HasStringPrefix(_config["prefix"], ref argPos))
{
using (var db = new DotbotDbContext())
var key = msg.Content.Substring(_config["prefix"].Length);
if (_db.Defs.Any(d => d.Id == key))
{
var key = msg.Content.Substring(_config["prefix"].Length);
if (db.Defs.Any(d => d.Id == key))
{
await context.Channel.SendMessageAsync($"**{key}**: {db.Defs.Find(key).Def}");
return;
}
await context.Channel.SendMessageAsync($"**{key}**: {_db.Defs.Find(key).Def}");
return;
}
if (_db.Images.Any(i => i.Id == key))
{
await context.Channel.TriggerTypingAsync();
await context.Message.DeleteAsync();
var img = _db.Images.Find(key);
await context.Channel.SendFileAsync(img.FilePath, $"{img.Id} by {context.User.Mention}");
return;
}
}
if (!result.ToString().Contains("UnknownCommand"))
await context.Channel.SendMessageAsync(result.ToString());
}
if (!result.IsSuccess)
await context.Channel.SendMessageAsync(result.ToString());
}
}
}
}

View File

@ -10,6 +10,7 @@
},
"endpoints": {
"owm": "http://api.openweathermap.org/data/2.5/weather",
"geonames": "http://api.geonames.org/timezoneJSON"
"geonames": "http://api.geonames.org/timezoneJSON",
"cleverbot": "https://www.cleverbot.com/getreply"
}
}