diff --git a/Module/ModLogs/Entry.cs b/Module/ModLogs/Entry.cs new file mode 100644 index 0000000..c3bec89 --- /dev/null +++ b/Module/ModLogs/Entry.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Noikoio.RegexBot.Module.ModLogs +{ + /// + /// Represents a log entry. + /// + class Entry + { + readonly int _logId; + readonly DateTime _ts; + readonly ulong? _invokeId; + readonly ulong _targetId; + readonly ulong? _channelId; + readonly string _type; + readonly string _message; + + /// + /// Gets the ID value of this log entry. + /// + public int Id => _logId; + /// + /// Gets the timestamp (a with ) of the entry. + /// + public DateTime Timestamp => _ts; + /// + /// Gets the ID of the invoking user. + /// This value exists only if this entry was created through action of another user that is not the target. + /// + public ulong? Invoker => _invokeId; + /// + /// Gets the ID of the user to which this log entry corresponds. + /// + public ulong Target => _targetId; + /// + /// Gets the guild channel ID to which this log entry corresponds, if any. + /// + public ulong? TargetChannel => _channelId; + /// + /// Gets this log entry's 'type', or category. + /// + public string LogType => _type; + /// + /// Gets the content of this log entry. + /// + public string Message => _message; + + public Entry() + { + throw new NotImplementedException(); + } + + // TODO figure out some helper methods to retrieve data of other entities by ID, if it becomes necessary + } +} diff --git a/Module/ModLogs/EventListener.cs b/Module/ModLogs/EventListener.cs new file mode 100644 index 0000000..3984696 --- /dev/null +++ b/Module/ModLogs/EventListener.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Noikoio.RegexBot.Module.ModLogs +{ + /// + /// Listens for certain events and places them on the log. + /// + class EventListener + { + } +} diff --git a/Module/ModLogs/MessageCache.cs b/Module/ModLogs/MessageCache.cs new file mode 100644 index 0000000..80cd933 --- /dev/null +++ b/Module/ModLogs/MessageCache.cs @@ -0,0 +1,110 @@ +using Discord.WebSocket; +using Newtonsoft.Json.Linq; +using Noikoio.RegexBot.ConfigItem; +using Npgsql; +using NpgsqlTypes; +using System.Threading.Tasks; + +namespace Noikoio.RegexBot.Module.DBCache +{ + /// + /// Caches information regarding all incoming messages. + /// The function of this feature should be transparent to the user, and thus no configuration is needed. + /// + class MessageCache : BotFeature + { + // TODO Something that clears expired cache items + private readonly DatabaseConfig _db; + + public override string Name => nameof(MessageCache); + + public MessageCache(DiscordSocketClient client) : base(client) + { + _db = RegexBot.Config.Database; + + if (_db.Enabled) + { + CreateCacheTables(); + + client.MessageReceived += Client_MessageReceived; + //client.MessageUpdated += Client_MessageUpdated; + } + else + { + Log("No database storage available.").Wait(); + } + } + + #region Table setup + const string TableMessage = "cache_messages"; + + public override Task ProcessConfiguration(JToken configSection) => Task.FromResult(null); + + #region Event handling + // A new message has been created + private async Task Client_MessageReceived(SocketMessage arg) + { + await Task.Run(() => CacheMessage(arg)); + } + + //private Task Client_MessageUpdated(Discord.Cacheable arg1, SocketMessage arg2, ISocketMessageChannel arg3) + /* + * Edited messages seem to retain their ID. This is a problem. + * The point of this message cache was to have another feature be able to relay + * both the previous and current message at once. + * For now: Do nothing on updated messages. + */ + #endregion + + private void CreateCacheTables() + { + using (var db = _db.GetOpenConnectionAsync().GetAwaiter().GetResult()) + { + using (var c = db.CreateCommand()) + { + c.CommandText = "CREATE TABLE IF NOT EXISTS " + TableMessage + " (" + + "message_id bigint primary key, " + + "author_id bigint not null, " + + "guild_id bigint not null, " + + "channel_id bigint not null, " // channel cache later? something to think about... + + "created_ts timestamptz not null, " + + "edited_ts timestamptz null, " + + "message text not null, " + + $"FOREIGN KEY (author_id, guild_id) references {EntityCache.Sql.TableUser} (user_id, guild_id)" + + ")"; + // TODO figure out how to store message edits + c.ExecuteNonQuery(); + } + } + } + #endregion + + private async Task CacheMessage(SocketMessage msg) + { + try + { + using (var db = await _db.GetOpenConnectionAsync()) + { + using (var c = db.CreateCommand()) + { + c.CommandText = "INSERT INTO " + TableMessage + + " (message_id, author_id, guild_id, channel_id, created_ts, message) VALUES " + + "(@MessageId, @UserId, @GuildId, @ChannelId, @Date, @Message)"; + c.Parameters.Add("@MessageId", NpgsqlDbType.Bigint).Value = msg.Id; + c.Parameters.Add("@UserId", NpgsqlDbType.Bigint).Value = msg.Author.Id; + c.Parameters.Add("@GuildId", NpgsqlDbType.Bigint).Value = ((SocketGuildUser)msg.Author).Guild.Id; + c.Parameters.Add("@ChannelId", NpgsqlDbType.Bigint).Value = msg.Channel.Id; + c.Parameters.Add("@Date", NpgsqlDbType.TimestampTZ).Value = msg.Timestamp; + c.Parameters.Add("@Message", NpgsqlDbType.Text).Value = msg.Content; + c.Prepare(); + await c.ExecuteNonQueryAsync(); + } + } + } + catch (NpgsqlException ex) + { + await Log($"SQL error in {nameof(CacheMessage)}: " + ex.Message); + } + } + } +} diff --git a/Module/ModLogs/ModLogs.cs b/Module/ModLogs/ModLogs.cs new file mode 100644 index 0000000..14fc93b --- /dev/null +++ b/Module/ModLogs/ModLogs.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Noikoio.RegexBot.Module.ModLogs +{ + class ModLogs + { + } +} \ No newline at end of file