using System.Collections.Generic; using System.Threading.Tasks; using NodaTime; namespace PluralKit.Core { public enum AutoproxyMode { Off = 1, Front = 2, Latch = 3, Member = 4 } public class FullMessage { public PKMessage Message; public PKMember Member; public PKSystem System; } public struct PKMessage { public ulong Mid; public ulong? Guild; // null value means "no data" (ie. from before this field being added) public ulong Channel; public ulong Sender; public ulong? OriginalMid; } public struct ImportedSwitch { public Instant Timestamp; public IReadOnlyCollection Members; } public struct SwitchListEntry { public ICollection Members; public Instant TimespanStart; public Instant TimespanEnd; } public struct MemberMessageCount { public int Member; public int MessageCount; } public struct FrontBreakdown { public Dictionary MemberSwitchDurations; public Duration NoFronterDuration; public Instant RangeStart; public Instant RangeEnd; } public struct SwitchMembersListEntry { public int Member; public Instant Timestamp; } public struct GuildConfig { public ulong Id { get; set; } public ulong? LogChannel { get; set; } public ISet LogBlacklist { get; set; } public ISet Blacklist { get; set; } } public class SystemGuildSettings { public ulong Guild { get; set; } public bool ProxyEnabled { get; set; } = true; public AutoproxyMode AutoproxyMode { get; set; } = AutoproxyMode.Off; public int? AutoproxyMember { get; set; } } public class MemberGuildSettings { public int Member { get; set; } public ulong Guild { get; set; } public string DisplayName { get; set; } public string AvatarUrl { get; set; } } public interface IDataStore { /// /// Gets a system by its internal system ID. /// /// The with the given internal ID, or null if no system was found. Task GetSystemById(int systemId); /// /// Gets a system by its user-facing human ID. /// /// The with the given human ID, or null if no system was found. Task GetSystemByHid(string systemHid); /// /// Gets a system by one of its linked Discord account IDs. Multiple IDs can return the same system. /// /// The with the given linked account, or null if no system was found. Task GetSystemByAccount(ulong linkedAccount); /// /// Gets a system by its API token. /// /// The with the given API token, or null if no corresponding system was found. Task GetSystemByToken(string apiToken); /// /// Gets the Discord account IDs linked to a system. /// /// An enumerable of Discord account IDs linked to this system. Task> GetSystemAccounts(PKSystem system); /// /// Gets the member count of a system. /// /// Whether the returned count should include private members. Task GetSystemMemberCount(PKSystem system, bool includePrivate); /// /// Gets a list of members with proxy tags that conflict with the given tags. /// /// A set of proxy tags A conflict with proxy tags B if both A's prefix and suffix /// are a "subset" of B's. In other words, if A's prefix *starts* with B's prefix /// and A's suffix *ends* with B's suffix, the tag pairs are considered conflicting. /// /// The system to check in. Task> GetConflictingProxies(PKSystem system, ProxyTag tag); /// /// Gets a specific system's guild-specific settings for a given guild. /// Task GetSystemGuildSettings(PKSystem system, ulong guild); /// /// Saves a specific system's guild-specific settings. /// Task SetSystemGuildSettings(PKSystem system, ulong guild, SystemGuildSettings settings); /// /// Creates a system, auto-generating its corresponding IDs. /// /// An optional system name to set. If `null`, will not set a system name. /// The created system model. Task CreateSystem(string systemName); // TODO: throw exception if account is present (when adding) or account isn't present (when removing) /// /// Links a Discord account to a system. /// /// Throws an exception (TODO: which?) if the given account is already linked to a system. Task AddAccount(PKSystem system, ulong accountToAdd); /// /// Unlinks a Discord account from a system. /// /// Will *not* throw if this results in an orphaned system - this is the caller's responsibility to ensure. /// /// Throws an exception (TODO: which?) if the given account is not linked to the given system. Task RemoveAccount(PKSystem system, ulong accountToRemove); /// /// Saves the information within the given struct to the data store. /// Task SaveSystem(PKSystem system); /// /// Deletes the given system from the database. /// /// /// This will also delete all the system's members, all system switches, and every message that has been proxied /// by members in the system. /// Task DeleteSystem(PKSystem system); /// /// Gets a system by its internal member ID. /// /// The with the given internal ID, or null if no member was found. Task GetMemberById(int memberId); /// /// Gets a member by its user-facing human ID. /// /// The with the given human ID, or null if no member was found. Task GetMemberByHid(string memberHid); /// /// Gets a member by its member name within one system. /// /// /// Member names are *usually* unique within a system (but not always), whereas member names /// are almost certainly *not* unique globally - therefore only intra-system lookup is /// allowed. /// /// The with the given name, or null if no member was found. Task GetMemberByName(PKSystem system, string name); /// /// Gets all members inside a given system. /// /// An enumerable of structs representing each member in the system, in no particular order. IAsyncEnumerable GetSystemMembers(PKSystem system, bool orderByName = false); /// /// Gets the amount of messages proxied by a given member. /// /// The message count of the given member. Task GetMemberMessageCount(PKMember member); /// /// Collects a breakdown of each member in a system's message count. /// /// An enumerable of members along with their message counts. Task> GetMemberMessageCountBulk(PKSystem system); /// /// Creates a member, auto-generating its corresponding IDs. /// /// The system in which to create the member. /// The name of the member to create. /// The created system model. Task CreateMember(PKSystem system, string name); /// /// Creates multiple members, auto-generating each corresponding ID. /// /// The system to create the member in. /// A dictionary containing a mapping from an arbitrary key to the member's name. /// A dictionary containing the resulting member structs, each mapped to the key given in the argument dictionary. Task> CreateMembersBulk(PKSystem system, Dictionary memberNames); /// /// Saves the information within the given struct to the data store. /// Task SaveMember(PKMember member); /// /// Deletes the given member from the database. /// /// /// This will remove this member from any switches it's involved in, as well as all the messages /// proxied by this member. /// Task DeleteMember(PKMember member); /// /// Gets a specific member's guild-specific settings for a given guild. /// Task GetMemberGuildSettings(PKMember member, ulong guild); /// /// Saves a specific member's guild-specific settings. /// Task SetMemberGuildSettings(PKMember member, ulong guild, MemberGuildSettings settings); /// /// Gets a message and its information by its ID. /// /// The message ID to look up. This can be either the ID of the trigger message containing the proxy tags or the resulting proxied webhook message. /// An extended message object, containing not only the message data itself but the associated system and member structs. Task GetMessage(ulong id); // id is both original and trigger, also add return type struct /// /// Saves a posted message to the database. /// /// The ID of the account that sent the original trigger message. /// The ID of the guild the message was posted to. /// The ID of the channel the message was posted to. /// The ID of the message posted by the webhook. /// The ID of the original trigger message containing the proxy tags. /// The member (and by extension system) that was proxied. /// Task AddMessage(ulong senderAccount, ulong guildId, ulong channelId, ulong postedMessageId, ulong triggerMessageId, PKMember proxiedMember); /// /// Deletes a message from the data store. /// /// The ID of the webhook message to delete. Task DeleteMessage(ulong postedMessageId); /// /// Deletes messages from the data store in bulk. /// /// The IDs of the webhook messages to delete. Task DeleteMessagesBulk(IEnumerable postedMessageIds); /// /// Gets the most recent message sent by a given account in a given guild. /// /// The full message object, or null if none was found. Task GetLastMessageInGuild(ulong account, ulong guild); /// /// Gets switches from a system. /// /// An enumerable of the *count* latest switches in the system, in latest-first order. May contain fewer elements than requested. IAsyncEnumerable GetSwitches(PKSystem system); /// /// Gets the total amount of switches in a given system. /// Task GetSwitchCount(PKSystem system); /// /// Gets the latest (temporally; closest to now) switch of a given system. /// Task GetLatestSwitch(PKSystem system); /// /// Gets the members a given switch consists of. /// IAsyncEnumerable GetSwitchMembers(PKSwitch sw); /// /// Gets a list of fronters over a given period of time. /// /// /// This list is returned as an enumerable of "switch members", each containing a timestamp /// and a member ID. /// /// Switches containing multiple members will be returned as multiple switch members each with the same /// timestamp, and a change in timestamp should be interpreted as the start of a new switch. /// /// An enumerable of the aforementioned "switch members". Task> GetPeriodFronters(PKSystem system, Instant periodStart, Instant periodEnd); /// /// Calculates a breakdown of a system's fronters over a given period, including how long each member has /// been fronting, and how long *no* member has been fronting. /// /// /// Switches containing multiple members will count the full switch duration for all members, meaning /// the total duration may add up to longer than the breakdown period. /// /// /// /// /// Task GetFrontBreakdown(PKSystem system, Instant periodStart, Instant periodEnd); /// /// Gets the first listed fronter in a system. /// /// The first fronter, or null if none are registered. Task GetFirstFronter(PKSystem system); /// /// Registers a switch with the given members in the given system. /// /// Throws an exception (TODO: which?) if any of the members are not in the given system. Task AddSwitch(PKSystem system, IEnumerable switchMembers); /// /// Registers switches in bulk. /// /// A list of switch structs, each containing a timestamp and a list of members. /// Throws an exception (TODO: which?) if any of the given members are not in the given system. Task AddSwitchesBulk(PKSystem system, IEnumerable switches); /// /// Updates the timestamp of a given switch. /// Task MoveSwitch(PKSwitch sw, Instant time); /// /// Deletes a given switch from the data store. /// Task DeleteSwitch(PKSwitch sw); /// /// Deletes all switches in a given system from the data store. /// Task DeleteAllSwitches(PKSystem system); /// /// Gets the total amount of systems in the data store. /// Task GetTotalSystems(); /// /// Gets the total amount of members in the data store. /// Task GetTotalMembers(); /// /// Gets the total amount of switches in the data store. /// Task GetTotalSwitches(); /// /// Gets the total amount of messages in the data store. /// Task GetTotalMessages(); /// /// Gets the guild configuration struct for a given guild, creating and saving one if none was found. /// /// The guild's configuration struct. Task GetOrCreateGuildConfig(ulong guild); /// /// Saves the given guild configuration struct to the data store. /// Task SaveGuildConfig(GuildConfig cfg); } }