From 404f51347d247af9ba16ecb1deda5b41699b444a Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 00:56:13 +1200 Subject: [PATCH 01/25] Updated data files The first of many commits --- src/EllieBot/data/aliases.yml | 14 +- src/EllieBot/data/gambling.yml | 2 +- src/EllieBot/data/games.yml | 74 ++++ src/EllieBot/data/patron.yml | 119 +++--- .../data/strings/commands/commands.en-US.yml | 400 ++++++++++-------- .../strings/responses/responses.en-US.json | 10 +- 6 files changed, 370 insertions(+), 249 deletions(-) create mode 100644 src/EllieBot/data/games.yml diff --git a/src/EllieBot/data/aliases.yml b/src/EllieBot/data/aliases.yml index 8d83875..678eaa6 100644 --- a/src/EllieBot/data/aliases.yml +++ b/src/EllieBot/data/aliases.yml @@ -773,6 +773,7 @@ listservers: - listservers cleverbot: - cleverbot + - chatbot - chatgpt shorten: - shorten @@ -1161,15 +1162,6 @@ massban: - massban masskill: - masskill -pathofexile: - - pathofexile - - poe -pathofexileleagues: - - pathofexileleagues - - poel -pathofexilecurrency: - - pathofexilecurrency - - poec rollduel: - rollduel reroadd: @@ -1406,4 +1398,6 @@ todoshow: stickyroles: - stickyroles cleanupguilddata: - - cleanupguilddata \ No newline at end of file + - cleanupguilddata +prompt: + - prompt \ No newline at end of file diff --git a/src/EllieBot/data/gambling.yml b/src/EllieBot/data/gambling.yml index be44a45..fbcbdc4 100644 --- a/src/EllieBot/data/gambling.yml +++ b/src/EllieBot/data/gambling.yml @@ -5,7 +5,7 @@ currency: # What is the emoji/character which represents the currency sign: "💵" # What is the name of the currency - name: Ellie Money + name: Ellie Cash # For how long (in days) will the transactions be kept in the database (curtrs) # Set 0 to disable cleanup (keep transactions forever) transactionsLifetime: 0 diff --git a/src/EllieBot/data/games.yml b/src/EllieBot/data/games.yml new file mode 100644 index 0000000..b46f69e --- /dev/null +++ b/src/EllieBot/data/games.yml @@ -0,0 +1,74 @@ +# DO NOT CHANGE +version: 4 +# Hangman related settings (.hangman command) +hangman: + # The amount of currency awarded to the winner of a hangman game + currencyReward: 0 +# Trivia related settings (.t command) +trivia: + # The amount of currency awarded to the winner of the trivia game. + currencyReward: 0 + # Users won't be able to start trivia games which have + # a smaller win requirement than the one specified by this setting. + minimumWinReq: 1 +# List of responses for the .8ball command. A random one will be selected every time +eightBallResponses: + - Most definitely yes. + - For sure. + - Totally! + - Of course! + - As I see it, yes. + - My sources say yes. + - Yes. + - Most likely. + - Perhaps... + - Maybe... + - Hm, not sure. + - It is uncertain. + - Ask me again later. + - Don't count on it. + - Probably not. + - Very doubtful. + - Most likely no. + - Nope. + - No. + - My sources say no. + - Don't even think about it. + - Definitely no. + - NO - It may cause disease contraction! +# List of animals which will be used for the animal race game (.race) +raceAnimals: + - icon: "🐼" + name: Panda + - icon: "🐻" + name: Bear + - icon: "🐧" + name: Pengu + - icon: "🐨" + name: Koala + - icon: "🐬" + name: Dolphin + - icon: "🐞" + name: Ladybird + - icon: "🦀" + name: Crab + - icon: "🦄" + name: Unicorn +# Which chatbot API should bot use. +# 'cleverbot' - bot will use Cleverbot API. +# 'gpt' - bot will use GPT API +chatBot: Gpt +chatGpt: + # Which GPT Model should bot use. + # gpt35turbo - cheapest + # gpt4o - more expensive, higher quality + # + modelName: Gpt35Turbo + # How should the chat bot behave, what's its personality? (Usage of this counts towards the max tokens) + personalityPrompt: You are a chat bot willing to have a conversation with anyone about anything. + # The maximum number of messages in a conversation that can be remembered. (This will increase the number of tokens used) + chatHistory: 5 + # The maximum number of tokens to use per GPT API call + maxTokens: 100 + # The minimum number of tokens to use per GPT API call, such that chat history is removed to make room. + minTokens: 30 diff --git a/src/EllieBot/data/patron.yml b/src/EllieBot/data/patron.yml index 6485e1c..632a3e6 100644 --- a/src/EllieBot/data/patron.yml +++ b/src/EllieBot/data/patron.yml @@ -1,69 +1,56 @@ # DO NOT CHANGE -version: 2 +version: 3 # Whether the patronage feature is enabled isEnabled: false -# List of patron only features and relevant quota data -quotas: -# Dictionary of feature names with their respective limits. Set to null for unlimited - features: - timely:extra_percent: - V: 10 - X: 22 - XX: 50 - L: 150 - C: 350 - rero:max_count: - V: 25 - X: 50 - cleverbot:response: - V: -20 - X: 5000 - XX: 12000 - L: 35000 - C: 100000 - # Dictionary of commands with their respective quota data - commands: - cleverbot: - V: - prune: - X: - PerHour: 1 - XX: - PerHour: 3 - google: - V: - PerDay: 15 - X: - PerDay: 30 - XX: - PerDay: 60 - L: - PerDay: 150 - C: - PerDay: 300 - image: - V: - PerDay: 15 - X: - PerDay: 30 - XX: - PerDay: 60 - L: - PerDay: 150 - C: - PerDay: 300 - youtube: - V: - PerDay: 25 - X: - PerDay: 50 - XX: - PerDay: 100 - L: - PerDay: 250 - C: - PerDay: 500 - # Dictionary of groups with their respective quota data - groups: {} - # Dictionary of modules with their respective quota data - modules: {} +# Who can do how much of what +limits: + 100: + ChatBot: + quota: 50000000 + quotaPeriod: PerMonth + ReactionRole: + quota: -1 + quotaPeriod: Total + Prune: + quota: -1 + quotaPeriod: PerDay + 50: + ChatBot: + quota: 20000000 + quotaPeriod: PerMonth + ReactionRole: + quota: -1 + quotaPeriod: Total + Prune: + quota: -1 + quotaPeriod: PerDay + 20: + ChatBot: + quota: 6500000 + quotaPeriod: PerMonth + ReactionRole: + quota: -1 + quotaPeriod: Total + Prune: + quota: 20 + quotaPeriod: PerDay + 10: + ChatBot: + quota: 2500000 + quotaPeriod: PerMonth + ReactionRole: + quota: 50 + quotaPeriod: Total + Prune: + quota: 5 + quotaPeriod: PerDay + 5: + ChatBot: + quota: 1000000 + quotaPeriod: PerMonth + ReactionRole: + quota: 25 + quotaPeriod: Total + Prune: + quota: 2 + quotaPeriod: PerDay diff --git a/src/EllieBot/data/strings/commands/commands.en-US.yml b/src/EllieBot/data/strings/commands/commands.en-US.yml index d64534e..a486970 100644 --- a/src/EllieBot/data/strings/commands/commands.en-US.yml +++ b/src/EllieBot/data/strings/commands/commands.en-US.yml @@ -1,51 +1,59 @@ h: - desc: Either shows a help for a single command, or DMs you help link if no parameters are specified. + desc: |- + Shows help for a single command. + Command help contains instructions on how to use the command with examples and a list of parameters. + DMs you helpful links if no parameters are specified. ex: - '{0}cmds' - '' params: + - com: + desc: "The command that help is being requested for." - fail: desc: "Fallback parameter if the command is not found." - - com: - desc: "The command information that the help is being requested for." gencmdlist: - desc: Generates the command list and sends it to the chat. Optionally also uploads it to DO spaces (not supported). + desc: Generates a json of the commands list and sends it to the chat. ex: - '' params: - {} donate: - desc: Instructions for helping the project financially. + desc: Provides instructions for helping the project financially. ex: - '' params: - {} modules: - desc: Lists all bot modules. + desc: |- + List all of the bot's modules. + Each module contains commands that you can use. ex: - '' params: - page: - desc: "The number of the page to display in the list of bot modules." + desc: "The page number to display in the list of modules." commands: - desc: List all of the bot's commands from the specified module. You can either specify the full name or only the first few letters of the module name. Specifying no module will show the list of modules instead. + desc: |- + List all of the bot's commands in the specified module. + You can either specify the full name or only the first few letters of the module name. + Specifying no module will show the list of modules instead. ex: - Admin - Admin --view 1 - '' params: - module: - desc: "The name of a module to retrieve command information for." + desc: "The name of the module to retrieve commands from." params: - desc: "The names of one or more modules to retrieve commands from, allowing for partial matching and optional omission." + desc: "How to display the list of commands." greetdel: - desc: Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. + desc: Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to `0` to disable automatic deletion. ex: - 0 - 30 params: - timer: - desc: "The amount of time before greeting messages are automatically deleted from the chat." + desc: "The amount of seconds before greeting messages are automatically deleted." greet: desc: Toggles announcements on the current channel when someone joins the server. ex: @@ -54,11 +62,11 @@ greet: - {} greetmsg: desc: |- - Sets a new join announcement message which will be shown in the server's channel. - Type `%user.mention%` if you want to mention the new member. + Sets a new join announcement message which will be shown in the current channel. + Write `%user.mention%` if you want to mention the new member. Full list of placeholders can be found here - Using it with no message will show the current greet message. - You can use embed json from instead of a regular text, if you want the message to be embedded. + Using this command with no message will show the current greet message. + You can use embed json from instead of regular text, if you want the message to be embedded. ex: - Welcome, %user.mention%. params: @@ -72,16 +80,16 @@ bye: - {} byemsg: desc: |- - Sets a new leave announcement message. - Type `%user.mention%` if you want to show the name the user who left. + Sets a new leave announcement message which will be shown in the current channel. + Type `%user.name%` to show the name of the user who left. Full list of placeholders can be found here Using this command with no message will show the current bye message. - You can use embed json from instead of a regular text, if you want the message to be embedded. + You can use embed json from instead of regular text, if you want the message to be embedded. ex: - - '%user.mention% has left.' + - '%user.name% has left.' params: - text: - desc: "The user's farewell message to display when they leave the chat." + desc: "The new announcement message to be displayed when a user leaves the server." byedel: desc: Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. ex: @@ -89,9 +97,9 @@ byedel: - 30 params: - timer: - desc: "The amount of time before a bye message is automatically deleted." + desc: "The amount of seconds before goodbye messages are automatically deleted." greetdm: - desc: Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). + desc: Toggles whether greet messages will be sent in a DM (This is separate from `{0}greet` - you can have both, one or neither enabled). ex: - '' params: @@ -103,7 +111,7 @@ greettest: - '@SomeoneElse' params: - user: - desc: "The user to impersonate when sending the greeting, or null for the bot's own account." + desc: "The user to impersonate when sending the greeting, defaulting to yourself if not specified." greetdmtest: desc: Sends the greet direct message to you as if you just joined the server. You can optionally specify a different user. ex: @@ -111,7 +119,7 @@ greetdmtest: - '@SomeoneElse' params: - user: - desc: "The recipient of the greeting, which defaults to the caller if not specified." + desc: "The recipient of the greeting, defaulting to yourself if not specified." byetest: desc: Sends the bye message in the current channel as if you just left the server. You can optionally specify a different user. ex: @@ -119,7 +127,7 @@ byetest: - '@SomeoneElse' params: - user: - desc: "The user who is leaving the channel, or whose account is being represented as leaving the channel." + desc: "The user to impersonate when sending the farewell, defaulting to yourself if not specified." boost: desc: Toggles announcements on the current channel when someone boosts the server. ex: @@ -128,16 +136,16 @@ boost: - {} boostmsg: desc: |- - Sets a new boost announcement message. - Type `%user.mention%` if you want to show the name the user who left. + Sets a new boost announcement message which will be shown in the current channel. + Type `%user.mention%` if you want to mention the booster. Full list of placeholders can be found here Using this command with no message will show the current boost message. - You can use embed json from instead of a regular text, if you want the message to be embedded. + You can use embed json from instead of regular text, if you want the message to be embedded. ex: - '%user.mention% has boosted the server!!!' params: - text: - desc: "The text to set as the new announcement message." + desc: "The new announcement message to be displayed when a user boosts the server." boostdel: desc: Sets the time it takes (in seconds) for boost messages to be auto-deleted. Set it to `0` to disable automatic deletion. ex: @@ -145,7 +153,7 @@ boostdel: - 30 params: - timer: - desc: "The amount of time before boost messages are automatically deleted." + desc: "The amount of seconds before boost messages are automatically deleted." logserver: desc: Enables or Disables ALL log events. If enabled, all log events will log to this channel. ex: @@ -153,9 +161,9 @@ logserver: - disable params: - action: - desc: "The type of action to take on the log event." + desc: "The type of action to take." logignore: - desc: Toggles whether the `{0}logserver` command ignores the specified channel or user. Provide no arguments to see the list of currently ignored users and channels + desc: Toggles whether the `{0}log` and `{0}logserver` commands ignore the specified channel or user. Provide no arguments to see the list of currently ignored users and channels. ex: - '' - '@SomeUser' @@ -167,32 +175,32 @@ logignore: - target: desc: "The user or channel being targeted for logging ignore or inclusion." repeatlist: - desc: Shows currently repeating messages and their indexes. + desc: Lists currently repeating messages and their indexes. ex: - '' params: - {} repeatremove: - desc: Removes a repeating message on a specified index. Use `{0}repeatlist` to see indexes. + desc: Removes a repeating message by index. Use `{0}replst` to see indexes. ex: - 2 params: - index: - desc: "The index at which the repeating message should be removed." + desc: "The index of the repeating message to be removed." repeatinvoke: - desc: Immediately shows the repeat message on a certain index and restarts its timer. + desc: Immediately post the repeat message on a certain index and restarts its timer. ex: - 1 params: - index: - desc: "The index at which to display the repeat message." + desc: "The index of the repeating message to post." repeat: desc: |- - Repeat a message once every specified amount of time in the current channel. - You can specify a different channel as the first argument. - You can instead specify time of day for the message to be repeated daily (make sure you've set your server's timezone). - If you've specified time of day, you can still override the default daily interval with your own interval. - You can have up to 5 repeating messages on the server in total. + Repeat a message once per specified time increment in the current channel. + You can specify a different channel as the first argument instead. + You can also specify time of day for the message to be repeated daily (make sure you've set your server's `{0}timezone`). + If you specify time of day, you can still override the default daily interval with your own interval. + You can have up to 5 repeating messages on one server in total. ex: - Hello there - '#other-channel hello there' @@ -202,59 +210,63 @@ repeat: - '21:00 30m Starting at 21 and every 30 minutes after that i will send this message!' params: - message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - channel: desc: "The channel where the message will be repeated." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - interval: desc: "The amount of time between each repetition." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - channel: desc: "The channel where the message will be sent." interval: desc: "The amount of time between each repetition." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - timeOfDay: - desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + desc: "The time at which the message should begin being repeated." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - channel: desc: "The channel where the message will be repeated." timeOfDay: - desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + desc: "The time at which the message should begin being repeated." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - timeOfDay: - desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + desc: "The time at which the message should begin being repeated." interval: desc: "The amount of time between each repetition." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." - channel: desc: "The channel where the message will be repeated." timeOfDay: - desc: "The time at which the message should be repeated, either once every specified amount of time or at a specific time of day." + desc: "The time at which the message should begin being repeated." interval: desc: "The amount of time between each repetition." message: - desc: "The text to be repeated at the specified intervals or times." + desc: "The text to be repeated." repeatredundant: - desc: Specify repeater's index (use `{0}repli` to find it) to toggle whether that repeater's message should be reposted if the last message in the channel is the same repeater's message. This is useful if you want to remind everyone to be nice in the channel every so often, but don't want to have the bot spam the channel. This is NOT useful if you want to periodically ping someone. + desc: |- + Specify repeater's index (Use `{0}replst` to see indexes) to toggle whether the message should be reposted if the last message in the channel is the same repeater's message. + This is useful if you want to remind everyone to be nice every so often, but don't want to have the bot spam the channel. This is NOT useful if you want to periodically ping someone. ex: - 1 params: - index: - desc: "The number of times a message should be repeated before reposting." + desc: "The index of the repeating message to modify." repeatskip: - desc: Specify a repeater's ID to toggle whether the next trigger of the repeater will be skipped. This setting is not stored in the database and will get reset if the bot is restarted. + desc: |- + Specify a repeater's ID to toggle whether the next trigger of the repeater will be skipped. + This setting is not stored in the database and will get reset if the bot is restarted. ex: - 3 params: - index: - desc: "The number of times to skip before triggering again." + desc: "The index of the repeating message to skip." rotateplaying: desc: Toggles rotation of playing status of the dynamic strings you previously specified. ex: @@ -262,28 +274,28 @@ rotateplaying: params: - {} addplaying: - desc: Adds a specified string to the list of playing strings to rotate. You have to pick either 'Playing', 'Watching' or 'Listening' as the first parameter. + desc: Adds a specified string to the list of playing strings to rotate. You have to pick either `Playing`, `Watching` or `Listening` as the first parameter. ex: - Playing with you - Watching you sleep params: - t: - desc: "The type of status, allowed values are 'Playing', 'Watching', or 'Listening'." + desc: "The type of status, allowed values are `Playing`, `Watching`, or `Listening`." status: desc: "The status text." listplaying: - desc: Lists all playing statuses with their corresponding number. + desc: Lists all playing statuses and their indexes. ex: - '' params: - {} removeplaying: - desc: Removes a playing string on a given number. + desc: Removes a playing status by index. Use `{0}lipl` to see indexes. ex: - '' params: - index: - desc: "The position in the list where the playing string should be removed." + desc: "The index of the playing string to be removed." vcrolelist: desc: Shows a list of currently set voice channel roles. ex: @@ -297,16 +309,16 @@ vcrole: - '' params: - role: - desc: "The role that is assigned to new members of the voice channel." + desc: "The role to assign to users who join the voice channel." vcrolerm: - desc: Removes vcrole associated with the specified voice channel ID. This is useful if your vcrole has been enabled on a VC which has been deleted. + desc: Removes any `{0}vcrole` associated with the specified channel ID. This is useful if your vcrole has been enabled on a VC which has been deleted. ex: - 123123123123123 params: - vcId: - desc: "The unique identifier of the voice channel to remove the vcrole from." + desc: "The voice channel ID to remove the vcrole from." asar: - desc: Adds a role to the list of self-assignable roles. You can also specify a group. If 'Exclusive self-assignable roles' feature is enabled, users will be able to pick one role per group. + desc: Adds a role to the list of self-assignable roles. You can also specify a group. If 'Exclusive self-assignable roles' feature is enabled (`{0}tesar`), users will be able to pick one role per group. ex: - Gamer - 1 Alliance @@ -315,7 +327,7 @@ asar: - role: desc: "The role that can be assigned by the user." - group: - desc: "The ID of a group that the new role should belong to." + desc: "The ID of a group that the designated role should belong to." role: desc: "The role that can be assigned by the user." rsar: @@ -326,7 +338,7 @@ rsar: - Horde params: - role: - desc: "The role being removed from the list of self-assignable roles." + desc: "The role to remove from the list of self-assignable roles." lsar: desc: Lists self-assignable roles. Shows 20 roles per page. ex: @@ -334,7 +346,7 @@ lsar: - 2 params: - page: - desc: "The current page number for the list of roles." + desc: "The page number to show." sargn: desc: Sets a self assignable role group name. Provide no name to remove. ex: @@ -342,59 +354,58 @@ sargn: - 2 params: - group: - desc: "The ID of the group to set as self-assignable." + desc: "The ID of the group to name." name: - desc: "The name of the new or existing role group to set." + desc: "The name to assign." togglexclsar: - desc: Toggles whether the self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group. + desc: Toggles whether self-assigned roles are exclusive. While enabled, users can only have one self-assignable role per group. ex: - '' params: - {} iam: - desc: Adds a role to you that you choose. Role must be on a list of self-assignable roles. + desc: Adds a role to you that you choose. Role must be on the list of self-assignable roles. ex: - Gamer params: - role: - desc: "The type of access or permission granted to the user." + desc: "The role to assign." iamnot: - desc: Removes a specified role from you. Role must be on a list of self-assignable roles. + desc: Removes a specified role from you. Role must be on the list of self-assignable roles. ex: - Gamer params: - role: - desc: "The role being removed from the user's assignment." + desc: "The role to remove." expradd: - desc: 'Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide here: ' + desc: 'Add an expression with a trigger and a response. Bot will post a response whenever someone types the trigger word. Running this command in a server requires the Administrator permission. Running this command in DM is Bot Owner only and adds a new global expression. Guide [here]()' ex: - '"hello" Hi there %user.mention%' params: - trigger: - desc: "The trigger word that sets off the response when typed by a user." + desc: "The trigger word or phrase for the bot to respond to users typing." response: desc: "The text of the message that shows up when a user types the trigger word." expraddserver: - desc: 'Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. Guide here: ' + desc: 'Add an expression with a trigger and a response in this server. Bot will post a response whenever someone types the trigger word. This command is useful if you want to lower the permission requirement for managing expressions by using `{0}dpo`. Guide [here]().' ex: - '"hello" Hi there %user.mention%' params: - key: - desc: "The unique identifier for the expression to be added in this server." + desc: "The trigger word or phrase for the bot to respond to users typing." message: - desc: "The text of the message that triggers the bot's response." + desc: "The text of the message that shows up when a user types the trigger word." exprlist: desc: |- - Lists global or server expressions (20 commands per page). + Lists global or server expressions (20 expressions per page). Running the command in DM will list global expressions, while running it in a server will list server expressions. Shows enabled settings, followed by id, followed by the trigger. **Settings:** - • 🗯️ Triggered if trigger matches any word (`{0}h {0}exca`) - • ✉️ Response will be DMed (`{0}h {0}exdm`) - • ❌ Trigger will be deleted (`{0}h {0}exad`) + • 🗯️ Triggered if trigger matches any phrase (`{0}h exca`) + • ✉️ Response will be DMed (`{0}h exdm`) + • ❌ Trigger message will be deleted (`{0}h exad`) ex: - 1 - - all params: - page: desc: "The number of pages to display in the list." @@ -404,21 +415,21 @@ exprshow: - 1 params: - id: - desc: "The identifier for the entity whose response is being displayed." + desc: "The expression ID to show." exprdelete: - desc: Deletes an expression on a specific index. If ran in DM, it is bot owner only and deletes a global expression. If ran in a server, it requires Administration privileges and removes server expression. + desc: Deletes an expression by index. If ran in DM, it is bot owner only and deletes a global expression. Running this command in a server requires the Administrator permission and deletes a server expression. ex: - 5 params: - id: - desc: "The identifier of the expression to be deleted." + desc: "The ID of the expression to delete." exprdeleteserver: - desc: Deletes an expression on a specific index on this server. + desc: Deletes an expression on a specific index on this server. This command is useful if you want to lower the permission requirement for managing expressions by using `{0}dpo`. ex: - 5c params: - id: - desc: "The identifier of the expression to be deleted." + desc: "The ID of the expression to delete." exprclear: desc: Deletes all expression on this server. ex: @@ -843,7 +854,12 @@ savechat: - cnt: desc: "The number of messages to be saved." remind: - desc: "Sends a message to you or a channel after certain amount of time (max 2 months). First parameter is `me`/`here`/'channelname'. Second parameter is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third parameter is a (multiword) message. Requires ManageMessages server permission if you're targeting a different channel." + desc: |- + Sets a reminder which will be sent to you or to the targeted channel after certain amount of time (max 2 months). + First parameter is `me` / `here` / 'channelname' + Second parameter is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. + Third parameter is a (multiword) message. + Requires ManageMessages server permission if you're targeting a different channel. ex: - me 1d5h Do something - '#general 1m Start now!' @@ -1336,7 +1352,11 @@ flip: - count: desc: "The number of times the coin is flipped." betflip: - desc: Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. + desc: |- + Bet to guess will the result be heads or tails. + Guessing awards you 1.95x the currency you've bet (rounded up). + Multiplier can be changed by the bot owner. + ex: - 5 heads - 3 t @@ -1482,38 +1502,52 @@ take: usrId: desc: "The ID of the user whose funds are being taken." betroll: - desc: Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. + desc: |- + Bets the specified amount of currency and rolls a dice. + Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. + You can type 'all', 'half' or 'X%' to bet that part of your current balance. ex: - 5 params: - amount: desc: "The amount to be wagered on the roll of the dice." luckyladder: - desc: Bets a certain amount of currency on the lucky ladder. You can stop on one of many different multipliers. Won amount is rounded down to the nearest whole number. + desc: + Bets the specified amount of currency on the lucky ladder. + You can stop on one of many different multipliers. + The won amount is rounded down to the nearest whole number. + You can type 'all', 'half' or 'X%' to bet that part of your current balance. ex: - 10 params: - amount: desc: "The total value of the bet being placed." leaderboard: - desc: Displays the bot's currency leaderboard. + desc: |- + Displays the bot's currency leaderboard, or in other words, the richest users. + Specifying -c flag will show only users who are in this server. + Paginated with 10 users per page. ex: - '' + - '-c' params: - params: - desc: "The list of player names or IDs to display in the leaderboard." + desc: "Optional -c flag" - page: - desc: "The number of pages to display in the leaderboard." + desc: "The page number to display." params: - desc: "The list of player names or IDs to display in the leaderboard." + desc: "Optional -c flag." trivia: - desc: Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. + desc: |- + Starts a game of trivia. + First player to get to 10 points wins by default. + 30 seconds per question. ex: - '' - --timeout 5 -p -w 3 -q 10 params: - params: - desc: "The list of questions and answers for the trivia game." + desc: "Options. --timeout , --pokemon, --win --question " tl: desc: Shows a current trivia leaderboard. ex: @@ -1585,7 +1619,10 @@ choose: - list: desc: "The type of items in the collection being searched." rps: - desc: Play a game of Rocket-Paperclip-Scissors with Ellie. You can bet on it. Multiplier is the same as on betflip. + desc: |- + Play a game of Rocket-Paperclip-Scissors with Ellie. + You can bet on it. Multiplier is the same as on betflip. + You can type 'all', 'half' or 'X%' to bet that part of your current balance. ex: - r 100 - scissors @@ -1593,7 +1630,7 @@ rps: - pick: desc: "The user's chosen move in the game, such as rock, paper or scissors." amount: - desc: "The stake to be wagered on the outcome of the game." + desc: "Optional amount of currency to be wagered on the outcome of the game." next: desc: Goes to the next song in the queue. You have to be in the same voice channel as the bot ex: @@ -1601,7 +1638,12 @@ next: params: - {} play: - desc: If no parameters are specified, acts as `{0}next 1` command. If you specify a song number, it will jump to that song. If you specify a search query, acts as a `{0}q` command + desc: |- + Queues up and plays a song or video based on a search query, song name, artist name or youtube link. + If no parameters are specified, it will skip the current song. + If you specify a song number, it will jump to that song. + If you specify a search query, acts as a `{0}q` command + **You must be in a voice channel**. ex: - '' - 5 @@ -1631,7 +1673,10 @@ pause: params: - {} queue: - desc: Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**. + desc: |- + Queues up and plays a song or video based on a search query, song name, artist name, search query or youtube link. + Bot will join your voice channel. + **You must be in a voice channel**. ex: - Dream Of Venice params: @@ -1946,12 +1991,12 @@ memegen: memeText: desc: "The user-provided text to be displayed on the generated meme." weather: - desc: Shows weather data for a specified city. You can also specify a country after a comma. + desc: Shows current weather data for the specified city. ex: - - Moscow, RU + - Auckland, NZ params: - query: - desc: "The location to retrieve weather information for." + desc: "The name of the place or city for which to show the weather data." youtube: desc: Searches youtubes and shows the first result ex: @@ -2142,7 +2187,9 @@ greetdmmsg: - text: desc: "The new join announcement message that will be sent to the user who joined." cash: - desc: Check how much currency a person has. If no argument is provided it will check your own balance. + desc: |- + Check how much currency a person has. + If no argument is provided it will check your own balance. ex: - '' - '@Someone' @@ -2493,7 +2540,10 @@ listservers: - page: desc: "The number of pages to retrieve from the server list." cleverbot: - desc: Toggles cleverbot/chatgpt session. When enabled, the bot will reply to messages starting with bot mention in the server. Expressions starting with %bot.mention% won't work if cleverbot/chatgpt is enabled. + desc: |- + Toggles cleverbot/chatgpt session. + When enabled, the bot will reply to messages starting with bot mention in the server. + Expressions starting with %bot.mention% won't work if cleverbot/chatgpt is enabled. ex: - '' params: @@ -2628,7 +2678,9 @@ antispamignore: params: - {} eventstart: - desc: 'Starts one of the events seen on public ellie. Events: `reaction`, `gamestatus`' + desc: |- + Starts one of the events seen on public Ellie. + Events: `reaction`, `gamestatus` ex: - reaction - reaction -d 1 -a 50 --pot-size 1500 @@ -2636,20 +2688,24 @@ eventstart: - ev: desc: "The type of event being started." options: - desc: "The types of events that can be started." + desc: "The optional option flags for the event." betstats: - desc: Shows the total stats of several gambling features. Updates once an hour. + desc: |- + Shows the total stats of several gambling features. + Updates once an hour. ex: - '' params: - {} slot: - desc: Play Ellie slots. 1 second cooldown per user. + desc: |- + Play Ellie slots by placing your bet. + You can type 'all', 'half' or 'X%' to bet that part of your current balance. ex: - 5 params: - amount: - desc: "The number of spins to perform in the game." + desc: "The amount of currency to bet." affinity: desc: Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `{0}claim` on you by 20%. Provide no parameters to clear your affinity. 30 minutes cooldown. ex: @@ -2687,7 +2743,11 @@ waifutransfer: newOwner: desc: "The user to whom ownership of the waifu is being transferred." waifugift: - desc: -| Gift an item to someone. This will increase their waifu value by a percentage of the gift's value. Negative gifts will not show up in waifuinfo. Provide no parameters to see a list of items that you can gift. + desc: -| + Gift an item to someone. + This will increase their waifu value by a percentage of the gift's value. + Negative gifts will not show up in waifuinfo. + Provide no parameters to see a list of items that you can gift. ex: - '' - Rose @Himesama @@ -2782,7 +2842,10 @@ restartshard: - shardId: desc: "The ID of the shard to be restarted or reconnected." tictactoe: - desc: Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. + desc: |- + Starts a game of tic tac toe. + Another user must run the command in the same channel in order to accept the challenge. + Use numbers 1-9 to play. ex: - '' params: @@ -3018,7 +3081,7 @@ autocommandslist: unban: desc: Unbans a user with the provided user#discrim or id. ex: - - kwoth#1234 + - toastie_t0ast - 123123123 params: - user: @@ -3146,27 +3209,38 @@ shop: - page: desc: "The number of the page to retrieve from the list of administrators' shops." shopadd: - desc: "- Available types are role, list and command.\n- If the item is a role, specify a role id or a role name.\n- If the item is a command, specify the full command, replacing the user with %user% (for a mention) or %user.id% for user id.\n90% of currency from each purchase will be received by the user who added the item to the shop. " + desc: |- + Adds an item to the shop. + First you begin by specifying the type of the item you wish to add. + Available types are role, list and command. + If the item is a role, specify a role id or a role name. + In case you're selling a command, and you need user's name, id etc, you can use the following placeholders: + - `%you%` - Buyer mention + - `%you.id%` - Buyer's user ID + - `%you.username%` - Buyer's username + - `%you.name%` - Buyer's global name + - `%you.nick%` - Buyer's display name + 90% of currency from each purchase will be received by the user who added the item to the shop. This is configurable by the bot owner ex: - role 1000 Rich - cmd 1000 .setrole %user% Rich params: - _: - desc: "The command to be executed when an item is purchased." + desc: "This value has to be 'cmd'" price: - desc: "The cost at which the item is available for purchase." + desc: "The cost at which the command is available for purchase." command: - desc: "The full command, replacing the user with %user% (for a mention) or %user.id% for user id. This allows users to specify custom" + desc: "The full command, replacing the buyer info (if required) with some of the special %you% placeholders." - _: - desc: "The role that should be granted to users when they purchase this item." + desc: "This value has to be 'list'" price: desc: "The cost at which the item is available for purchase." role: - desc: "The ID or name of a predefined role in the system, used to specify the type of item being added to the shop." + desc: "The item (text) that is being sold." - _: - desc: "The list of items to be added to the shop." + desc: "This value has to be 'role'" price: - desc: "The cost at which the item is available for purchase." + desc: "The cost at which the role is available for purchase." name: desc: "The name of the role, command, or list being added to the shop." shopremove: @@ -3359,7 +3433,7 @@ experience: - '@someguy' params: - user: - desc: "The ID or handle of a player whose XP statistics are being displayed." + desc: "Optional name, mention or ID of the user" xptemplatereload: desc: Reloads the xp template file. Xp template file allows you to customize the position and color of elements on the `{0}xp` card. ex: @@ -3803,7 +3877,10 @@ timelyset: period: desc: "The time period within which a user's timely currency allowance can be used." timely: - desc: Use to claim your 'timely' currency. Bot owner has to specify the amount and the period on how often you can claim your currency. + desc: |- + Use to claim your timely currency. + This is usually set by the bot owners to be daily, hourly or once every 12 hours. + Bot owner has to specify the amount and the period on how often you can claim your currency. ex: - '' params: @@ -3848,40 +3925,12 @@ massban: - userStrings: desc: "The list of user IDs to ban, provided as a comma-separated string." masskill: - desc: Specify a new-line separated list of `userid reason`. You can use Username#discrim instead of UserId. Specified users will be banned from the current server, blacklisted from the bot, and have all of their flowers taken away. + desc: Specify a new-line separated list of `userid reason`. You can use Username#discrim instead of UserId. Specified users will be banned from the current server, blacklisted from the bot, and have all of their currency taken away. ex: - BadPerson#1234 Toxic person params: - people: desc: "The list of user IDs or usernames to ban from the server and blacklist from the bot." -pathofexile: - desc: Searches characters for a given Path of Exile account. May specify league name to filter results. - ex: - - '"Zizaran"' - params: - - usr: - desc: "The username or email address associated with the Path of Exile account being searched." - league: - desc: "The league in which the character is playing, allowing users to focus on a specific game mode or event." - page: - desc: "The number of pages to retrieve from the API." -pathofexileleagues: - desc: Returns a list of the main Path of Exile leagues. - ex: - - '' - params: - - {} -pathofexilecurrency: - desc: Returns the chaos equivalent of a given currency or exchange rate between two currencies. - ex: - - Standard "Mirror of Kalandra" - params: - - leagueName: - desc: "The name of the league in which the currency is used, such as \"Harbinger\" or \"Delve\"." - currencyName: - desc: "The type of currency being converted." - convertName: - desc: "The type of currency being converted from or to." rollduel: desc: Challenge someone to a roll duel by specifying the amount and the user you wish to challenge as the parameters. To accept the challenge, just specify the name of the user who challenged you, without the amount. ex: @@ -3946,12 +3995,17 @@ rerotransfer: toMessageId: desc: "The ID of the target message where the reaction roles should be transferred." blackjack: - desc: Start or join a blackjack game. You must specify the amount you're betting. Use `{0}hit`, `{0}stand` and `{0}double` commands to play. Game is played with 4 decks. Dealer hits on soft 17 and wins draws. + desc: |- + Start or join a blackjack game by specifying the amount you're betting. + You must specify the amount you're betting. + Use `{0}hit`, `{0}stand` and `{0}double` commands to play. + Game is played with 4 decks. + Dealer hits on soft 17 and wins draws. ex: - 50 params: - amount: - desc: "The minimum bet required to participate in the game." + desc: "The amount you want to bet in the blackjack game." hit: desc: In the blackjack game, ask the dealer for an extra card. ex: @@ -4126,7 +4180,7 @@ marmaladeload: desc: |- Loads a marmalade with the specified name from the data/marmalades/ folder. Provide no name to see the list of loadable marmalades. - Read about the marmalade system [here](https://docs.elliebot.net/ellie/) + Read about the marmalade system [here](https://docs.elliebot.net/ellie/marmalade/creating-a-marmalade/) ex: - mycoolmarmalade - '' @@ -4137,7 +4191,7 @@ marmaladeunload: desc: |- Unloads the previously loaded marmalade. Provide no name to see the list of unloadable marmalades. - Read about the marmalade system [here](https://docs.elliebot.net/ellie/) + Read about the marmalade system [here](https://docs.elliebot.net/ellie/marmalade/creating-a-marmalade/) ex: - mycoolmarmalade - '' @@ -4148,7 +4202,7 @@ marmaladeinfo: desc: |- Shows information about the specified marmalade such as the author, name, description, list of sneks, number of commands etc. Provide no name to see the basic information about all loaded marmalades. - Read about the marmalade system [here](https://docs.elliebot.net/ellie/) + Read about the marmalade system [here](https://docs.elliebot.net/ellie/marmalade/creating-a-marmalade/) ex: - mycoolmarmalade - '' @@ -4158,7 +4212,7 @@ marmaladeinfo: marmaladelist: desc: |- Lists all loaded and unloaded marmalades. - Read about the marmalade system [here](https://docs.elliebot.net/ellie/) + Read about the marmalade system [here](https://docs.elliebot.net/ellie/marmalade/creating-a-marmalade/) ex: - '' params: @@ -4184,7 +4238,10 @@ bankwithdraw: - amount: desc: "The amount of money to be withdrawn." bankbalance: - desc: Shows your current bank balance available for withdrawal. + desc: |- + Shows how much currency is in your bank account. + This differs from your cash amount, as the cash amount is publicly available, but only you have access to your bank balance. + However, you have to withdraw it first in order to use it. ex: - '' params: @@ -4456,4 +4513,13 @@ cleanupguilddata: ex: - '' params: - - {} \ No newline at end of file + - {} +prompt: + desc: |- + Ask the bot to do something for you. + This will fall back to the chatbot service in case of an error. + ex: + - What's the weather like today? + params: + - query: + desc: "The message to send to the bot." \ No newline at end of file diff --git a/src/EllieBot/data/strings/responses/responses.en-US.json b/src/EllieBot/data/strings/responses/responses.en-US.json index bbc021b..59c8a47 100644 --- a/src/EllieBot/data/strings/responses/responses.en-US.json +++ b/src/EllieBot/data/strings/responses/responses.en-US.json @@ -345,8 +345,8 @@ "submissions_closed": "Submissions closed", "animal_race_already_started": "Animal Race is already running.", "category": "Category", - "cleverbot_disabled": "Disabled cleverbot on this server.", - "cleverbot_enabled": "Enabled cleverbot on this server.", + "chatbot_disabled": "Disabled chatbot on this server.", + "chatbot_enabled": "Enabled chatbot on this server.", "curgen_disabled": "Currency generation has been disabled on this channel.", "curgen_enabled": "Currency generation has been enabled on this channel.", "curgen_pl": "{0} random {1} appeared!", @@ -619,7 +619,7 @@ "quote_deleted": "Quote #{0} deleted.", "quote_edited": "Quote Edited", "region": "Region", - "remind": "I will remind {0} to {1} in {2} `({3:d.M.yyyy.} at {4:HH:mm})`", + "remind2": "I will remind {0} to {1} {2} ({3})`", "remind_timely": "I will remind you about your timely reward {0}", "remind_invalid": "Not a valid remind format. Remind must have a target, timer and a reason. Check the command list.", "remind_too_long": "Remind time has exceeded maximum.", @@ -1002,7 +1002,7 @@ "module_description_permissions": "Setup perms for commands, filter words and set up command cooldowns", "module_description_searches": "Search for jokes, images of animals, anime and manga", "module_description_xp": "Gain xp based on chat activity, check users' xp cards", - "module_description_marmalade": "**Bot Owner only.** Load, unload and handle dynamic modules. Read more [here](https://docs.elliebot.net/ellie/)", + "module_description_marmalade": "**Bot Owner only.** Load, unload and handle dynamic modules. Read more [here](https://docs.elliebot.net/ellie/marmalade/creating-a-marmalade/)", "module_description_patronage": "Commands related to supporting the bot", "module_description_missing": "Description is missing for this module.", "purge_user_confirm": "Are you sure that you want to purge {0} from the database?", @@ -1045,7 +1045,7 @@ "cmd_group_commands": "'{0}' command group", "limit_reached": "Feature limit of {0} reached.", "feature_limit_reached_you": "You've reached the limit of {0} for the {1} feature. You may be able to increase this limit by upgrading your patron tier.", - "feature_limit_reached_owner": "Server owner has reached the limit of {0} for the {1} feature. Server owner may be able to upgrade this limit by upgrading patron tier.", + "feature_limit_reached_owner": "Feature limit reached. Server owner may upgrade patron level to increase the limit.", "feature_limit_reached_either": "The limit of {0} for the {1} feature has been reached. Either you or the server owner may able to upgrade this limit by upgrading the patron tier.", "xp_shop_buy_required_tier": "Buying items from this shop requires Patron Tier {0} or higher.", "available_commands": "Available Commands", From 4fe4c4eff2b167bdaa7efb2e4d895a6f9ad8e2f0 Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 01:00:44 +1200 Subject: [PATCH 02/25] Added cleanup code for invalid database data in sqlite --- .../Migrations/Sqlite/20240518221424_guidlconfig-cleanup.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/EllieBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.cs b/src/EllieBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.cs index 9f5aa20..faaf454 100644 --- a/src/EllieBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.cs +++ b/src/EllieBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.cs @@ -11,6 +11,8 @@ namespace EllieBot.Migrations /// protected override void Up(MigrationBuilder migrationBuilder) { + MigrationQueries.GuildConfigCleanup(migrationBuilder); + migrationBuilder.DropForeignKey( name: "FK_AntiRaidSetting_GuildConfigs_GuildConfigId", table: "AntiRaidSetting"); From b045015efbd977d14bdecca29a5ad5f4ff151da9 Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 17:59:28 +1200 Subject: [PATCH 03/25] Updated common abstractions --- .../Abstractions/Cache/BotCacheExtensions.cs | 4 ++-- .../_common/Abstractions/Cache/IBotCache.cs | 4 ++-- .../_common/Abstractions/Cache/MemoryBotCache.cs | 6 +++--- .../Collections/ConcurrentHashSet.cs | 14 +++++--------- ...ndexedCollections.cs => IndexedCollection.cs} | 2 +- src/EllieBot/_common/Abstractions/EllieRandom.cs | 2 +- .../Abstractions/Extensions/ArrayExtensions.cs | 4 ++-- .../Extensions/EnumerableExtensions.cs | 4 ++-- .../Abstractions/Extensions/Extensions.cs | 2 +- .../Abstractions/Extensions/PipeExtensions.cs | 6 +++--- .../Abstractions/Extensions/StringExtensions.cs | 16 ++++++++-------- .../Abstractions/Helpers/StandardConversions.cs | 2 +- .../_common/Abstractions/PubSub/EventPubSub.cs | 6 +++--- .../_common/Abstractions/PubSub/IPubSub.cs | 2 +- .../_common/Abstractions/PubSub/ISeria.cs | 2 +- src/EllieBot/_common/Abstractions/QueueRunner.cs | 4 ++-- src/EllieBot/_common/Abstractions/TypedKey.cs | 2 +- .../Abstractions/creds/IBotCredentials.cs | 5 +++-- .../Abstractions/strings/CommandStrings.cs | 4 ++-- .../_common/Abstractions/strings/IBotStrings.cs | 2 +- .../strings/IBotStringsExtensions.cs | 2 +- .../Abstractions/strings/IBotStringsProvider.cs | 2 +- .../Abstractions/strings/IStringsSource.cs | 1 - 23 files changed, 47 insertions(+), 51 deletions(-) rename src/EllieBot/_common/Abstractions/Collections/{IndexedCollections.cs => IndexedCollection.cs} (98%) diff --git a/src/EllieBot/_common/Abstractions/Cache/BotCacheExtensions.cs b/src/EllieBot/_common/Abstractions/Cache/BotCacheExtensions.cs index 39d5e82..2c6ea67 100644 --- a/src/EllieBot/_common/Abstractions/Cache/BotCacheExtensions.cs +++ b/src/EllieBot/_common/Abstractions/Cache/BotCacheExtensions.cs @@ -1,4 +1,4 @@ -using OneOf; +using OneOf; using OneOf.Types; namespace Ellie.Common; @@ -13,7 +13,7 @@ public static class BotCacheExtensions return default; } - + private static TypedKey GetImgKey(Uri uri) => new($"image:{uri}"); diff --git a/src/EllieBot/_common/Abstractions/Cache/IBotCache.cs b/src/EllieBot/_common/Abstractions/Cache/IBotCache.cs index 5622c5f..15f9e3f 100644 --- a/src/EllieBot/_common/Abstractions/Cache/IBotCache.cs +++ b/src/EllieBot/_common/Abstractions/Cache/IBotCache.cs @@ -15,7 +15,7 @@ public interface IBotCache /// Type of the value /// Returns whether add was sucessful. Always true unless ovewrite = false ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true); - + /// /// Get an element from the cache /// @@ -23,7 +23,7 @@ public interface IBotCache /// Type of the value /// Either a value or ValueTask> GetAsync(TypedKey key); - + /// /// Remove a key from the cache /// diff --git a/src/EllieBot/_common/Abstractions/Cache/MemoryBotCache.cs b/src/EllieBot/_common/Abstractions/Cache/MemoryBotCache.cs index caac44f..2368ac2 100644 --- a/src/EllieBot/_common/Abstractions/Cache/MemoryBotCache.cs +++ b/src/EllieBot/_common/Abstractions/Cache/MemoryBotCache.cs @@ -26,12 +26,12 @@ public sealed class MemoryBotCache : IBotCache item.AbsoluteExpirationRelativeToNow = expiry; return new(true); } - + lock (_cacheLock) { if (_cache.TryGetValue(key.Key, out var old) && old is not null) return new(false); - + using var item = _cache.CreateEntry(key.Key); item.Value = value; item.AbsoluteExpirationRelativeToNow = expiry; @@ -63,7 +63,7 @@ public sealed class MemoryBotCache : IBotCache { lock (_cacheLock) { - var toReturn = _cache.TryGetValue(key.Key, out var old) && old is not null; + var toReturn = _cache.TryGetValue(key.Key, out var old ) && old is not null; _cache.Remove(key.Key); return new(toReturn); } diff --git a/src/EllieBot/_common/Abstractions/Collections/ConcurrentHashSet.cs b/src/EllieBot/_common/Abstractions/Collections/ConcurrentHashSet.cs index 19986be..7d5bbc1 100644 --- a/src/EllieBot/_common/Abstractions/Collections/ConcurrentHashSet.cs +++ b/src/EllieBot/_common/Abstractions/Collections/ConcurrentHashSet.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; namespace System.Collections.Generic; @@ -6,7 +6,7 @@ namespace System.Collections.Generic; public sealed class ConcurrentHashSet : IReadOnlyCollection, ICollection where T : notnull { private readonly ConcurrentDictionary _backingStore; - + public ConcurrentHashSet() => _backingStore = new(); @@ -46,12 +46,8 @@ public sealed class ConcurrentHashSet : IReadOnlyCollection, ICollection= array.Length) - throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + ArgumentOutOfRangeException.ThrowIfNegative(arrayIndex); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(arrayIndex, array.Length); CopyToInternal(array, arrayIndex); } @@ -63,7 +59,7 @@ public sealed class ConcurrentHashSet : IReadOnlyCollection, ICollection= len) throw new IndexOutOfRangeException(nameof(arrayIndex)); - + array[arrayIndex++] = k; } } diff --git a/src/EllieBot/_common/Abstractions/Collections/IndexedCollections.cs b/src/EllieBot/_common/Abstractions/Collections/IndexedCollection.cs similarity index 98% rename from src/EllieBot/_common/Abstractions/Collections/IndexedCollections.cs rename to src/EllieBot/_common/Abstractions/Collections/IndexedCollection.cs index fe8e2c1..dce86a0 100644 --- a/src/EllieBot/_common/Abstractions/Collections/IndexedCollections.cs +++ b/src/EllieBot/_common/Abstractions/Collections/IndexedCollection.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; namespace Ellie.Common; diff --git a/src/EllieBot/_common/Abstractions/EllieRandom.cs b/src/EllieBot/_common/Abstractions/EllieRandom.cs index 0ece259..df2d073 100644 --- a/src/EllieBot/_common/Abstractions/EllieRandom.cs +++ b/src/EllieBot/_common/Abstractions/EllieRandom.cs @@ -16,7 +16,7 @@ public sealed class EllieRandom : Random _rng.GetBytes(bytes); return Math.Abs(BitConverter.ToInt32(bytes, 0)); } - + /// /// Generates a random integer between 0 (inclusive) and /// a specified exclusive upper bound using a cryptographically strong random number generator. diff --git a/src/EllieBot/_common/Abstractions/Extensions/ArrayExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/ArrayExtensions.cs index dbe2d93..f3e8ae3 100644 --- a/src/EllieBot/_common/Abstractions/Extensions/ArrayExtensions.cs +++ b/src/EllieBot/_common/Abstractions/Extensions/ArrayExtensions.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography; +using System.Security.Cryptography; namespace Ellie.Common; @@ -43,7 +43,7 @@ public static class ArrayExtensions public static TOut[] Map(this IReadOnlyCollection col, Func f) { var toReturn = new TOut[col.Count]; - + var i = 0; foreach (var item in col) toReturn[i++] = f(item); diff --git a/src/EllieBot/_common/Abstractions/Extensions/EnumerableExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/EnumerableExtensions.cs index 4e4c786..3cedd0e 100644 --- a/src/EllieBot/_common/Abstractions/Extensions/EnumerableExtensions.cs +++ b/src/EllieBot/_common/Abstractions/Extensions/EnumerableExtensions.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography; +using System.Security.Cryptography; namespace Ellie.Common; @@ -37,7 +37,7 @@ public static class EnumerableExtensions /// public static string Join(this IEnumerable data, string separator, Func? func = null) => string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty))); - + /// /// Randomize element order by performing the Fisher-Yates shuffle /// diff --git a/src/EllieBot/_common/Abstractions/Extensions/Extensions.cs b/src/EllieBot/_common/Abstractions/Extensions/Extensions.cs index 487afe7..8abf5d6 100644 --- a/src/EllieBot/_common/Abstractions/Extensions/Extensions.cs +++ b/src/EllieBot/_common/Abstractions/Extensions/Extensions.cs @@ -1,4 +1,4 @@ -namespace Ellie.Common; +namespace Ellie.Common; public static class Extensions { diff --git a/src/EllieBot/_common/Abstractions/Extensions/PipeExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/PipeExtensions.cs index 215a829..65b5bb2 100644 --- a/src/EllieBot/_common/Abstractions/Extensions/PipeExtensions.cs +++ b/src/EllieBot/_common/Abstractions/Extensions/PipeExtensions.cs @@ -7,16 +7,16 @@ public static class PipeExtensions { public static TOut Pipe(this TIn a, Func fn) => fn(a); - + public static TOut Pipe(this TIn a, PipeFunc fn) => fn(a); - + public static TOut Pipe(this (TIn1, TIn2) a, PipeFunc fn) => fn(a.Item1, a.Item2); public static (TIn, TExtra) With(this TIn a, TExtra b) => (a, b); - + public static async Task Pipe(this Task a, Func fn) => fn(await a); } \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/Extensions/StringExtensions.cs b/src/EllieBot/_common/Abstractions/Extensions/StringExtensions.cs index 95baadb..f2fd050 100644 --- a/src/EllieBot/_common/Abstractions/Extensions/StringExtensions.cs +++ b/src/EllieBot/_common/Abstractions/Extensions/StringExtensions.cs @@ -1,4 +1,4 @@ -using EllieBot.Common.Yml; +using EllieBot.Common.Yml; using System.Text; using System.Text.RegularExpressions; @@ -82,14 +82,14 @@ public static class StringExtensions // Step 3 for (var i = 1; i <= n; i++) //Step 4 - for (var j = 1; j <= m; j++) - { - // Step 5 - var cost = t[j - 1] == s[i - 1] ? 0 : 1; + for (var j = 1; j <= m; j++) + { + // Step 5 + var cost = t[j - 1] == s[i - 1] ? 0 : 1; - // Step 6 - d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost); - } + // Step 6 + d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost); + } // Step 7 return d[n, m]; diff --git a/src/EllieBot/_common/Abstractions/Helpers/StandardConversions.cs b/src/EllieBot/_common/Abstractions/Helpers/StandardConversions.cs index 143c149..d277b7e 100644 --- a/src/EllieBot/_common/Abstractions/Helpers/StandardConversions.cs +++ b/src/EllieBot/_common/Abstractions/Helpers/StandardConversions.cs @@ -1,4 +1,4 @@ -namespace Ellie.Common; +namespace Ellie.Common; public static class StandardConversions { diff --git a/src/EllieBot/_common/Abstractions/PubSub/EventPubSub.cs b/src/EllieBot/_common/Abstractions/PubSub/EventPubSub.cs index a3d753a..87ce07f 100644 --- a/src/EllieBot/_common/Abstractions/PubSub/EventPubSub.cs +++ b/src/EllieBot/_common/Abstractions/PubSub/EventPubSub.cs @@ -50,9 +50,9 @@ public class EventPubSub : IPubSub { // get subscriptions for this action if (_actions.TryGetValue(key.Key, out var actions)) - // get subscriptions which have the same action hash code - // note: having this as a list allows for multiple subscriptions of - // the same insance's/static method + // get subscriptions which have the same action hash code + // note: having this as a list allows for multiple subscriptions of + // the same insance's/static method { if (actions.TryGetValue(action, out var sameActions)) { diff --git a/src/EllieBot/_common/Abstractions/PubSub/IPubSub.cs b/src/EllieBot/_common/Abstractions/PubSub/IPubSub.cs index ea84b6b..7c092cb 100644 --- a/src/EllieBot/_common/Abstractions/PubSub/IPubSub.cs +++ b/src/EllieBot/_common/Abstractions/PubSub/IPubSub.cs @@ -1,4 +1,4 @@ -namespace Ellie.Common; +namespace Ellie.Common; public interface IPubSub { diff --git a/src/EllieBot/_common/Abstractions/PubSub/ISeria.cs b/src/EllieBot/_common/Abstractions/PubSub/ISeria.cs index 76094f4..57217c2 100644 --- a/src/EllieBot/_common/Abstractions/PubSub/ISeria.cs +++ b/src/EllieBot/_common/Abstractions/PubSub/ISeria.cs @@ -1,4 +1,4 @@ -namespace Ellie.Common; +namespace Ellie.Common; public interface ISeria { diff --git a/src/EllieBot/_common/Abstractions/QueueRunner.cs b/src/EllieBot/_common/Abstractions/QueueRunner.cs index 6e582cc..7bba829 100644 --- a/src/EllieBot/_common/Abstractions/QueueRunner.cs +++ b/src/EllieBot/_common/Abstractions/QueueRunner.cs @@ -37,7 +37,7 @@ public sealed class QueueRunner while (true) { var func = await _channel.Reader.ReadAsync(cancel); - + try { await func(); @@ -55,7 +55,7 @@ public sealed class QueueRunner } } } - + public ValueTask EnqueueAsync(Func action) => _channel.Writer.WriteAsync(action); } \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/TypedKey.cs b/src/EllieBot/_common/Abstractions/TypedKey.cs index ea3103c..0ca2554 100644 --- a/src/EllieBot/_common/Abstractions/TypedKey.cs +++ b/src/EllieBot/_common/Abstractions/TypedKey.cs @@ -1,4 +1,4 @@ -namespace Ellie.Common; +namespace Ellie.Common; public readonly struct TypedKey { diff --git a/src/EllieBot/_common/Abstractions/creds/IBotCredentials.cs b/src/EllieBot/_common/Abstractions/creds/IBotCredentials.cs index 87db412..faeae4f 100644 --- a/src/EllieBot/_common/Abstractions/creds/IBotCredentials.cs +++ b/src/EllieBot/_common/Abstractions/creds/IBotCredentials.cs @@ -1,11 +1,12 @@ -#nullable disable +#nullable disable namespace EllieBot; public interface IBotCredentials { string Token { get; } - string GoogleApiKey { get; } + string EllieAiToken { get; } ICollection OwnerIds { get; set; } + string GoogleApiKey { get; } bool UsePrivilegedIntents { get; } string RapidApiKey { get; } diff --git a/src/EllieBot/_common/Abstractions/strings/CommandStrings.cs b/src/EllieBot/_common/Abstractions/strings/CommandStrings.cs index 6f72ab0..77f16be 100644 --- a/src/EllieBot/_common/Abstractions/strings/CommandStrings.cs +++ b/src/EllieBot/_common/Abstractions/strings/CommandStrings.cs @@ -20,7 +20,7 @@ public sealed record class CommandStrings [YamlMember(Alias = "ex")] public string[] Examples { get; set; } - + [YamlMember(Alias = "params")] public Dictionary[] Params { get; set; } } @@ -29,7 +29,7 @@ public sealed record class CommandStringParam { // [YamlMember(Alias = "type", ScalarStyle = ScalarStyle.DoubleQuoted)] // public string Type { get; set; } - + [YamlMember(Alias = "desc", ScalarStyle = ScalarStyle.DoubleQuoted)] public string Desc { get; set; } } \ No newline at end of file diff --git a/src/EllieBot/_common/Abstractions/strings/IBotStrings.cs b/src/EllieBot/_common/Abstractions/strings/IBotStrings.cs index 2ded833..5c43755 100644 --- a/src/EllieBot/_common/Abstractions/strings/IBotStrings.cs +++ b/src/EllieBot/_common/Abstractions/strings/IBotStrings.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System.Globalization; namespace EllieBot.Common; diff --git a/src/EllieBot/_common/Abstractions/strings/IBotStringsExtensions.cs b/src/EllieBot/_common/Abstractions/strings/IBotStringsExtensions.cs index 17f9377..a635b4b 100644 --- a/src/EllieBot/_common/Abstractions/strings/IBotStringsExtensions.cs +++ b/src/EllieBot/_common/Abstractions/strings/IBotStringsExtensions.cs @@ -8,7 +8,7 @@ public static class BotStringsExtensions // this one is for pipe fun, see PipeExtensions.cs public static string GetText(this IBotStrings strings, in LocStr str, in ulong guildId) => strings.GetText(str.Key, guildId, str.Params); - + public static string GetText(this IBotStrings strings, in LocStr str, ulong? guildId = null) => strings.GetText(str.Key, guildId, str.Params); diff --git a/src/EllieBot/_common/Abstractions/strings/IBotStringsProvider.cs b/src/EllieBot/_common/Abstractions/strings/IBotStringsProvider.cs index 87cab9f..ef98051 100644 --- a/src/EllieBot/_common/Abstractions/strings/IBotStringsProvider.cs +++ b/src/EllieBot/_common/Abstractions/strings/IBotStringsProvider.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services; /// diff --git a/src/EllieBot/_common/Abstractions/strings/IStringsSource.cs b/src/EllieBot/_common/Abstractions/strings/IStringsSource.cs index a2715f0..08ad986 100644 --- a/src/EllieBot/_common/Abstractions/strings/IStringsSource.cs +++ b/src/EllieBot/_common/Abstractions/strings/IStringsSource.cs @@ -1,5 +1,4 @@ #nullable disable - namespace EllieBot.Services; /// From a63889b2f3675e15e903865b41120dc372da7f32 Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 19:44:07 +1200 Subject: [PATCH 04/25] Updated common files --- src/EllieBot/_common/AddRemove.cs | 2 +- .../_common/Attributes/CmdAttribute.cs | 2 +- .../_common/Attributes/DIIgnoreAttribute.cs | 2 +- .../Attributes/EllieOptionsAttribute.cs | 2 +- .../Attributes/OnlyPublicBotAttribute.cs | 2 +- .../_common/Attributes/OwnerOnlyAttribute.cs | 4 +- .../_common/Attributes/RatelimitAttribute.cs | 2 +- .../_common/Attributes/UserPermAttribute.cs | 2 +- src/EllieBot/_common/CommandNameLoadHelper.cs | 2 +- src/EllieBot/_common/Configs/BotConfig.cs | 14 +++--- src/EllieBot/_common/Configs/IConfigSeria.cs | 2 +- src/EllieBot/_common/Creds.cs | 40 +++++++++------ src/EllieBot/_common/DoAsUserMessage.cs | 2 +- src/EllieBot/_common/DownloadTracker.cs | 2 +- src/EllieBot/_common/EllieModule.cs | 2 +- src/EllieBot/_common/ILogCommandService.cs | 2 +- src/EllieBot/_common/IPermissionChecker.cs | 12 ++--- src/EllieBot/_common/IPlaceholderProvider.cs | 2 +- src/EllieBot/_common/ImageUrls.cs | 2 +- .../_common/Interaction/EllieInteraction.cs | 5 +- .../Interaction/IEllieInteractionService.cs | 4 +- .../Models/EllieButtonInteraction.cs | 4 +- .../JsonConverters/CultureInfoConverter.cs | 4 +- .../JsonConverters/NumberToStringConverter.cs | 30 ++++++++++++ .../_common/JsonConverters/Rgba32Converter.cs | 2 +- src/EllieBot/_common/Linq2DbExpressions.cs | 2 +- .../_common/ModuleBehaviors/IExecNoCommand.cs | 2 +- .../_common/ModuleBehaviors/IExecOnMessage.cs | 2 +- .../ModuleBehaviors/IExecPostCommand.cs | 2 +- .../ModuleBehaviors/IExecPreCommand.cs | 2 +- .../ModuleBehaviors/IInputTransformer.cs | 2 +- .../_common/ModuleBehaviors/IReadyExecutor.cs | 2 +- ...ensions.cs => NinjectIKernelExtensions.cs} | 6 +-- .../_common/Patronage/FeatureLimitKey.cs | 7 +++ .../_common/Patronage/FeatureQuotaStats.cs | 8 --- .../_common/Patronage/IPatronageService.cs | 25 +++------- src/EllieBot/_common/Patronage/Patron.cs | 2 +- .../_common/Patronage/PatronConfigData.cs | 28 ++--------- .../_common/Patronage/PatronExtensions.cs | 9 ---- src/EllieBot/_common/Patronage/QuotaLimit.cs | 49 ++----------------- src/EllieBot/_common/Patronage/QuotaPer.cs | 1 + .../_common/Patronage/UserQuotaStats.cs | 25 ---------- .../_common/Pokemon/SearchPokemonAbility.cs | 2 +- .../Impl/ReplacementRegistrator.default.cs | 2 +- .../_common/Sender/MessageSenderService.cs | 8 +-- .../ResponseBuilder.PaginationSender.cs | 20 ++++++-- .../_common/ServiceCollectionExtensions.cs | 10 ++-- .../_common/Services/CommandHandler.cs | 4 +- .../_common/Services/IBehaviourHandler.cs | 4 +- .../_common/Services/ILocalization.cs | 2 +- .../_common/Services/ITimezoneService.cs | 2 +- .../_common/Services/Impl/YtdlOperation.cs | 2 +- .../_common/Settings/BotConfigService.cs | 10 ++-- .../_common/Settings/ConfigParsers.cs | 4 +- .../_common/Settings/ConfigServiceBase.cs | 4 +- .../_common/Settings/IConfigService.cs | 2 +- .../_common/Settings/SettingParser.cs | 2 +- src/EllieBot/_common/Yml/CommentAttribute.cs | 2 +- .../Yml/MultilineScalarFlowStyleEmitter.cs | 1 - .../_Extensions/CommandContextExtensions.cs | 10 ++++ .../_common/_Extensions/Extensions.cs | 1 + 61 files changed, 188 insertions(+), 227 deletions(-) create mode 100644 src/EllieBot/_common/JsonConverters/NumberToStringConverter.cs rename src/EllieBot/_common/{NinjectKernelExtensions.cs => NinjectIKernelExtensions.cs} (98%) delete mode 100644 src/EllieBot/_common/Patronage/FeatureQuotaStats.cs delete mode 100644 src/EllieBot/_common/Patronage/UserQuotaStats.cs diff --git a/src/EllieBot/_common/AddRemove.cs b/src/EllieBot/_common/AddRemove.cs index bb3862e..cccd892 100644 --- a/src/EllieBot/_common/AddRemove.cs +++ b/src/EllieBot/_common/AddRemove.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Common; public enum AddRemove diff --git a/src/EllieBot/_common/Attributes/CmdAttribute.cs b/src/EllieBot/_common/Attributes/CmdAttribute.cs index a02fd1e..363348c 100644 --- a/src/EllieBot/_common/Attributes/CmdAttribute.cs +++ b/src/EllieBot/_common/Attributes/CmdAttribute.cs @@ -1,4 +1,4 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; namespace EllieBot.Common.Attributes; diff --git a/src/EllieBot/_common/Attributes/DIIgnoreAttribute.cs b/src/EllieBot/_common/Attributes/DIIgnoreAttribute.cs index 7be799a..608e079 100644 --- a/src/EllieBot/_common/Attributes/DIIgnoreAttribute.cs +++ b/src/EllieBot/_common/Attributes/DIIgnoreAttribute.cs @@ -7,5 +7,5 @@ namespace EllieBot.Common; [AttributeUsage(AttributeTargets.Class)] public class DIIgnoreAttribute : Attribute { - + } \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/EllieOptionsAttribute.cs b/src/EllieBot/_common/Attributes/EllieOptionsAttribute.cs index c94b109..7db4315 100644 --- a/src/EllieBot/_common/Attributes/EllieOptionsAttribute.cs +++ b/src/EllieBot/_common/Attributes/EllieOptionsAttribute.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Common.Attributes; +namespace EllieBot.Common.Attributes; [AttributeUsage(AttributeTargets.Method)] public sealed class EllieOptionsAttribute : Attribute diff --git a/src/EllieBot/_common/Attributes/OnlyPublicBotAttribute.cs b/src/EllieBot/_common/Attributes/OnlyPublicBotAttribute.cs index 6ae9408..2ee7958 100644 --- a/src/EllieBot/_common/Attributes/OnlyPublicBotAttribute.cs +++ b/src/EllieBot/_common/Attributes/OnlyPublicBotAttribute.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System.Diagnostics.CodeAnalysis; namespace EllieBot.Common; diff --git a/src/EllieBot/_common/Attributes/OwnerOnlyAttribute.cs b/src/EllieBot/_common/Attributes/OwnerOnlyAttribute.cs index 7aa9317..c1baa53 100644 --- a/src/EllieBot/_common/Attributes/OwnerOnlyAttribute.cs +++ b/src/EllieBot/_common/Attributes/OwnerOnlyAttribute.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; namespace EllieBot.Common.Attributes; @@ -16,4 +16,4 @@ public sealed class OwnerOnlyAttribute : PreconditionAttribute ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner")); } -} +} \ No newline at end of file diff --git a/src/EllieBot/_common/Attributes/RatelimitAttribute.cs b/src/EllieBot/_common/Attributes/RatelimitAttribute.cs index 7fcf9c8..54402d9 100644 --- a/src/EllieBot/_common/Attributes/RatelimitAttribute.cs +++ b/src/EllieBot/_common/Attributes/RatelimitAttribute.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; namespace EllieBot.Common.Attributes; diff --git a/src/EllieBot/_common/Attributes/UserPermAttribute.cs b/src/EllieBot/_common/Attributes/UserPermAttribute.cs index 1b4ee75..2e0af03 100644 --- a/src/EllieBot/_common/Attributes/UserPermAttribute.cs +++ b/src/EllieBot/_common/Attributes/UserPermAttribute.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; namespace Discord; diff --git a/src/EllieBot/_common/CommandNameLoadHelper.cs b/src/EllieBot/_common/CommandNameLoadHelper.cs index 3d69f2e..0a811e2 100644 --- a/src/EllieBot/_common/CommandNameLoadHelper.cs +++ b/src/EllieBot/_common/CommandNameLoadHelper.cs @@ -1,4 +1,4 @@ -using EllieBot.Common.Yml; +using EllieBot.Common.Yml; using YamlDotNet.Serialization; namespace EllieBot.Common.Attributes; diff --git a/src/EllieBot/_common/Configs/BotConfig.cs b/src/EllieBot/_common/Configs/BotConfig.cs index 0715701..0908577 100644 --- a/src/EllieBot/_common/Configs/BotConfig.cs +++ b/src/EllieBot/_common/Configs/BotConfig.cs @@ -44,13 +44,13 @@ public sealed partial class BotConfig : ICloneable or all owners? (this might cause the bot to lag if there's a lot of owners specified) """)] public bool ForwardToAllOwners { get; set; } - + [Comment(""" Any messages sent by users in Bot's DM to be forwarded to the specified channel. This option will only work when ForwardToAllOwners is set to false """)] public ulong? ForwardToChannel { get; set; } - + [Comment(""" Should the bot ignore messages from other bots? Settings this to false might get your bot banned if it gets into a spam loop with another bot. @@ -155,11 +155,11 @@ public sealed partial class BotConfig : ICloneable ]; } - // [Comment(@"Whether the prefix will be a suffix, or prefix. - // For example, if your prefix is ! you will run a command called 'cash' by typing either - // '!cash @Someone' if your prefixIsSuffix: false or - // 'cash @Someone!' if your prefixIsSuffix: true")] - // public bool PrefixIsSuffix { get; set; } +// [Comment(@"Whether the prefix will be a suffix, or prefix. +// For example, if your prefix is ! you will run a command called 'cash' by typing either +// '!cash @Someone' if your prefixIsSuffix: false or +// 'cash @Someone!' if your prefixIsSuffix: true")] +// public bool PrefixIsSuffix { get; set; } // public string Prefixed(string text) => PrefixIsSuffix // ? text + Prefix diff --git a/src/EllieBot/_common/Configs/IConfigSeria.cs b/src/EllieBot/_common/Configs/IConfigSeria.cs index 1f96850..a5d3a10 100644 --- a/src/EllieBot/_common/Configs/IConfigSeria.cs +++ b/src/EllieBot/_common/Configs/IConfigSeria.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Common.Configs; +namespace EllieBot.Common.Configs; /// /// Base interface for available config serializers diff --git a/src/EllieBot/_common/Creds.cs b/src/EllieBot/_common/Creds.cs index f6aef5d..8f454a0 100644 --- a/src/EllieBot/_common/Creds.cs +++ b/src/EllieBot/_common/Creds.cs @@ -1,7 +1,7 @@ -#nullable disable +#nullable disable using EllieBot.Common.Yml; -namespace Ellie.Common; +namespace EllieBot.Common; public sealed class Creds : IBotCredentials { @@ -16,7 +16,7 @@ public sealed class Creds : IBotCredentials **DO NOT ADD PEOPLE YOU DON'T TRUST** """)] public ICollection OwnerIds { get; set; } - + [Comment("Keep this on 'true' unless you're sure your bot shouldn't use privileged intents or you're waiting to be accepted")] public bool UsePrivilegedIntents { get; set; } @@ -29,15 +29,24 @@ public sealed class Creds : IBotCredentials """)] public int TotalShards { get; set; } - [Comment( + [Comment(""" + Pledge 5$ or more on https://patreon.com/elliebot and connect your discord account to Patreon. + Go to https://dashy.elliebot.net and login with your discord account + Go to the Keys page and click "Generate New Key" and copy it here + You and anyone else with the permission to run `.prompt` command will be able to use natural language to run bot's commands. + For example '@Bot how's the weather in Paris' will return the current weather in Paris as if you were to run `.weather Paris` command + """)] + public string EllieAiToken { get; set; } + + [Comment( """ Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it. Then, go to APIs and Services -> Credentials and click Create credentials -> API key. Used only for Youtube Data Api (at the moment). """)] public string GoogleApiKey { get; set; } - - [Comment( + + [Comment( """ Create a new custom search here https://programmablesearchengine.google.com/cse/create/new Enable SafeSearch @@ -64,16 +73,16 @@ public sealed class Creds : IBotCredentials [Comment("""Official cleverbot api key.""")] public string CleverbotApiKey { get; set; } - [Comment(@"Official GPT-3 api key.")] + [Comment(@"OpenAi api key.")] public string Gpt3ApiKey { get; set; } - + [Comment(""" Which cache implementation should bot use. 'memory' - Cache will be in memory of the bot's process itself. Only use this on bots with a single shard. When the bot is restarted the cache is reset. 'redis' - Uses redis (which needs to be separately downloaded and installed). The cache will persist through bot restarts. You can configure connection string in creds.yml """)] public BotCacheImplemenation BotCache { get; set; } - + [Comment(""" Redis connection string. Don't change if you don't know what you're doing. Only used if botCache is set to 'redis' @@ -110,10 +119,10 @@ public sealed class Creds : IBotCredentials Used for cryptocurrency related commands. """)] public string CoinmarketcapApiKey { get; set; } - - // [Comment(@"https://polygon.io/dashboard/api-keys api key. Free plan allows for 5 queries per minute. - // Used for stocks related commands.")] - // public string PolygonIoApiKey { get; set; } + +// [Comment(@"https://polygon.io/dashboard/api-keys api key. Free plan allows for 5 queries per minute. +// Used for stocks related commands.")] +// public string PolygonIoApiKey { get; set; } [Comment("""Api key used for Osu related commands. Obtain this key at https://osu.ppy.sh/p/api""")] public string OsuApiKey { get; set; } @@ -171,7 +180,7 @@ public sealed class Creds : IBotCredentials RestartCommand = new RestartConfig(); Google = new GoogleApiConfig(); } - + public class DbOptions : IDbOptions { @@ -270,3 +279,6 @@ public class GoogleApiConfig : IGoogleApiConfig public string SearchId { get; init; } public string ImageSearchId { get; init; } } + + + diff --git a/src/EllieBot/_common/DoAsUserMessage.cs b/src/EllieBot/_common/DoAsUserMessage.cs index f8fba27..f7f2980 100644 --- a/src/EllieBot/_common/DoAsUserMessage.cs +++ b/src/EllieBot/_common/DoAsUserMessage.cs @@ -1,4 +1,4 @@ -using MessageType = Discord.MessageType; +using MessageType = Discord.MessageType; namespace EllieBot.Modules.Administration; diff --git a/src/EllieBot/_common/DownloadTracker.cs b/src/EllieBot/_common/DownloadTracker.cs index 51d7cc6..b886228 100644 --- a/src/EllieBot/_common/DownloadTracker.cs +++ b/src/EllieBot/_common/DownloadTracker.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Common; public class DownloadTracker : IEService diff --git a/src/EllieBot/_common/EllieModule.cs b/src/EllieBot/_common/EllieModule.cs index ba52708..d8867c1 100644 --- a/src/EllieBot/_common/EllieModule.cs +++ b/src/EllieBot/_common/EllieModule.cs @@ -91,7 +91,7 @@ public abstract class EllieModule : ModuleBase if (validate is not null && !validate(arg.Content)) return Task.CompletedTask; - + if (userInputTask.TrySetResult(arg.Content)) userMsg.DeleteAfter(1); diff --git a/src/EllieBot/_common/ILogCommandService.cs b/src/EllieBot/_common/ILogCommandService.cs index 344be96..7e5bcd5 100644 --- a/src/EllieBot/_common/ILogCommandService.cs +++ b/src/EllieBot/_common/ILogCommandService.cs @@ -28,7 +28,7 @@ public enum LogType VoicePresence, UserMuted, UserWarned, - + ThreadDeleted, ThreadCreated } \ No newline at end of file diff --git a/src/EllieBot/_common/IPermissionChecker.cs b/src/EllieBot/_common/IPermissionChecker.cs index 81aaa64..5b4bc48 100644 --- a/src/EllieBot/_common/IPermissionChecker.cs +++ b/src/EllieBot/_common/IPermissionChecker.cs @@ -17,14 +17,14 @@ public partial class PermCheckResult { public bool IsAllowed => IsT0; - - public bool IsCooldown + + public bool IsCooldown => IsT1; - - public bool IsGlobalBlock + + public bool IsGlobalBlock => IsT2; - - public bool IsDisallowed + + public bool IsDisallowed => IsT3; } diff --git a/src/EllieBot/_common/IPlaceholderProvider.cs b/src/EllieBot/_common/IPlaceholderProvider.cs index 1766577..20fcc12 100644 --- a/src/EllieBot/_common/IPlaceholderProvider.cs +++ b/src/EllieBot/_common/IPlaceholderProvider.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Common; public interface IPlaceholderProvider diff --git a/src/EllieBot/_common/ImageUrls.cs b/src/EllieBot/_common/ImageUrls.cs index 7274e60..449043f 100644 --- a/src/EllieBot/_common/ImageUrls.cs +++ b/src/EllieBot/_common/ImageUrls.cs @@ -5,7 +5,7 @@ using Cloneable; namespace EllieBot.Common; [Cloneable] -public partial class ImageUrls : ICloneable +public partial class ImageUrls : ICloneable { [Comment("DO NOT CHANGE")] public int Version { get; set; } = 3; diff --git a/src/EllieBot/_common/Interaction/EllieInteraction.cs b/src/EllieBot/_common/Interaction/EllieInteraction.cs index 89e2103..6157aad 100644 --- a/src/EllieBot/_common/Interaction/EllieInteraction.cs +++ b/src/EllieBot/_common/Interaction/EllieInteraction.cs @@ -1,4 +1,4 @@ -namespace EllieBot; +namespace EllieBot; public abstract class EllieInteractionBase { @@ -85,6 +85,9 @@ public abstract class EllieInteractionBase public Task ExecuteOnActionAsync(SocketMessageComponent smc) => _onAction(smc); + + public void SetCompleted() + => _interactionCompletedSource.TrySetResult(true); } public sealed class EllieModalSubmitHandler diff --git a/src/EllieBot/_common/Interaction/IEllieInteractionService.cs b/src/EllieBot/_common/Interaction/IEllieInteractionService.cs index 967e91d..4d2530c 100644 --- a/src/EllieBot/_common/Interaction/IEllieInteractionService.cs +++ b/src/EllieBot/_common/Interaction/IEllieInteractionService.cs @@ -20,9 +20,9 @@ public interface IEllieInteractionService SelectMenuBuilder menu, Func onTrigger, bool singleUse = true); - + EllieInteractionBase Create( - ulong userId, + ulong userId, ButtonBuilder button, ModalBuilder modal, Func onTrigger, diff --git a/src/EllieBot/_common/Interaction/Models/EllieButtonInteraction.cs b/src/EllieBot/_common/Interaction/Models/EllieButtonInteraction.cs index 3e65c1c..1ad7128 100644 --- a/src/EllieBot/_common/Interaction/Models/EllieButtonInteraction.cs +++ b/src/EllieBot/_common/Interaction/Models/EllieButtonInteraction.cs @@ -1,4 +1,4 @@ -namespace EllieBot; +namespace EllieBot; public sealed class EllieButtonInteractionHandler : EllieInteractionBase { @@ -16,6 +16,6 @@ public sealed class EllieButtonInteractionHandler : EllieInteractionBase public ButtonBuilder Button { get; } - public override void AddTo(ComponentBuilder cb) + public override void AddTo(ComponentBuilder cb) => cb.WithButton(Button); } \ No newline at end of file diff --git a/src/EllieBot/_common/JsonConverters/CultureInfoConverter.cs b/src/EllieBot/_common/JsonConverters/CultureInfoConverter.cs index 28167d6..0c26f15 100644 --- a/src/EllieBot/_common/JsonConverters/CultureInfoConverter.cs +++ b/src/EllieBot/_common/JsonConverters/CultureInfoConverter.cs @@ -7,8 +7,8 @@ namespace EllieBot.Common.JsonConverters; public class CultureInfoConverter : JsonConverter { public override CultureInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => new(reader.GetString() ?? "en_US"); + => new(reader.GetString() ?? "en-US"); - public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options) => writer.WriteStringValue(value.Name); } \ No newline at end of file diff --git a/src/EllieBot/_common/JsonConverters/NumberToStringConverter.cs b/src/EllieBot/_common/JsonConverters/NumberToStringConverter.cs new file mode 100644 index 0000000..bc20b10 --- /dev/null +++ b/src/EllieBot/_common/JsonConverters/NumberToStringConverter.cs @@ -0,0 +1,30 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +public class NumberToStringConverter : JsonConverter +{ + public override bool CanConvert(Type typeToConvert) + => typeof(string) == typeToConvert; + + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + switch (reader.TokenType) + { + case JsonTokenType.Number: + return reader.TryGetInt64(out var l) + ? l.ToString() + : reader.GetDouble().ToString(CultureInfo.InvariantCulture); + case JsonTokenType.String: + return reader.GetString() ?? string.Empty; + default: + { + using var document = JsonDocument.ParseValue(ref reader); + return document.RootElement.Clone().ToString(); + } + } + } + + public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) + => writer.WriteStringValue(value.ToString()); +} \ No newline at end of file diff --git a/src/EllieBot/_common/JsonConverters/Rgba32Converter.cs b/src/EllieBot/_common/JsonConverters/Rgba32Converter.cs index ef619a6..906db1e 100644 --- a/src/EllieBot/_common/JsonConverters/Rgba32Converter.cs +++ b/src/EllieBot/_common/JsonConverters/Rgba32Converter.cs @@ -1,4 +1,4 @@ -using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats; using System.Text.Json; using System.Text.Json.Serialization; diff --git a/src/EllieBot/_common/Linq2DbExpressions.cs b/src/EllieBot/_common/Linq2DbExpressions.cs index a724652..53c90e6 100644 --- a/src/EllieBot/_common/Linq2DbExpressions.cs +++ b/src/EllieBot/_common/Linq2DbExpressions.cs @@ -9,7 +9,7 @@ public static class Linq2DbExpressions [ExpressionMethod(nameof(GuildOnShardExpression))] public static bool GuildOnShard(ulong guildId, int totalShards, int shardId) => throw new NotSupportedException(); - + private static Expression> GuildOnShardExpression() => (guildId, totalShards, shardId) => guildId / 4194304 % (ulong)totalShards == (ulong)shardId; diff --git a/src/EllieBot/_common/ModuleBehaviors/IExecNoCommand.cs b/src/EllieBot/_common/ModuleBehaviors/IExecNoCommand.cs index 4ceeaaf..f23d085 100644 --- a/src/EllieBot/_common/ModuleBehaviors/IExecNoCommand.cs +++ b/src/EllieBot/_common/ModuleBehaviors/IExecNoCommand.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Common.ModuleBehaviors; +namespace EllieBot.Common.ModuleBehaviors; /// /// Executed if no command was found for this message diff --git a/src/EllieBot/_common/ModuleBehaviors/IExecOnMessage.cs b/src/EllieBot/_common/ModuleBehaviors/IExecOnMessage.cs index 7b37a24..3e39152 100644 --- a/src/EllieBot/_common/ModuleBehaviors/IExecOnMessage.cs +++ b/src/EllieBot/_common/ModuleBehaviors/IExecOnMessage.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Common.ModuleBehaviors; +namespace EllieBot.Common.ModuleBehaviors; /// /// Implemented by modules to handle non-bot messages received diff --git a/src/EllieBot/_common/ModuleBehaviors/IExecPostCommand.cs b/src/EllieBot/_common/ModuleBehaviors/IExecPostCommand.cs index ccb949c..b97f584 100644 --- a/src/EllieBot/_common/ModuleBehaviors/IExecPostCommand.cs +++ b/src/EllieBot/_common/ModuleBehaviors/IExecPostCommand.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Common.ModuleBehaviors; +namespace EllieBot.Common.ModuleBehaviors; /// /// This interface's method is executed after the command successfully finished execution. diff --git a/src/EllieBot/_common/ModuleBehaviors/IExecPreCommand.cs b/src/EllieBot/_common/ModuleBehaviors/IExecPreCommand.cs index 438cbd0..4320d8f 100644 --- a/src/EllieBot/_common/ModuleBehaviors/IExecPreCommand.cs +++ b/src/EllieBot/_common/ModuleBehaviors/IExecPreCommand.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Common.ModuleBehaviors; +namespace EllieBot.Common.ModuleBehaviors; /// /// This interface's method is executed after a command was found but before it was executed. diff --git a/src/EllieBot/_common/ModuleBehaviors/IInputTransformer.cs b/src/EllieBot/_common/ModuleBehaviors/IInputTransformer.cs index 957e659..7039989 100644 --- a/src/EllieBot/_common/ModuleBehaviors/IInputTransformer.cs +++ b/src/EllieBot/_common/ModuleBehaviors/IInputTransformer.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Common.ModuleBehaviors; +namespace EllieBot.Common.ModuleBehaviors; /// /// Implemented by services which may transform input before a command is searched for diff --git a/src/EllieBot/_common/ModuleBehaviors/IReadyExecutor.cs b/src/EllieBot/_common/ModuleBehaviors/IReadyExecutor.cs index f0a200b..9364286 100644 --- a/src/EllieBot/_common/ModuleBehaviors/IReadyExecutor.cs +++ b/src/EllieBot/_common/ModuleBehaviors/IReadyExecutor.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Common.ModuleBehaviors; +namespace EllieBot.Common.ModuleBehaviors; /// /// All services which need to execute something after diff --git a/src/EllieBot/_common/NinjectKernelExtensions.cs b/src/EllieBot/_common/NinjectIKernelExtensions.cs similarity index 98% rename from src/EllieBot/_common/NinjectKernelExtensions.cs rename to src/EllieBot/_common/NinjectIKernelExtensions.cs index 36b4fa8..5b5b909 100644 --- a/src/EllieBot/_common/NinjectKernelExtensions.cs +++ b/src/EllieBot/_common/NinjectIKernelExtensions.cs @@ -1,4 +1,4 @@ -using DryIoc; +using DryIoc; namespace EllieBot.Extensions; @@ -11,7 +11,7 @@ public static class DryIocExtensions return container; } - + public static IContainer AddSingleton(this IContainer container, TImpl obj) where TImpl : TSvc { @@ -41,7 +41,7 @@ public static class DryIocExtensions return container; } - + public static IContainer AddSingleton(this IContainer container, Func factory) { container.RegisterDelegate(factory); diff --git a/src/EllieBot/_common/Patronage/FeatureLimitKey.cs b/src/EllieBot/_common/Patronage/FeatureLimitKey.cs index 9aa8a46..10278e1 100644 --- a/src/EllieBot/_common/Patronage/FeatureLimitKey.cs +++ b/src/EllieBot/_common/Patronage/FeatureLimitKey.cs @@ -1,5 +1,12 @@ namespace EllieBot.Modules.Patronage; +public enum LimitedFeatureName +{ + ChatBot, + ReactionRole, + Prune, + +} public readonly struct FeatureLimitKey { public string PrettyName { get; init; } diff --git a/src/EllieBot/_common/Patronage/FeatureQuotaStats.cs b/src/EllieBot/_common/Patronage/FeatureQuotaStats.cs deleted file mode 100644 index 02db5d3..0000000 --- a/src/EllieBot/_common/Patronage/FeatureQuotaStats.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EllieBot.Modules.Patronage; - -public readonly struct FeatureQuotaStats -{ - public (uint Cur, uint Max) Hourly { get; init; } - public (uint Cur, uint Max) Daily { get; init; } - public (uint Cur, uint Max) Monthly { get; init; } -} \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/IPatronageService.cs b/src/EllieBot/_common/Patronage/IPatronageService.cs index 77fed4b..650bf06 100644 --- a/src/EllieBot/_common/Patronage/IPatronageService.cs +++ b/src/EllieBot/_common/Patronage/IPatronageService.cs @@ -31,26 +31,15 @@ public interface IPatronageService /// /// UserId for which to get the patron data for. /// A patron with the specifeid userId - public Task GetPatronAsync(ulong userId); + public Task GetPatronAsync(ulong userId); - /// - /// Gets the quota statistic for the user/patron specified by the userId - /// - /// UserId of the user for which to get the quota statistic for - /// Quota stats for the specified user - Task GetUserQuotaStatistic(ulong userId); - + Task LimitHitAsync(LimitedFeatureName key, ulong userId, int amount = 1); + Task LimitForceHit(LimitedFeatureName key, ulong userId, int amount); + Task GetUserLimit(LimitedFeatureName name, ulong userId); - Task TryGetFeatureLimitAsync(FeatureLimitKey key, ulong userId, int? defaultValue); - - ValueTask> TryIncrementQuotaCounterAsync( - ulong userId, - bool isSelf, - FeatureType featureType, - string featureName, - uint? maybeHourly, - uint? maybeDaily, - uint? maybeMonthly); + Task> LimitStats(ulong userId); PatronConfigData GetConfig(); + int PercentBonus(Patron? user); + int PercentBonus(long amount); } \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/Patron.cs b/src/EllieBot/_common/Patronage/Patron.cs index a7c9d97..93a7575 100644 --- a/src/EllieBot/_common/Patronage/Patron.cs +++ b/src/EllieBot/_common/Patronage/Patron.cs @@ -13,7 +13,7 @@ public readonly struct Patron public ulong UserId { get; init; } /// - /// Amount the Patron is currently pledging or paid + /// Amount the Patron is currently pledging or paid in cents /// public int Amount { get; init; } diff --git a/src/EllieBot/_common/Patronage/PatronConfigData.cs b/src/EllieBot/_common/Patronage/PatronConfigData.cs index 09ed100..9becae0 100644 --- a/src/EllieBot/_common/Patronage/PatronConfigData.cs +++ b/src/EllieBot/_common/Patronage/PatronConfigData.cs @@ -7,31 +7,11 @@ namespace EllieBot.Modules.Patronage; public partial class PatronConfigData : ICloneable { [Comment("DO NOT CHANGE")] - public int Version { get; set; } = 2; - + public int Version { get; set; } = 3; + [Comment("Whether the patronage feature is enabled")] public bool IsEnabled { get; set; } - [Comment("List of patron only features and relevant quota data")] - public FeatureQuotas Quotas { get; set; } - - public PatronConfigData() - { - Quotas = new(); - } - - public class FeatureQuotas - { - [Comment("Dictionary of feature names with their respective limits. Set to null for unlimited")] - public Dictionary> Features { get; set; } = new(); - - [Comment("Dictionary of commands with their respective quota data")] - public Dictionary?>> Commands { get; set; } = new(); - - [Comment("Dictionary of groups with their respective quota data")] - public Dictionary?>> Groups { get; set; } = new(); - - [Comment("Dictionary of modules with their respective quota data")] - public Dictionary?>> Modules { get; set; } = new(); - } + [Comment("Who can do how much of what")] + public Dictionary> Limits { get; set; } = new(); } \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/PatronExtensions.cs b/src/EllieBot/_common/Patronage/PatronExtensions.cs index b422b73..1686a4c 100644 --- a/src/EllieBot/_common/Patronage/PatronExtensions.cs +++ b/src/EllieBot/_common/Patronage/PatronExtensions.cs @@ -8,15 +8,6 @@ public static class PatronExtensions _ => $"Patron Tier {tier}", }; - public static string ToFullName(this QuotaPer per) - => per switch - { - QuotaPer.PerDay => "per day", - QuotaPer.PerHour => "per hour", - QuotaPer.PerMonth => "per month", - _ => "Unknown", - }; - public static DateTime DayOfNextMonth(this DateTime date, int day) { var nextMonth = date.AddMonths(1); diff --git a/src/EllieBot/_common/Patronage/QuotaLimit.cs b/src/EllieBot/_common/Patronage/QuotaLimit.cs index b40017c..ed2cae9 100644 --- a/src/EllieBot/_common/Patronage/QuotaLimit.cs +++ b/src/EllieBot/_common/Patronage/QuotaLimit.cs @@ -10,57 +10,16 @@ public readonly struct QuotaLimit /// /// Amount of usages reached, which is the limit /// - public uint Quota { get; init; } + public int Quota { get; init; } /// /// Which period is this quota limit for (hourly, daily, monthly, etc...) /// public QuotaPer QuotaPeriod { get; init; } - /// - /// When does this quota limit reset - /// - public DateTime ResetsAt { get; init; } - - /// - /// Type of the feature this quota limit is for - /// - public FeatureType FeatureType { get; init; } - - /// - /// Name of the feature this quota limit is for - /// - public string Feature { get; init; } - - /// - /// Whether it is the user's own quota (true), or server owners (false) - /// - public bool IsOwnQuota { get; init; } -} - - -/// -/// Respresent information about the feature limit -/// -public readonly struct FeatureLimit -{ - - /// - /// Whether this limit comes from the patronage system - /// - public bool IsPatronLimit { get; init; } = false; - - /// - /// Maximum limit allowed - /// - public int? Quota { get; init; } = null; - - /// - /// Name of the limit - /// - public string Name { get; init; } = string.Empty; - - public FeatureLimit() + public QuotaLimit(int quota, QuotaPer quotaPeriod) { + Quota = quota; + QuotaPeriod = quotaPeriod; } } \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/QuotaPer.cs b/src/EllieBot/_common/Patronage/QuotaPer.cs index c6080ac..9f67a40 100644 --- a/src/EllieBot/_common/Patronage/QuotaPer.cs +++ b/src/EllieBot/_common/Patronage/QuotaPer.cs @@ -5,4 +5,5 @@ public enum QuotaPer PerHour, PerDay, PerMonth, + Total, } \ No newline at end of file diff --git a/src/EllieBot/_common/Patronage/UserQuotaStats.cs b/src/EllieBot/_common/Patronage/UserQuotaStats.cs deleted file mode 100644 index a9e33e4..0000000 --- a/src/EllieBot/_common/Patronage/UserQuotaStats.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace EllieBot.Modules.Patronage; - -public readonly struct UserQuotaStats -{ - private static readonly IReadOnlyDictionary _emptyDictionary - = new Dictionary(); - public PatronTier Tier { get; init; } - = PatronTier.None; - - public IReadOnlyDictionary Features { get; init; } - = _emptyDictionary; - - public IReadOnlyDictionary Commands { get; init; } - = _emptyDictionary; - - public IReadOnlyDictionary Groups { get; init; } - = _emptyDictionary; - - public IReadOnlyDictionary Modules { get; init; } - = _emptyDictionary; - - public UserQuotaStats() - { - } -} \ No newline at end of file diff --git a/src/EllieBot/_common/Pokemon/SearchPokemonAbility.cs b/src/EllieBot/_common/Pokemon/SearchPokemonAbility.cs index c3f8f36..f401284 100644 --- a/src/EllieBot/_common/Pokemon/SearchPokemonAbility.cs +++ b/src/EllieBot/_common/Pokemon/SearchPokemonAbility.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Common.Pokemon; public class SearchPokemonAbility diff --git a/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs b/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs index d42bba6..acecd9e 100644 --- a/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs +++ b/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs @@ -95,7 +95,7 @@ public sealed partial class ReplacementPatternStore Register(_rngRegex, match => { - var rng = new EllieRandom(); + var rng = new NadekoRandom(); if (!int.TryParse(match.Groups["from"].ToString(), out var from)) from = 0; if (!int.TryParse(match.Groups["to"].ToString(), out var to)) diff --git a/src/EllieBot/_common/Sender/MessageSenderService.cs b/src/EllieBot/_common/Sender/MessageSenderService.cs index f91f1ab..c6e34ad 100644 --- a/src/EllieBot/_common/Sender/MessageSenderService.cs +++ b/src/EllieBot/_common/Sender/MessageSenderService.cs @@ -33,15 +33,15 @@ public sealed class MessageSenderService : IMessageSenderService, IEService => new ResponseBuilder(_bs, _bcs, _client) .Channel(smc.Channel); - public EllieEmbedBuilder CreateEmbed() - => new EllieEmbedBuilder(_bcs); + public NadekoEmbedBuilder CreateEmbed() + => new NadekoEmbedBuilder(_bcs); } -public class EllieEmbedBuilder : EmbedBuilder +public class NadekoEmbedBuilder : EmbedBuilder { private readonly BotConfig _bc; - public EllieEmbedBuilder(BotConfigService bcs) + public NadekoEmbedBuilder(BotConfigService bcs) { _bc = bcs.Data; } diff --git a/src/EllieBot/_common/Sender/ResponseBuilder.PaginationSender.cs b/src/EllieBot/_common/Sender/ResponseBuilder.PaginationSender.cs index a1dee4d..f4be0c1 100644 --- a/src/EllieBot/_common/Sender/ResponseBuilder.PaginationSender.cs +++ b/src/EllieBot/_common/Sender/ResponseBuilder.PaginationSender.cs @@ -11,6 +11,10 @@ public partial class ResponseBuilder private readonly ResponseBuilder _builder; private readonly DiscordSocketClient _client; private int currentPage; + + private EllieButtonInteractionHandler left; + private EllieButtonInteractionHandler right; + private EllieInteractionBase? extra; public PaginationSender( SourcedPaginatedResponseBuilder paginationBuilder, @@ -106,6 +110,8 @@ public partial class ResponseBuilder return (leftBtnInter, maybeInter, rightBtnInter); } + + (left, extra, right) = await GetInteractions(); async Task UpdatePageAsync(SocketMessageComponent smc) { @@ -114,21 +120,25 @@ public partial class ResponseBuilder if (_paginationBuilder.AddPaginatedFooter) toSend.AddPaginatedFooter(currentPage, lastPage); - var (left, extra, right) = (await GetInteractions()); + left.SetCompleted(); + right.SetCompleted(); + extra?.SetCompleted(); + (left, extra, right) = (await GetInteractions()); var cb = new ComponentBuilder(); left.AddTo(cb); right.AddTo(cb); extra?.AddTo(cb); - + await smc.ModifyOriginalResponseAsync(x => { x.Embed = toSend.Build(); x.Components = cb.Build(); }); + + await Task.WhenAll(left.RunAsync(smc.Message), extra?.RunAsync(smc.Message) ?? Task.CompletedTask, right.RunAsync(smc.Message)); } - var (left, extra, right) = await GetInteractions(); var cb = new ComponentBuilder(); left.AddTo(cb); @@ -144,9 +154,11 @@ public partial class ResponseBuilder if (lastPage == 0 && _paginationBuilder.InteractionFunc is null) return; - + await Task.WhenAll(left.RunAsync(msg), extra?.RunAsync(msg) ?? Task.CompletedTask, right.RunAsync(msg)); + await Task.Delay(30_000); + await msg.ModifyAsync(mp => mp.Components = new ComponentBuilder().Build()); } } diff --git a/src/EllieBot/_common/ServiceCollectionExtensions.cs b/src/EllieBot/_common/ServiceCollectionExtensions.cs index 4b468d2..3a59226 100644 --- a/src/EllieBot/_common/ServiceCollectionExtensions.cs +++ b/src/EllieBot/_common/ServiceCollectionExtensions.cs @@ -1,4 +1,4 @@ -using DryIoc; +using DryIoc; using LinqToDB.Extensions; using Microsoft.Extensions.DependencyInjection; using EllieBot.Modules.Music; @@ -33,7 +33,7 @@ public static class ServiceCollectionExtensions public static IContainer AddConfigServices(this IContainer svcs, Assembly a) { - + foreach (var type in a.GetTypes() .Where(x => !x.IsAbstract && x.IsAssignableToGenericType(typeof(ConfigServiceBase<>)))) { @@ -41,7 +41,7 @@ public static class ServiceCollectionExtensions getServiceTypes: type => type.GetImplementedTypes(ReflectionTools.AsImplementedType.SourceType), getImplFactory: type => ReflectionFactory.Of(type, Reuse.Singleton)); } - + return svcs; } @@ -95,7 +95,7 @@ public static class ServiceCollectionExtensions }); var prov = proxySvcs.BuildServiceProvider(); - + svcs.RegisterDelegate(_ => prov.GetRequiredService()); svcs.RegisterDelegate(_ => prov.GetRequiredService()); @@ -113,7 +113,7 @@ public static class ServiceCollectionExtensions typeof(IInputTransformer), typeof(IEService) ]; - + foreach (var svc in a.GetTypes() .Where(type => type.IsClass && types.Any(t => type.IsAssignableTo(t)) && !type.HasAttribute() #if GLOBAL_ELLIE diff --git a/src/EllieBot/_common/Services/CommandHandler.cs b/src/EllieBot/_common/Services/CommandHandler.cs index c058887..2061b29 100644 --- a/src/EllieBot/_common/Services/CommandHandler.cs +++ b/src/EllieBot/_common/Services/CommandHandler.cs @@ -9,7 +9,7 @@ namespace EllieBot.Services; public class CommandHandler : IEService, IReadyExecutor, ICommandHandler { - private const int GLOBAL_COMMANDS_COOLDOWN = 750; + private const int GLOBAL_COMMANDS_COOLDOWN = 200; private const float ONE_THOUSANDTH = 1.0f / 1000; @@ -262,7 +262,7 @@ public class CommandHandler : IEService, IReadyExecutor, ICommandHandler var blockTime = Environment.TickCount - startTime; var messageContent = await _behaviorHandler.RunInputTransformersAsync(guild, usrMsg); - + var prefix = GetPrefix(guild?.Id); var isPrefixCommand = messageContent.StartsWith(".prefix", StringComparison.InvariantCultureIgnoreCase); // execute the command and measure the time it took diff --git a/src/EllieBot/_common/Services/IBehaviourHandler.cs b/src/EllieBot/_common/Services/IBehaviourHandler.cs index 79e8e5a..2f75074 100644 --- a/src/EllieBot/_common/Services/IBehaviourHandler.cs +++ b/src/EllieBot/_common/Services/IBehaviourHandler.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services; public interface IBehaviorHandler @@ -7,7 +7,7 @@ public interface IBehaviorHandler Task AddRangeAsync(IEnumerable behavior); Task RemoveAsync(ICustomBehavior behavior); Task RemoveRangeAsync(IEnumerable behs); - + Task RunExecOnMessageAsync(SocketGuild guild, IUserMessage usrMsg); Task RunInputTransformersAsync(SocketGuild guild, IUserMessage usrMsg); Task RunPreCommandAsync(ICommandContext context, CommandInfo cmd); diff --git a/src/EllieBot/_common/Services/ILocalization.cs b/src/EllieBot/_common/Services/ILocalization.cs index 3fa7c5e..ab37be5 100644 --- a/src/EllieBot/_common/Services/ILocalization.cs +++ b/src/EllieBot/_common/Services/ILocalization.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System.Globalization; namespace EllieBot.Services; diff --git a/src/EllieBot/_common/Services/ITimezoneService.cs b/src/EllieBot/_common/Services/ITimezoneService.cs index aa8cbff..e70b985 100644 --- a/src/EllieBot/_common/Services/ITimezoneService.cs +++ b/src/EllieBot/_common/Services/ITimezoneService.cs @@ -1,4 +1,4 @@ -namespace EllieBot.Common; +namespace EllieBot.Common; public interface ITimezoneService { diff --git a/src/EllieBot/_common/Services/Impl/YtdlOperation.cs b/src/EllieBot/_common/Services/Impl/YtdlOperation.cs index f302ab7..3813b80 100644 --- a/src/EllieBot/_common/Services/Impl/YtdlOperation.cs +++ b/src/EllieBot/_common/Services/Impl/YtdlOperation.cs @@ -53,7 +53,7 @@ public class YtdlOperation } catch (Win32Exception) { - Log.Error("youtube-dl is likely not installed. " + "Please install it before running the command again"); + Log.Error("youtube-dl is likely not installed. Please install it before running the command again"); return default; } catch (Exception ex) diff --git a/src/EllieBot/_common/Settings/BotConfigService.cs b/src/EllieBot/_common/Settings/BotConfigService.cs index 952f402..477f080 100644 --- a/src/EllieBot/_common/Settings/BotConfigService.cs +++ b/src/EllieBot/_common/Settings/BotConfigService.cs @@ -49,21 +49,21 @@ public sealed class BotConfigService : ConfigServiceBase .ToHashSet(); }); } - + if (data.Version < 4) ModifyConfig(c => { c.Version = 4; c.CheckForUpdates = true; }); - - if (data.Version < 5) + + if(data.Version < 5) ModifyConfig(c => { c.Version = 5; }); - - if (data.Version < 7) + + if(data.Version < 7) ModifyConfig(c => { c.Version = 7; diff --git a/src/EllieBot/_common/Settings/ConfigParsers.cs b/src/EllieBot/_common/Settings/ConfigParsers.cs index c32b7ca..8eda144 100644 --- a/src/EllieBot/_common/Settings/ConfigParsers.cs +++ b/src/EllieBot/_common/Settings/ConfigParsers.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using SixLabors.ImageSharp.PixelFormats; using System.Globalization; @@ -33,7 +33,7 @@ public static class ConfigParsers } public static bool InsensitiveEnum(string input, out T output) - where T : struct + where T: struct => Enum.TryParse(input, true, out output); } diff --git a/src/EllieBot/_common/Settings/ConfigServiceBase.cs b/src/EllieBot/_common/Settings/ConfigServiceBase.cs index bdf76d8..ab4a15f 100644 --- a/src/EllieBot/_common/Settings/ConfigServiceBase.cs +++ b/src/EllieBot/_common/Settings/ConfigServiceBase.cs @@ -1,9 +1,9 @@ -using EllieBot.Common.Configs; +using EllieBot.Common.Configs; using EllieBot.Common.Yml; using System.Linq.Expressions; using System.Reflection; -namespace EllieBot.Services; +namespace NadekoBot.Services; /// /// Base service for all settings services diff --git a/src/EllieBot/_common/Settings/IConfigService.cs b/src/EllieBot/_common/Settings/IConfigService.cs index 69ac966..ae97198 100644 --- a/src/EllieBot/_common/Settings/IConfigService.cs +++ b/src/EllieBot/_common/Settings/IConfigService.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services; /// diff --git a/src/EllieBot/_common/Settings/SettingParser.cs b/src/EllieBot/_common/Settings/SettingParser.cs index 06a8e75..1437591 100644 --- a/src/EllieBot/_common/Settings/SettingParser.cs +++ b/src/EllieBot/_common/Settings/SettingParser.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Services; /// diff --git a/src/EllieBot/_common/Yml/CommentAttribute.cs b/src/EllieBot/_common/Yml/CommentAttribute.cs index 7c04bea..1c1ad89 100644 --- a/src/EllieBot/_common/Yml/CommentAttribute.cs +++ b/src/EllieBot/_common/Yml/CommentAttribute.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Common.Yml; [AttributeUsage(AttributeTargets.Property)] diff --git a/src/EllieBot/_common/Yml/MultilineScalarFlowStyleEmitter.cs b/src/EllieBot/_common/Yml/MultilineScalarFlowStyleEmitter.cs index e2cfd97..c63dcab 100644 --- a/src/EllieBot/_common/Yml/MultilineScalarFlowStyleEmitter.cs +++ b/src/EllieBot/_common/Yml/MultilineScalarFlowStyleEmitter.cs @@ -5,7 +5,6 @@ using YamlDotNet.Serialization.EventEmitters; namespace EllieBot.Common.Yml; - public class MultilineScalarFlowStyleEmitter : ChainedEventEmitter { public MultilineScalarFlowStyleEmitter(IEventEmitter nextEmitter) diff --git a/src/EllieBot/_common/_Extensions/CommandContextExtensions.cs b/src/EllieBot/_common/_Extensions/CommandContextExtensions.cs index 7f90d78..ebb019b 100644 --- a/src/EllieBot/_common/_Extensions/CommandContextExtensions.cs +++ b/src/EllieBot/_common/_Extensions/CommandContextExtensions.cs @@ -27,4 +27,14 @@ public static class CommandContextExtensions public static Task WarningAsync(this ICommandContext ctx) => ctx.ReactAsync(MsgType.Pending); + + + public static Task OkAsync(this IUserMessage msg) + => msg.AddReactionAsync(_okEmoji); + + public static Task ErrorAsync(this IUserMessage msg) + => msg.AddReactionAsync(_errorEmoji); + + public static Task WarningAsync(this IUserMessage msg) + => msg.AddReactionAsync(_warnEmoji); } \ No newline at end of file diff --git a/src/EllieBot/_common/_Extensions/Extensions.cs b/src/EllieBot/_common/_Extensions/Extensions.cs index 27341ad..f0cb9f9 100644 --- a/src/EllieBot/_common/_Extensions/Extensions.cs +++ b/src/EllieBot/_common/_Extensions/Extensions.cs @@ -229,6 +229,7 @@ public static class Extensions public static IEnumerable GetRoles(this IGuildUser user) => user.RoleIds.Select(r => user.Guild.GetRole(r)).Where(r => r is not null); + // todo remove public static void Lap(this Stopwatch sw, string checkpoint) { Log.Information("Checkpoint {CheckPoint}: {Time}ms", checkpoint, sw.Elapsed.TotalMilliseconds); From 0f927a3dd1d63c740587fc00960e32ec8b58c17b Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 21:01:23 +1200 Subject: [PATCH 05/25] Updated Db files --- src/EllieBot/Db/EllieContext.cs | 12 -------- .../Db/Models/anti/AntiRaidSetting.cs | 1 - src/EllieBot/Db/Models/support/PatronQuota.cs | 30 ++----------------- 3 files changed, 3 insertions(+), 40 deletions(-) diff --git a/src/EllieBot/Db/EllieContext.cs b/src/EllieBot/Db/EllieContext.cs index 263963b..2ca114e 100644 --- a/src/EllieBot/Db/EllieContext.cs +++ b/src/EllieBot/Db/EllieContext.cs @@ -53,8 +53,6 @@ public abstract class EllieContext : DbContext public DbSet Patrons { get; set; } - public DbSet PatronQuotas { get; set; } - public DbSet StreamOnlineMessages { get; set; } public DbSet StickyRoles { get; set; } @@ -597,16 +595,6 @@ public abstract class EllieContext : DbContext }); // quotes are per user id - modelBuilder.Entity(pq => - { - pq.HasIndex(x => x.UserId).IsUnique(false); - pq.HasKey(x => new - { - x.UserId, - x.FeatureType, - x.Feature - }); - }); #endregion diff --git a/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs b/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs index b5e5f67..351d194 100644 --- a/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs +++ b/src/EllieBot/Db/Models/anti/AntiRaidSetting.cs @@ -3,7 +3,6 @@ using System.ComponentModel.DataAnnotations.Schema; namespace EllieBot.Db.Models; - public class AntiRaidSetting : DbEntity { public int GuildConfigId { get; set; } diff --git a/src/EllieBot/Db/Models/support/PatronQuota.cs b/src/EllieBot/Db/Models/support/PatronQuota.cs index 1ebd2fd..688d005 100644 --- a/src/EllieBot/Db/Models/support/PatronQuota.cs +++ b/src/EllieBot/Db/Models/support/PatronQuota.cs @@ -1,41 +1,17 @@ #nullable disable namespace EllieBot.Db.Models; -/// -/// Contains data about usage of Patron-Only commands per user -/// in order to provide support for quota limitations -/// (allow user x who is pledging amount y to use the specified command only -/// x amount of times in the specified time period) -/// -public class PatronQuota -{ - public ulong UserId { get; set; } - public FeatureType FeatureType { get; set; } - public string Feature { get; set; } - public uint HourlyCount { get; set; } - public uint DailyCount { get; set; } - public uint MonthlyCount { get; set; } -} - -public enum FeatureType -{ - Command, - Group, - Module, - Limit -} - public class PatronUser { public string UniquePlatformUserId { get; set; } public ulong UserId { get; set; } public int AmountCents { get; set; } - + public DateTime LastCharge { get; set; } - + // Date Only component public DateTime ValidThru { get; set; } - + public PatronUser Clone() => new PatronUser() { From ed7deeb99dfb1049d1da30389e75aedff802095b Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 21:03:14 +1200 Subject: [PATCH 06/25] Updated Migrations files --- .../20220409170652_mysql-init.Designer.cs | 2 +- .../Mysql/20220428044612_stondel.Designer.cs | 2 +- .../Mysql/20220429044757_bank.Designer.cs | 2 +- .../Mysql/20220504162509_new-rero.Designer.cs | 2 +- ...0220614071410_patronage-system.Designer.cs | 2 +- ...0220623090718_stondel-db-cache.Designer.cs | 2 +- .../Mysql/20220703194400_logwarns.Designer.cs | 2 +- .../20220725155953_xpitemshop.Designer.cs | 2 +- ...220727033931_linkonly-channels.Designer.cs | 2 +- ...855_remove-obsolete-xp-columns.Designer.cs | 2 +- .../Mysql/20220831142722_banprune.Designer.cs | 2 +- .../20220913192520_shop-role-req.Designer.cs | 2 +- .../Mysql/20220916194514_autopub.Designer.cs | 2 +- .../20221003175743_gambling-stats.Designer.cs | 2 +- ...2758_toggle-global-expressions.Designer.cs | 2 +- .../20221118195208_log-thread.Designer.cs | 2 +- .../20221122204432_feed-text.Designer.cs | 2 +- .../Mysql/20240502233216_v5.Designer.cs | 2 +- ...0518221440_guidlconfig-cleanup.Designer.cs | 2 +- ...611180516_remove-patron-limits.Designer.cs | 3784 +++++++++++++++++ .../20240611180516_remove-patron-limits.cs | 44 + .../Mysql/MysqlContextModelSnapshot.cs | 35 - .../20220428044547_stondel.Designer.cs | 2 +- .../20220429044808_bank.Designer.cs | 2 +- .../20220504162457_new-rero.Designer.cs | 2 +- ...0220614071421_patronage-system.Designer.cs | 2 +- ...0220623090729_stondel-db-cache.Designer.cs | 2 +- .../20220703194412_logwarns.Designer.cs | 2 +- .../20220725155941_xpitemshop.Designer.cs | 2 +- ...220727033944_linkonly-channels.Designer.cs | 2 +- ...559_remove-obsolete-xp-columns.Designer.cs | 2 +- .../20220831142735_banprune.Designer.cs | 2 +- .../20220913192529_shop-role-req.Designer.cs | 2 +- .../20220916194523_autopub.Designer.cs | 2 +- .../20221003175752_gambling-stats.Designer.cs | 2 +- ...2807_toggle-global-expressions.Designer.cs | 2 +- .../20221118195200_log-thread.Designer.cs | 2 +- .../20221122204423_feed-text.Designer.cs | 2 +- .../PostgreSql/20240502233202_v5.Designer.cs | 2 +- ...0518221432_guidlconfig-cleanup.Designer.cs | 2 +- ...611180506_remove-patron-limits.Designer.cs | 3781 ++++++++++++++++ .../20240611180506_remove-patron-limits.cs | 42 + .../PostgreSqlContextModelSnapshot.cs | 35 - .../20240518221424_guidlconfig-cleanup.cs | 2 +- ...611180456_remove-patron-limits.Designer.cs | 2921 +++++++++++++ .../20240611180456_remove-patron-limits.cs | 42 + .../Sqlite/EllieSqliteContextModelSnapshot.cs | 27 - 47 files changed, 10652 insertions(+), 135 deletions(-) create mode 100644 src/EllieBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs create mode 100644 src/EllieBot/Migrations/Mysql/20240611180516_remove-patron-limits.cs create mode 100644 src/EllieBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs create mode 100644 src/EllieBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.cs create mode 100644 src/EllieBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs create mode 100644 src/EllieBot/Migrations/Sqlite/20240611180456_remove-patron-limits.cs diff --git a/src/EllieBot/Migrations/Mysql/20220409170652_mysql-init.Designer.cs b/src/EllieBot/Migrations/Mysql/20220409170652_mysql-init.Designer.cs index 4872ab6..458c74a 100644 --- a/src/EllieBot/Migrations/Mysql/20220409170652_mysql-init.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220409170652_mysql-init.Designer.cs @@ -1418,7 +1418,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220428044612_stondel.Designer.cs b/src/EllieBot/Migrations/Mysql/20220428044612_stondel.Designer.cs index 04ca748..3eef208 100644 --- a/src/EllieBot/Migrations/Mysql/20220428044612_stondel.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220428044612_stondel.Designer.cs @@ -1422,7 +1422,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220429044757_bank.Designer.cs b/src/EllieBot/Migrations/Mysql/20220429044757_bank.Designer.cs index 1a8d96b..f47381e 100644 --- a/src/EllieBot/Migrations/Mysql/20220429044757_bank.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220429044757_bank.Designer.cs @@ -1451,7 +1451,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220504162509_new-rero.Designer.cs b/src/EllieBot/Migrations/Mysql/20220504162509_new-rero.Designer.cs index 207ba53..ef0f91b 100644 --- a/src/EllieBot/Migrations/Mysql/20220504162509_new-rero.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220504162509_new-rero.Designer.cs @@ -1451,7 +1451,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220614071410_patronage-system.Designer.cs b/src/EllieBot/Migrations/Mysql/20220614071410_patronage-system.Designer.cs index 27b18ac..9ae3e46 100644 --- a/src/EllieBot/Migrations/Mysql/20220614071410_patronage-system.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220614071410_patronage-system.Designer.cs @@ -1521,7 +1521,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220623090718_stondel-db-cache.Designer.cs b/src/EllieBot/Migrations/Mysql/20220623090718_stondel-db-cache.Designer.cs index d0d2681..3b4cb17 100644 --- a/src/EllieBot/Migrations/Mysql/20220623090718_stondel-db-cache.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220623090718_stondel-db-cache.Designer.cs @@ -1554,7 +1554,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220703194400_logwarns.Designer.cs b/src/EllieBot/Migrations/Mysql/20220703194400_logwarns.Designer.cs index 4b23faf..9a940a3 100644 --- a/src/EllieBot/Migrations/Mysql/20220703194400_logwarns.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220703194400_logwarns.Designer.cs @@ -1558,7 +1558,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220725155953_xpitemshop.Designer.cs b/src/EllieBot/Migrations/Mysql/20220725155953_xpitemshop.Designer.cs index 28e1540..e887ab4 100644 --- a/src/EllieBot/Migrations/Mysql/20220725155953_xpitemshop.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220725155953_xpitemshop.Designer.cs @@ -1596,7 +1596,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220727033931_linkonly-channels.Designer.cs b/src/EllieBot/Migrations/Mysql/20220727033931_linkonly-channels.Designer.cs index 166a899..11a1e05 100644 --- a/src/EllieBot/Migrations/Mysql/20220727033931_linkonly-channels.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220727033931_linkonly-channels.Designer.cs @@ -1600,7 +1600,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220808141855_remove-obsolete-xp-columns.Designer.cs b/src/EllieBot/Migrations/Mysql/20220808141855_remove-obsolete-xp-columns.Designer.cs index 407b1b1..26d81e5 100644 --- a/src/EllieBot/Migrations/Mysql/20220808141855_remove-obsolete-xp-columns.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220808141855_remove-obsolete-xp-columns.Designer.cs @@ -1588,7 +1588,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220831142722_banprune.Designer.cs b/src/EllieBot/Migrations/Mysql/20220831142722_banprune.Designer.cs index 1afccb9..19d21c1 100644 --- a/src/EllieBot/Migrations/Mysql/20220831142722_banprune.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220831142722_banprune.Designer.cs @@ -1592,7 +1592,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220913192520_shop-role-req.Designer.cs b/src/EllieBot/Migrations/Mysql/20220913192520_shop-role-req.Designer.cs index bbf5c0f..031585a 100644 --- a/src/EllieBot/Migrations/Mysql/20220913192520_shop-role-req.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220913192520_shop-role-req.Designer.cs @@ -1592,7 +1592,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20220916194514_autopub.Designer.cs b/src/EllieBot/Migrations/Mysql/20220916194514_autopub.Designer.cs index f5dc4a0..af77b12 100644 --- a/src/EllieBot/Migrations/Mysql/20220916194514_autopub.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20220916194514_autopub.Designer.cs @@ -1621,7 +1621,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20221003175743_gambling-stats.Designer.cs b/src/EllieBot/Migrations/Mysql/20221003175743_gambling-stats.Designer.cs index eeb172f..c2041d8 100644 --- a/src/EllieBot/Migrations/Mysql/20221003175743_gambling-stats.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20221003175743_gambling-stats.Designer.cs @@ -1654,7 +1654,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20221021192758_toggle-global-expressions.Designer.cs b/src/EllieBot/Migrations/Mysql/20221021192758_toggle-global-expressions.Designer.cs index 68aacf9..a953c5f 100644 --- a/src/EllieBot/Migrations/Mysql/20221021192758_toggle-global-expressions.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20221021192758_toggle-global-expressions.Designer.cs @@ -1658,7 +1658,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20221118195208_log-thread.Designer.cs b/src/EllieBot/Migrations/Mysql/20221118195208_log-thread.Designer.cs index a31fad2..ba0d48a 100644 --- a/src/EllieBot/Migrations/Mysql/20221118195208_log-thread.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20221118195208_log-thread.Designer.cs @@ -1666,7 +1666,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20221122204432_feed-text.Designer.cs b/src/EllieBot/Migrations/Mysql/20221122204432_feed-text.Designer.cs index 63be61d..d21380b 100644 --- a/src/EllieBot/Migrations/Mysql/20221122204432_feed-text.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20221122204432_feed-text.Designer.cs @@ -1670,7 +1670,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20240502233216_v5.Designer.cs b/src/EllieBot/Migrations/Mysql/20240502233216_v5.Designer.cs index d20fae3..4c8220f 100644 --- a/src/EllieBot/Migrations/Mysql/20240502233216_v5.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20240502233216_v5.Designer.cs @@ -1700,7 +1700,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Db.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Db.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20240518221440_guidlconfig-cleanup.Designer.cs b/src/EllieBot/Migrations/Mysql/20240518221440_guidlconfig-cleanup.Designer.cs index aa5e2cb..7c2b93b 100644 --- a/src/EllieBot/Migrations/Mysql/20240518221440_guidlconfig-cleanup.Designer.cs +++ b/src/EllieBot/Migrations/Mysql/20240518221440_guidlconfig-cleanup.Designer.cs @@ -1670,7 +1670,7 @@ namespace EllieBot.Migrations.Mysql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Db.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Db.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs b/src/EllieBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs new file mode 100644 index 0000000..fb9293b --- /dev/null +++ b/src/EllieBot/Migrations/Mysql/20240611180516_remove-patron-limits.Designer.cs @@ -0,0 +1,3784 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using EllieBot.Db; + +#nullable disable + +namespace EllieBot.Migrations.Mysql +{ + [DbContext(typeof(MysqlContext))] + [Migration("20240611180516_remove-patron-limits")] + partial class removepatronlimits + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("EllieBot.Db.Models.AntiAltSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("int") + .HasColumnName("action"); + + b.Property("ActionDurationMinutes") + .HasColumnType("int") + .HasColumnName("actiondurationminutes"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("MinAge") + .HasColumnType("time(6)") + .HasColumnName("minage"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_antialtsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antialtsetting_guildconfigid"); + + b.ToTable("antialtsetting", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("int") + .HasColumnName("action"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("PunishDuration") + .HasColumnType("int") + .HasColumnName("punishduration"); + + b.Property("Seconds") + .HasColumnType("int") + .HasColumnName("seconds"); + + b.Property("UserThreshold") + .HasColumnType("int") + .HasColumnName("userthreshold"); + + b.HasKey("Id") + .HasName("pk_antiraidsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antiraidsetting_guildconfigid"); + + b.ToTable("antiraidsetting", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AntiSpamSettingId") + .HasColumnType("int") + .HasColumnName("antispamsettingid"); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.HasKey("Id") + .HasName("pk_antispamignore"); + + b.HasIndex("AntiSpamSettingId") + .HasDatabaseName("ix_antispamignore_antispamsettingid"); + + b.ToTable("antispamignore", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("int") + .HasColumnName("action"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("MessageThreshold") + .HasColumnType("int") + .HasColumnName("messagethreshold"); + + b.Property("MuteTime") + .HasColumnType("int") + .HasColumnName("mutetime"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_antispamsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antispamsetting_guildconfigid"); + + b.ToTable("antispamsetting", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ArchivedTodoListModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_todosarchive"); + + b.ToTable("todosarchive", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("ChannelName") + .HasColumnType("longtext") + .HasColumnName("channelname"); + + b.Property("CommandText") + .HasColumnType("longtext") + .HasColumnName("commandtext"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("GuildName") + .HasColumnType("longtext") + .HasColumnName("guildname"); + + b.Property("Interval") + .HasColumnType("int") + .HasColumnName("interval"); + + b.Property("VoiceChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("voicechannelid"); + + b.Property("VoiceChannelName") + .HasColumnType("longtext") + .HasColumnName("voicechannelname"); + + b.HasKey("Id") + .HasName("pk_autocommands"); + + b.ToTable("autocommands", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoPublishChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.HasKey("Id") + .HasName("pk_autopublishchannel"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_autopublishchannel_guildid"); + + b.ToTable("autopublishchannel", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AutoDelete") + .HasColumnType("tinyint(1)") + .HasColumnName("autodelete"); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.HasKey("Id") + .HasName("pk_autotranslatechannels"); + + b.HasIndex("ChannelId") + .IsUnique() + .HasDatabaseName("ix_autotranslatechannels_channelid"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_autotranslatechannels_guildid"); + + b.ToTable("autotranslatechannels", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("int") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Source") + .HasColumnType("longtext") + .HasColumnName("source"); + + b.Property("Target") + .HasColumnType("longtext") + .HasColumnName("target"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_autotranslateusers"); + + b.HasAlternateKey("ChannelId", "UserId") + .HasName("ak_autotranslateusers_channelid_userid"); + + b.ToTable("autotranslateusers", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.BanTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("PruneDays") + .HasColumnType("int") + .HasColumnName("prunedays"); + + b.Property("Text") + .HasColumnType("longtext") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_bantemplates"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_bantemplates_guildid"); + + b.ToTable("bantemplates", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.BankUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Balance") + .HasColumnType("bigint") + .HasColumnName("balance"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_bankusers"); + + b.HasIndex("UserId") + .IsUnique() + .HasDatabaseName("ix_bankusers_userid"); + + b.ToTable("bankusers", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.BlacklistEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ItemId") + .HasColumnType("bigint unsigned") + .HasColumnName("itemid"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_blacklist"); + + b.ToTable("blacklist", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubApplicants", b => + { + b.Property("ClubId") + .HasColumnType("int") + .HasColumnName("clubid"); + + b.Property("UserId") + .HasColumnType("int") + .HasColumnName("userid"); + + b.HasKey("ClubId", "UserId") + .HasName("pk_clubapplicants"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_clubapplicants_userid"); + + b.ToTable("clubapplicants", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubBans", b => + { + b.Property("ClubId") + .HasColumnType("int") + .HasColumnName("clubid"); + + b.Property("UserId") + .HasColumnType("int") + .HasColumnName("userid"); + + b.HasKey("ClubId", "UserId") + .HasName("pk_clubbans"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_clubbans_userid"); + + b.ToTable("clubbans", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Description") + .HasColumnType("longtext") + .HasColumnName("description"); + + b.Property("ImageUrl") + .HasColumnType("longtext") + .HasColumnName("imageurl"); + + b.Property("Name") + .HasMaxLength(20) + .HasColumnType("varchar(20)") + .HasColumnName("name") + .UseCollation("utf8mb4_bin"); + + b.Property("OwnerId") + .HasColumnType("int") + .HasColumnName("ownerid"); + + b.Property("Xp") + .HasColumnType("int") + .HasColumnName("xp"); + + b.HasKey("Id") + .HasName("pk_clubs"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_clubs_name"); + + b.HasIndex("OwnerId") + .IsUnique() + .HasDatabaseName("ix_clubs_ownerid"); + + b.ToTable("clubs", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Mapping") + .HasColumnType("longtext") + .HasColumnName("mapping"); + + b.Property("Trigger") + .HasColumnType("longtext") + .HasColumnName("trigger"); + + b.HasKey("Id") + .HasName("pk_commandalias"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_commandalias_guildconfigid"); + + b.ToTable("commandalias", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("CommandName") + .HasColumnType("longtext") + .HasColumnName("commandname"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Seconds") + .HasColumnType("int") + .HasColumnName("seconds"); + + b.HasKey("Id") + .HasName("pk_commandcooldown"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_commandcooldown_guildconfigid"); + + b.ToTable("commandcooldown", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("bigint") + .HasColumnName("amount"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Extra") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("extra"); + + b.Property("Note") + .HasColumnType("longtext") + .HasColumnName("note"); + + b.Property("OtherId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint unsigned") + .HasColumnName("otherid") + .HasDefaultValueSql("NULL"); + + b.Property("Type") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("type"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_currencytransactions"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_currencytransactions_userid"); + + b.ToTable("currencytransactions", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("State") + .HasColumnType("tinyint(1)") + .HasColumnName("state"); + + b.HasKey("Id") + .HasName("pk_delmsgoncmdchannel"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_delmsgoncmdchannel_guildconfigid"); + + b.ToTable("delmsgoncmdchannel", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DiscordPermOverride", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Command") + .HasColumnType("varchar(255)") + .HasColumnName("command"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Perm") + .HasColumnType("bigint unsigned") + .HasColumnName("perm"); + + b.HasKey("Id") + .HasName("pk_discordpermoverrides"); + + b.HasIndex("GuildId", "Command") + .IsUnique() + .HasDatabaseName("ix_discordpermoverrides_guildid_command"); + + b.ToTable("discordpermoverrides", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AvatarId") + .HasColumnType("longtext") + .HasColumnName("avatarid"); + + b.Property("ClubId") + .HasColumnType("int") + .HasColumnName("clubid"); + + b.Property("CurrencyAmount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L) + .HasColumnName("currencyamount"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Discriminator") + .HasColumnType("longtext") + .HasColumnName("discriminator"); + + b.Property("IsClubAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(false) + .HasColumnName("isclubadmin"); + + b.Property("NotifyOnLevelUp") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("notifyonlevelup"); + + b.Property("TotalXp") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L) + .HasColumnName("totalxp"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("longtext") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_discorduser"); + + b.HasAlternateKey("UserId") + .HasName("ak_discorduser_userid"); + + b.HasIndex("ClubId") + .HasDatabaseName("ix_discorduser_clubid"); + + b.HasIndex("CurrencyAmount") + .HasDatabaseName("ix_discorduser_currencyamount"); + + b.HasIndex("TotalXp") + .HasDatabaseName("ix_discorduser_totalxp"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_discorduser_userid"); + + b.ToTable("discorduser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ItemId") + .HasColumnType("bigint unsigned") + .HasColumnName("itemid"); + + b.Property("ItemType") + .HasColumnType("int") + .HasColumnName("itemtype"); + + b.Property("XpSettingsId") + .HasColumnType("int") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_excludeditem"); + + b.HasIndex("XpSettingsId") + .HasDatabaseName("ix_excludeditem_xpsettingsid"); + + b.ToTable("excludeditem", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("Url") + .IsRequired() + .HasColumnType("varchar(255)") + .HasColumnName("url"); + + b.HasKey("Id") + .HasName("pk_feedsub"); + + b.HasAlternateKey("GuildConfigId", "Url") + .HasName("ak_feedsub_guildconfigid_url"); + + b.ToTable("feedsub", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterchannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterchannelid_guildconfigid"); + + b.ToTable("filterchannelid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterLinksChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterlinkschannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterlinkschannelid_guildconfigid"); + + b.ToTable("filterlinkschannelid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterWordsChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterwordschannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterwordschannelid_guildconfigid"); + + b.ToTable("filterwordschannelid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Word") + .HasColumnType("longtext") + .HasColumnName("word"); + + b.HasKey("Id") + .HasName("pk_filteredword"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filteredword_guildconfigid"); + + b.ToTable("filteredword", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.Property("Username") + .HasColumnType("longtext") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_followedstream"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_followedstream_guildconfigid"); + + b.ToTable("followedstream", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_gcchannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_gcchannelid_guildconfigid"); + + b.ToTable("gcchannelid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GamblingStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Bet") + .HasColumnType("decimal(65,30)") + .HasColumnName("bet"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Feature") + .HasColumnType("varchar(255)") + .HasColumnName("feature"); + + b.Property("PaidOut") + .HasColumnType("decimal(65,30)") + .HasColumnName("paidout"); + + b.HasKey("Id") + .HasName("pk_gamblingstats"); + + b.HasIndex("Feature") + .IsUnique() + .HasDatabaseName("ix_gamblingstats_feature"); + + b.ToTable("gamblingstats", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("EndsAt") + .HasColumnType("datetime(6)") + .HasColumnName("endsat"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("MessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageid"); + + b.HasKey("Id") + .HasName("pk_giveawaymodel"); + + b.ToTable("giveawaymodel", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("GiveawayId") + .HasColumnType("int") + .HasColumnName("giveawayid"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_giveawayuser"); + + b.HasIndex("GiveawayId", "UserId") + .IsUnique() + .HasDatabaseName("ix_giveawayuser_giveawayid_userid"); + + b.ToTable("giveawayuser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GroupName", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("Number") + .HasColumnType("int") + .HasColumnName("number"); + + b.HasKey("Id") + .HasName("pk_groupname"); + + b.HasIndex("GuildConfigId", "Number") + .IsUnique() + .HasDatabaseName("ix_groupname_guildconfigid_number"); + + b.ToTable("groupname", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AutoAssignRoleIds") + .HasColumnType("longtext") + .HasColumnName("autoassignroleids"); + + b.Property("AutoDeleteByeMessagesTimer") + .HasColumnType("int") + .HasColumnName("autodeletebyemessagestimer"); + + b.Property("AutoDeleteGreetMessagesTimer") + .HasColumnType("int") + .HasColumnName("autodeletegreetmessagestimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages") + .HasColumnType("tinyint(1)") + .HasColumnName("autodeleteselfassignedrolemessages"); + + b.Property("BoostMessage") + .HasColumnType("longtext") + .HasColumnName("boostmessage"); + + b.Property("BoostMessageChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("boostmessagechannelid"); + + b.Property("BoostMessageDeleteAfter") + .HasColumnType("int") + .HasColumnName("boostmessagedeleteafter"); + + b.Property("ByeMessageChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("byemessagechannelid"); + + b.Property("ChannelByeMessageText") + .HasColumnType("longtext") + .HasColumnName("channelbyemessagetext"); + + b.Property("ChannelGreetMessageText") + .HasColumnType("longtext") + .HasColumnName("channelgreetmessagetext"); + + b.Property("CleverbotEnabled") + .HasColumnType("tinyint(1)") + .HasColumnName("cleverbotenabled"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("DeleteMessageOnCommand") + .HasColumnType("tinyint(1)") + .HasColumnName("deletemessageoncommand"); + + b.Property("DeleteStreamOnlineMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("deletestreamonlinemessage"); + + b.Property("DisableGlobalExpressions") + .HasColumnType("tinyint(1)") + .HasColumnName("disableglobalexpressions"); + + b.Property("DmGreetMessageText") + .HasColumnType("longtext") + .HasColumnName("dmgreetmessagetext"); + + b.Property("ExclusiveSelfAssignedRoles") + .HasColumnType("tinyint(1)") + .HasColumnName("exclusiveselfassignedroles"); + + b.Property("FilterInvites") + .HasColumnType("tinyint(1)") + .HasColumnName("filterinvites"); + + b.Property("FilterLinks") + .HasColumnType("tinyint(1)") + .HasColumnName("filterlinks"); + + b.Property("FilterWords") + .HasColumnType("tinyint(1)") + .HasColumnName("filterwords"); + + b.Property("GameVoiceChannel") + .HasColumnType("bigint unsigned") + .HasColumnName("gamevoicechannel"); + + b.Property("GreetMessageChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("greetmessagechannelid"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Locale") + .HasColumnType("longtext") + .HasColumnName("locale"); + + b.Property("MuteRoleName") + .HasColumnType("longtext") + .HasColumnName("muterolename"); + + b.Property("NotifyStreamOffline") + .HasColumnType("tinyint(1)") + .HasColumnName("notifystreamoffline"); + + b.Property("PermissionRole") + .HasColumnType("longtext") + .HasColumnName("permissionrole"); + + b.Property("Prefix") + .HasColumnType("longtext") + .HasColumnName("prefix"); + + b.Property("SendBoostMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("sendboostmessage"); + + b.Property("SendChannelByeMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("sendchannelbyemessage"); + + b.Property("SendChannelGreetMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("sendchannelgreetmessage"); + + b.Property("SendDmGreetMessage") + .HasColumnType("tinyint(1)") + .HasColumnName("senddmgreetmessage"); + + b.Property("StickyRoles") + .HasColumnType("tinyint(1)") + .HasColumnName("stickyroles"); + + b.Property("TimeZoneId") + .HasColumnType("longtext") + .HasColumnName("timezoneid"); + + b.Property("VerboseErrors") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint(1)") + .HasDefaultValue(true) + .HasColumnName("verboseerrors"); + + b.Property("VerbosePermissions") + .HasColumnType("tinyint(1)") + .HasColumnName("verbosepermissions"); + + b.Property("WarnExpireAction") + .HasColumnType("int") + .HasColumnName("warnexpireaction"); + + b.Property("WarnExpireHours") + .HasColumnType("int") + .HasColumnName("warnexpirehours"); + + b.Property("WarningsInitialized") + .HasColumnType("tinyint(1)") + .HasColumnName("warningsinitialized"); + + b.HasKey("Id") + .HasName("pk_guildconfigs"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_guildconfigs_guildid"); + + b.HasIndex("WarnExpireHours") + .HasDatabaseName("ix_guildconfigs_warnexpirehours"); + + b.ToTable("guildconfigs", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ItemType") + .HasColumnType("int") + .HasColumnName("itemtype"); + + b.Property("LogItemId") + .HasColumnType("bigint unsigned") + .HasColumnName("logitemid"); + + b.Property("LogSettingId") + .HasColumnType("int") + .HasColumnName("logsettingid"); + + b.HasKey("Id") + .HasName("pk_ignoredlogchannels"); + + b.HasIndex("LogSettingId", "LogItemId", "ItemType") + .IsUnique() + .HasDatabaseName("ix_ignoredlogchannels_logsettingid_logitemid_itemtype"); + + b.ToTable("ignoredlogchannels", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ImageOnlyChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_imageonlychannels"); + + b.HasIndex("ChannelId") + .IsUnique() + .HasDatabaseName("ix_imageonlychannels_channelid"); + + b.ToTable("imageonlychannels", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelCreatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelcreatedid"); + + b.Property("ChannelDestroyedId") + .HasColumnType("bigint unsigned") + .HasColumnName("channeldestroyedid"); + + b.Property("ChannelUpdatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelupdatedid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("LogOtherId") + .HasColumnType("bigint unsigned") + .HasColumnName("logotherid"); + + b.Property("LogUserPresenceId") + .HasColumnType("bigint unsigned") + .HasColumnName("loguserpresenceid"); + + b.Property("LogVoicePresenceId") + .HasColumnType("bigint unsigned") + .HasColumnName("logvoicepresenceid"); + + b.Property("LogVoicePresenceTTSId") + .HasColumnType("bigint unsigned") + .HasColumnName("logvoicepresencettsid"); + + b.Property("LogWarnsId") + .HasColumnType("bigint unsigned") + .HasColumnName("logwarnsid"); + + b.Property("MessageDeletedId") + .HasColumnType("bigint unsigned") + .HasColumnName("messagedeletedid"); + + b.Property("MessageUpdatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageupdatedid"); + + b.Property("ThreadCreatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("threadcreatedid"); + + b.Property("ThreadDeletedId") + .HasColumnType("bigint unsigned") + .HasColumnName("threaddeletedid"); + + b.Property("UserBannedId") + .HasColumnType("bigint unsigned") + .HasColumnName("userbannedid"); + + b.Property("UserJoinedId") + .HasColumnType("bigint unsigned") + .HasColumnName("userjoinedid"); + + b.Property("UserLeftId") + .HasColumnType("bigint unsigned") + .HasColumnName("userleftid"); + + b.Property("UserMutedId") + .HasColumnType("bigint unsigned") + .HasColumnName("usermutedid"); + + b.Property("UserUnbannedId") + .HasColumnType("bigint unsigned") + .HasColumnName("userunbannedid"); + + b.Property("UserUpdatedId") + .HasColumnType("bigint unsigned") + .HasColumnName("userupdatedid"); + + b.HasKey("Id") + .HasName("pk_logsettings"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_logsettings_guildid"); + + b.ToTable("logsettings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MusicPlayerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AutoDisconnect") + .HasColumnType("tinyint(1)") + .HasColumnName("autodisconnect"); + + b.Property("AutoPlay") + .HasColumnType("tinyint(1)") + .HasColumnName("autoplay"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("MusicChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("musicchannelid"); + + b.Property("PlayerRepeat") + .HasColumnType("int") + .HasColumnName("playerrepeat"); + + b.Property("QualityPreset") + .HasColumnType("int") + .HasColumnName("qualitypreset"); + + b.Property("Volume") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(100) + .HasColumnName("volume"); + + b.HasKey("Id") + .HasName("pk_musicplayersettings"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_musicplayersettings_guildid"); + + b.ToTable("musicplayersettings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Author") + .HasColumnType("longtext") + .HasColumnName("author"); + + b.Property("AuthorId") + .HasColumnType("bigint unsigned") + .HasColumnName("authorid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("pk_musicplaylists"); + + b.ToTable("musicplaylists", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_muteduserid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_muteduserid_guildconfigid"); + + b.ToTable("muteduserid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.EllieExpression", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AllowTarget") + .HasColumnType("tinyint(1)") + .HasColumnName("allowtarget"); + + b.Property("AutoDeleteTrigger") + .HasColumnType("tinyint(1)") + .HasColumnName("autodeletetrigger"); + + b.Property("ContainsAnywhere") + .HasColumnType("tinyint(1)") + .HasColumnName("containsanywhere"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("DmResponse") + .HasColumnType("tinyint(1)") + .HasColumnName("dmresponse"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Reactions") + .HasColumnType("longtext") + .HasColumnName("reactions"); + + b.Property("Response") + .HasColumnType("longtext") + .HasColumnName("response"); + + b.Property("Trigger") + .HasColumnType("longtext") + .HasColumnName("trigger"); + + b.HasKey("Id") + .HasName("pk_expressions"); + + b.ToTable("expressions", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("UserId")); + + b.Property("AmountCents") + .HasColumnType("int") + .HasColumnName("amountcents"); + + b.Property("LastCharge") + .HasColumnType("datetime(6)") + .HasColumnName("lastcharge"); + + b.Property("UniquePlatformUserId") + .HasColumnType("varchar(255)") + .HasColumnName("uniqueplatformuserid"); + + b.Property("ValidThru") + .HasColumnType("datetime(6)") + .HasColumnName("validthru"); + + b.HasKey("UserId") + .HasName("pk_patrons"); + + b.HasIndex("UniquePlatformUserId") + .IsUnique() + .HasDatabaseName("ix_patrons_uniqueplatformuserid"); + + b.ToTable("patrons", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Index") + .HasColumnType("int") + .HasColumnName("index"); + + b.Property("IsCustomCommand") + .HasColumnType("tinyint(1)") + .HasColumnName("iscustomcommand"); + + b.Property("PrimaryTarget") + .HasColumnType("int") + .HasColumnName("primarytarget"); + + b.Property("PrimaryTargetId") + .HasColumnType("bigint unsigned") + .HasColumnName("primarytargetid"); + + b.Property("SecondaryTarget") + .HasColumnType("int") + .HasColumnName("secondarytarget"); + + b.Property("SecondaryTargetName") + .HasColumnType("longtext") + .HasColumnName("secondarytargetname"); + + b.Property("State") + .HasColumnType("tinyint(1)") + .HasColumnName("state"); + + b.HasKey("Id") + .HasName("pk_permissions"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_permissions_guildconfigid"); + + b.ToTable("permissions", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PlantedCurrency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("bigint") + .HasColumnName("amount"); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("MessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageid"); + + b.Property("Password") + .HasColumnType("longtext") + .HasColumnName("password"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_plantedcurrency"); + + b.HasIndex("ChannelId") + .HasDatabaseName("ix_plantedcurrency_channelid"); + + b.HasIndex("MessageId") + .IsUnique() + .HasDatabaseName("ix_plantedcurrency_messageid"); + + b.ToTable("plantedcurrency", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("MusicPlaylistId") + .HasColumnType("int") + .HasColumnName("musicplaylistid"); + + b.Property("Provider") + .HasColumnType("longtext") + .HasColumnName("provider"); + + b.Property("ProviderType") + .HasColumnType("int") + .HasColumnName("providertype"); + + b.Property("Query") + .HasColumnType("longtext") + .HasColumnName("query"); + + b.Property("Title") + .HasColumnType("longtext") + .HasColumnName("title"); + + b.Property("Uri") + .HasColumnType("longtext") + .HasColumnName("uri"); + + b.HasKey("Id") + .HasName("pk_playlistsong"); + + b.HasIndex("MusicPlaylistId") + .HasDatabaseName("ix_playlistsong_musicplaylistid"); + + b.ToTable("playlistsong", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AuthorId") + .HasColumnType("bigint unsigned") + .HasColumnName("authorid"); + + b.Property("AuthorName") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("authorname"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Keyword") + .IsRequired() + .HasColumnType("varchar(255)") + .HasColumnName("keyword"); + + b.Property("Text") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_quotes"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_quotes_guildid"); + + b.HasIndex("Keyword") + .HasDatabaseName("ix_quotes_keyword"); + + b.ToTable("quotes", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ReactionRoleV2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Emote") + .HasMaxLength(100) + .HasColumnType("varchar(100)") + .HasColumnName("emote"); + + b.Property("Group") + .HasColumnType("int") + .HasColumnName("group"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("LevelReq") + .HasColumnType("int") + .HasColumnName("levelreq"); + + b.Property("MessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageid"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_reactionroles"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_reactionroles_guildid"); + + b.HasIndex("MessageId", "Emote") + .IsUnique() + .HasDatabaseName("ix_reactionroles_messageid_emote"); + + b.ToTable("reactionroles", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("IsPrivate") + .HasColumnType("tinyint(1)") + .HasColumnName("isprivate"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("ServerId") + .HasColumnType("bigint unsigned") + .HasColumnName("serverid"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("When") + .HasColumnType("datetime(6)") + .HasColumnName("when"); + + b.HasKey("Id") + .HasName("pk_reminders"); + + b.HasIndex("When") + .HasDatabaseName("ix_reminders_when"); + + b.ToTable("reminders", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Repeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Interval") + .HasColumnType("time(6)") + .HasColumnName("interval"); + + b.Property("LastMessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("lastmessageid"); + + b.Property("Message") + .HasColumnType("longtext") + .HasColumnName("message"); + + b.Property("NoRedundant") + .HasColumnType("tinyint(1)") + .HasColumnName("noredundant"); + + b.Property("StartTimeOfDay") + .HasColumnType("time(6)") + .HasColumnName("starttimeofday"); + + b.HasKey("Id") + .HasName("pk_repeaters"); + + b.ToTable("repeaters", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AmountRewardedThisMonth") + .HasColumnType("bigint") + .HasColumnName("amountrewardedthismonth"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("LastReward") + .HasColumnType("datetime(6)") + .HasColumnName("lastreward"); + + b.Property("PlatformUserId") + .HasColumnType("varchar(255)") + .HasColumnName("platformuserid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_rewardedusers"); + + b.HasIndex("PlatformUserId") + .IsUnique() + .HasDatabaseName("ix_rewardedusers_platformuserid"); + + b.ToTable("rewardedusers", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.RotatingPlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Status") + .HasColumnType("longtext") + .HasColumnName("status"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_rotatingstatus"); + + b.ToTable("rotatingstatus", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Group") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0) + .HasColumnName("group"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("LevelRequirement") + .HasColumnType("int") + .HasColumnName("levelrequirement"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_selfassignableroles"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique() + .HasDatabaseName("ix_selfassignableroles_guildid_roleid"); + + b.ToTable("selfassignableroles", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AuthorId") + .HasColumnType("bigint unsigned") + .HasColumnName("authorid"); + + b.Property("Command") + .HasColumnType("longtext") + .HasColumnName("command"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Index") + .HasColumnType("int") + .HasColumnName("index"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("Price") + .HasColumnType("int") + .HasColumnName("price"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("RoleName") + .HasColumnType("longtext") + .HasColumnName("rolename"); + + b.Property("RoleRequirement") + .HasColumnType("bigint unsigned") + .HasColumnName("rolerequirement"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_shopentry"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_shopentry_guildconfigid"); + + b.ToTable("shopentry", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ShopEntryId") + .HasColumnType("int") + .HasColumnName("shopentryid"); + + b.Property("Text") + .HasColumnType("longtext") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_shopentryitem"); + + b.HasIndex("ShopEntryId") + .HasDatabaseName("ix_shopentryitem_shopentryid"); + + b.ToTable("shopentryitem", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_slowmodeignoredrole"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_slowmodeignoredrole_guildconfigid"); + + b.ToTable("slowmodeignoredrole", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_slowmodeignoreduser"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_slowmodeignoreduser_guildconfigid"); + + b.ToTable("slowmodeignoreduser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StickyRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("RoleIds") + .HasColumnType("longtext") + .HasColumnName("roleids"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_stickyroles"); + + b.HasIndex("GuildId", "UserId") + .IsUnique() + .HasDatabaseName("ix_stickyroles_guildid_userid"); + + b.ToTable("stickyroles", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamOnlineMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("MessageId") + .HasColumnType("bigint unsigned") + .HasColumnName("messageid"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("Type") + .HasColumnType("int") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_streamonlinemessages"); + + b.ToTable("streamonlinemessages", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("int") + .HasColumnName("streamrolesettingsid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("longtext") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_streamroleblacklisteduser"); + + b.HasIndex("StreamRoleSettingsId") + .HasDatabaseName("ix_streamroleblacklisteduser_streamrolesettingsid"); + + b.ToTable("streamroleblacklisteduser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AddRoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("addroleid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)") + .HasColumnName("enabled"); + + b.Property("FromRoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("fromroleid"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Keyword") + .HasColumnType("longtext") + .HasColumnName("keyword"); + + b.HasKey("Id") + .HasName("pk_streamrolesettings"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_streamrolesettings_guildconfigid"); + + b.ToTable("streamrolesettings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("int") + .HasColumnName("streamrolesettingsid"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("longtext") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_streamrolewhitelisteduser"); + + b.HasIndex("StreamRoleSettingsId") + .HasDatabaseName("ix_streamrolewhitelisteduser_streamrolesettingsid"); + + b.ToTable("streamrolewhitelisteduser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ArchiveId") + .HasColumnType("int") + .HasColumnName("archiveid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("IsDone") + .HasColumnType("tinyint(1)") + .HasColumnName("isdone"); + + b.Property("Todo") + .HasColumnType("longtext") + .HasColumnName("todo"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_todos"); + + b.HasIndex("ArchiveId") + .HasDatabaseName("ix_todos_archiveid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_todos_userid"); + + b.ToTable("todos", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnbanTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("UnbanAt") + .HasColumnType("datetime(6)") + .HasColumnName("unbanat"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unbantimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unbantimer_guildconfigid"); + + b.ToTable("unbantimer", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("UnmuteAt") + .HasColumnType("datetime(6)") + .HasColumnName("unmuteat"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unmutetimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unmutetimer_guildconfigid"); + + b.ToTable("unmutetimer", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnroleTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("UnbanAt") + .HasColumnType("datetime(6)") + .HasColumnName("unbanat"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unroletimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unroletimer_guildconfigid"); + + b.ToTable("unroletimer", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UserXpStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AwardedXp") + .HasColumnType("bigint") + .HasColumnName("awardedxp"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("NotifyOnLevelUp") + .HasColumnType("int") + .HasColumnName("notifyonlevelup"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Xp") + .HasColumnType("bigint") + .HasColumnName("xp"); + + b.HasKey("Id") + .HasName("pk_userxpstats"); + + b.HasIndex("AwardedXp") + .HasDatabaseName("ix_userxpstats_awardedxp"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_userxpstats_guildid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_userxpstats_userid"); + + b.HasIndex("Xp") + .HasDatabaseName("ix_userxpstats_xp"); + + b.HasIndex("UserId", "GuildId") + .IsUnique() + .HasDatabaseName("ix_userxpstats_userid_guildid"); + + b.ToTable("userxpstats", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("VoiceChannelId") + .HasColumnType("bigint unsigned") + .HasColumnName("voicechannelid"); + + b.HasKey("Id") + .HasName("pk_vcroleinfo"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_vcroleinfo_guildconfigid"); + + b.ToTable("vcroleinfo", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AffinityId") + .HasColumnType("int") + .HasColumnName("affinityid"); + + b.Property("ClaimerId") + .HasColumnType("int") + .HasColumnName("claimerid"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Price") + .HasColumnType("bigint") + .HasColumnName("price"); + + b.Property("WaifuId") + .HasColumnType("int") + .HasColumnName("waifuid"); + + b.HasKey("Id") + .HasName("pk_waifuinfo"); + + b.HasIndex("AffinityId") + .HasDatabaseName("ix_waifuinfo_affinityid"); + + b.HasIndex("ClaimerId") + .HasDatabaseName("ix_waifuinfo_claimerid"); + + b.HasIndex("Price") + .HasDatabaseName("ix_waifuinfo_price"); + + b.HasIndex("WaifuId") + .IsUnique() + .HasDatabaseName("ix_waifuinfo_waifuid"); + + b.ToTable("waifuinfo", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("ItemEmoji") + .HasColumnType("longtext") + .HasColumnName("itememoji"); + + b.Property("Name") + .HasColumnType("longtext") + .HasColumnName("name"); + + b.Property("WaifuInfoId") + .HasColumnType("int") + .HasColumnName("waifuinfoid"); + + b.HasKey("Id") + .HasName("pk_waifuitem"); + + b.HasIndex("WaifuInfoId") + .HasDatabaseName("ix_waifuitem_waifuinfoid"); + + b.ToTable("waifuitem", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("NewId") + .HasColumnType("int") + .HasColumnName("newid"); + + b.Property("OldId") + .HasColumnType("int") + .HasColumnName("oldid"); + + b.Property("UpdateType") + .HasColumnType("int") + .HasColumnName("updatetype"); + + b.Property("UserId") + .HasColumnType("int") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_waifuupdates"); + + b.HasIndex("NewId") + .HasDatabaseName("ix_waifuupdates_newid"); + + b.HasIndex("OldId") + .HasDatabaseName("ix_waifuupdates_oldid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_waifuupdates_userid"); + + b.ToTable("waifuupdates", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Forgiven") + .HasColumnType("tinyint(1)") + .HasColumnName("forgiven"); + + b.Property("ForgivenBy") + .HasColumnType("longtext") + .HasColumnName("forgivenby"); + + b.Property("GuildId") + .HasColumnType("bigint unsigned") + .HasColumnName("guildid"); + + b.Property("Moderator") + .HasColumnType("longtext") + .HasColumnName("moderator"); + + b.Property("Reason") + .HasColumnType("longtext") + .HasColumnName("reason"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.Property("Weight") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(1L) + .HasColumnName("weight"); + + b.HasKey("Id") + .HasName("pk_warnings"); + + b.HasIndex("DateAdded") + .HasDatabaseName("ix_warnings_dateadded"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_warnings_guildid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_warnings_userid"); + + b.ToTable("warnings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("int") + .HasColumnName("count"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("Punishment") + .HasColumnType("int") + .HasColumnName("punishment"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("Time") + .HasColumnType("int") + .HasColumnName("time"); + + b.HasKey("Id") + .HasName("pk_warningpunishment"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_warningpunishment_guildconfigid"); + + b.ToTable("warningpunishment", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpCurrencyReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("int") + .HasColumnName("amount"); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Level") + .HasColumnType("int") + .HasColumnName("level"); + + b.Property("XpSettingsId") + .HasColumnType("int") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_xpcurrencyreward"); + + b.HasIndex("XpSettingsId") + .HasDatabaseName("ix_xpcurrencyreward_xpsettingsid"); + + b.ToTable("xpcurrencyreward", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpRoleReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("Level") + .HasColumnType("int") + .HasColumnName("level"); + + b.Property("Remove") + .HasColumnType("tinyint(1)") + .HasColumnName("remove"); + + b.Property("RoleId") + .HasColumnType("bigint unsigned") + .HasColumnName("roleid"); + + b.Property("XpSettingsId") + .HasColumnType("int") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_xprolereward"); + + b.HasIndex("XpSettingsId", "Level") + .IsUnique() + .HasDatabaseName("ix_xprolereward_xpsettingsid_level"); + + b.ToTable("xprolereward", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("int") + .HasColumnName("guildconfigid"); + + b.Property("ServerExcluded") + .HasColumnType("tinyint(1)") + .HasColumnName("serverexcluded"); + + b.HasKey("Id") + .HasName("pk_xpsettings"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_xpsettings_guildconfigid"); + + b.ToTable("xpsettings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpShopOwnedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasColumnName("id"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("datetime(6)") + .HasColumnName("dateadded"); + + b.Property("IsUsing") + .HasColumnType("tinyint(1)") + .HasColumnName("isusing"); + + b.Property("ItemKey") + .IsRequired() + .HasColumnType("varchar(255)") + .HasColumnName("itemkey"); + + b.Property("ItemType") + .HasColumnType("int") + .HasColumnName("itemtype"); + + b.Property("UserId") + .HasColumnType("bigint unsigned") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_xpshopowneditem"); + + b.HasIndex("UserId", "ItemType", "ItemKey") + .IsUnique() + .HasDatabaseName("ix_xpshopowneditem_userid_itemtype_itemkey"); + + b.ToTable("xpshopowneditem", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiAltSetting", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithOne("AntiAltSetting") + .HasForeignKey("EllieBot.Db.Models.AntiAltSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antialtsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiRaidSetting", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithOne("AntiRaidSetting") + .HasForeignKey("EllieBot.Db.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antiraidsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamIgnore", b => + { + b.HasOne("EllieBot.Db.Models.AntiSpamSetting", null) + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_antispamignore_antispamsetting_antispamsettingid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamSetting", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithOne("AntiSpamSetting") + .HasForeignKey("EllieBot.Db.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antispamsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateUser", b => + { + b.HasOne("EllieBot.Db.Models.AutoTranslateChannel", "Channel") + .WithMany("Users") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_autotranslateusers_autotranslatechannels_channelid"); + + b.Navigation("Channel"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubApplicants", b => + { + b.HasOne("EllieBot.Db.Models.ClubInfo", "Club") + .WithMany("Applicants") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubapplicants_clubs_clubid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubapplicants_discorduser_userid"); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubBans", b => + { + b.HasOne("EllieBot.Db.Models.ClubInfo", "Club") + .WithMany("Bans") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubbans_clubs_clubid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubbans_discorduser_userid"); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubInfo", b => + { + b.HasOne("EllieBot.Db.Models.DiscordUser", "Owner") + .WithOne() + .HasForeignKey("EllieBot.Db.Models.ClubInfo", "OwnerId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_clubs_discorduser_ownerid"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandAlias", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_commandalias_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandCooldown", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_commandcooldown_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("DelMsgOnCmdChannels") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_delmsgoncmdchannel_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DiscordUser", b => + { + b.HasOne("EllieBot.Db.Models.ClubInfo", "Club") + .WithMany("Members") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.NoAction) + .HasConstraintName("fk_discorduser_clubs_clubid"); + + b.Navigation("Club"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b => + { + b.HasOne("EllieBot.Db.Models.XpSettings", "XpSettings") + .WithMany("ExclusionList") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_excludeditem_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("FeedSubs") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_feedsub_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterchannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterLinksChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilterLinksChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterlinkschannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterWordsChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterwordschannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilteredWord", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filteredword_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FollowedStream", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_followedstream_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GCChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_gcchannelid_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayUser", b => + { + b.HasOne("EllieBot.Db.Models.GiveawayModel", null) + .WithMany("Participants") + .HasForeignKey("GiveawayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_giveawayuser_giveawaymodel_giveawayid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GroupName", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("SelfAssignableRoleGroupNames") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_groupname_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b => + { + b.HasOne("EllieBot.Db.Models.LogSetting", "LogSetting") + .WithMany("LogIgnores") + .HasForeignKey("LogSettingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_ignoredlogchannels_logsettings_logsettingid"); + + b.Navigation("LogSetting"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MutedUserId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_muteduserid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Permissionv2", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("Permissions") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_permissions_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PlaylistSong", b => + { + b.HasOne("EllieBot.Db.Models.MusicPlaylist", null) + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_playlistsong_musicplaylists_musicplaylistid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_shopentry_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntryItem", b => + { + b.HasOne("EllieBot.Db.Models.ShopEntry", null) + .WithMany("Items") + .HasForeignKey("ShopEntryId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_shopentryitem_shopentry_shopentryid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_slowmodeignoredrole_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_slowmodeignoreduser_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.HasOne("EllieBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Blacklist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamroleblacklisteduser_streamrolesettings_streamrolesetti~"); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleSettings", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("StreamRole") + .HasForeignKey("EllieBot.Db.Models.StreamRoleSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamrolesettings_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.HasOne("EllieBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Whitelist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamrolewhitelisteduser_streamrolesettings_streamrolesetti~"); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b => + { + b.HasOne("EllieBot.Db.Models.ArchivedTodoListModel", null) + .WithMany("Items") + .HasForeignKey("ArchiveId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_todos_todosarchive_archiveid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnbanTimer", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("UnbanTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unbantimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnmuteTimer", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unmutetimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnroleTimer", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("UnroleTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unroletimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.VcRoleInfo", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_vcroleinfo_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuInfo", b => + { + b.HasOne("EllieBot.Db.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId") + .HasConstraintName("fk_waifuinfo_discorduser_affinityid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId") + .HasConstraintName("fk_waifuinfo_discorduser_claimerid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("EllieBot.Db.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_waifuinfo_discorduser_waifuid"); + + b.Navigation("Affinity"); + + b.Navigation("Claimer"); + + b.Navigation("Waifu"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuItem", b => + { + b.HasOne("EllieBot.Db.Models.WaifuInfo", "WaifuInfo") + .WithMany("Items") + .HasForeignKey("WaifuInfoId") + .HasConstraintName("fk_waifuitem_waifuinfo_waifuinfoid"); + + b.Navigation("WaifuInfo"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuUpdate", b => + { + b.HasOne("EllieBot.Db.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId") + .HasConstraintName("fk_waifuupdates_discorduser_newid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId") + .HasConstraintName("fk_waifuupdates_discorduser_oldid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_waifuupdates_discorduser_userid"); + + b.Navigation("New"); + + b.Navigation("Old"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WarningPunishment", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_warningpunishment_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpCurrencyReward", b => + { + b.HasOne("EllieBot.Db.Models.XpSettings", "XpSettings") + .WithMany("CurrencyRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xpcurrencyreward_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpRoleReward", b => + { + b.HasOne("EllieBot.Db.Models.XpSettings", "XpSettings") + .WithMany("RoleRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xprolereward_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpSettings", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("XpSettings") + .HasForeignKey("EllieBot.Db.Models.XpSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xpsettings_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamSetting", b => + { + b.Navigation("IgnoredChannels"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ArchivedTodoListModel", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateChannel", b => + { + b.Navigation("Users"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubInfo", b => + { + b.Navigation("Applicants"); + + b.Navigation("Bans"); + + b.Navigation("Members"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayModel", b => + { + b.Navigation("Participants"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b => + { + b.Navigation("AntiAltSetting"); + + b.Navigation("AntiRaidSetting"); + + b.Navigation("AntiSpamSetting"); + + b.Navigation("CommandAliases"); + + b.Navigation("CommandCooldowns"); + + b.Navigation("DelMsgOnCmdChannels"); + + b.Navigation("FeedSubs"); + + b.Navigation("FilterInvitesChannelIds"); + + b.Navigation("FilterLinksChannelIds"); + + b.Navigation("FilterWordsChannelIds"); + + b.Navigation("FilteredWords"); + + b.Navigation("FollowedStreams"); + + b.Navigation("GenerateCurrencyChannelIds"); + + b.Navigation("MutedUsers"); + + b.Navigation("Permissions"); + + b.Navigation("SelfAssignableRoleGroupNames"); + + b.Navigation("ShopEntries"); + + b.Navigation("SlowmodeIgnoredRoles"); + + b.Navigation("SlowmodeIgnoredUsers"); + + b.Navigation("StreamRole"); + + b.Navigation("UnbanTimer"); + + b.Navigation("UnmuteTimers"); + + b.Navigation("UnroleTimer"); + + b.Navigation("VcRoleInfos"); + + b.Navigation("WarnPunishments"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.LogSetting", b => + { + b.Navigation("LogIgnores"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MusicPlaylist", b => + { + b.Navigation("Songs"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleSettings", b => + { + b.Navigation("Blacklist"); + + b.Navigation("Whitelist"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuInfo", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpSettings", b => + { + b.Navigation("CurrencyRewards"); + + b.Navigation("ExclusionList"); + + b.Navigation("RoleRewards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/EllieBot/Migrations/Mysql/20240611180516_remove-patron-limits.cs b/src/EllieBot/Migrations/Mysql/20240611180516_remove-patron-limits.cs new file mode 100644 index 0000000..745636a --- /dev/null +++ b/src/EllieBot/Migrations/Mysql/20240611180516_remove-patron-limits.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace EllieBot.Migrations.Mysql +{ + /// + public partial class removepatronlimits : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "patronquotas"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "patronquotas", + columns: table => new + { + userid = table.Column(type: "bigint unsigned", nullable: false), + featuretype = table.Column(type: "int", nullable: false), + feature = table.Column(type: "varchar(255)", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + dailycount = table.Column(type: "int unsigned", nullable: false), + hourlycount = table.Column(type: "int unsigned", nullable: false), + monthlycount = table.Column(type: "int unsigned", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_patronquotas", x => new { x.userid, x.featuretype, x.feature }); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "ix_patronquotas_userid", + table: "patronquotas", + column: "userid"); + } + } +} diff --git a/src/EllieBot/Migrations/Mysql/MysqlContextModelSnapshot.cs b/src/EllieBot/Migrations/Mysql/MysqlContextModelSnapshot.cs index 9a6e160..7399a1d 100644 --- a/src/EllieBot/Migrations/Mysql/MysqlContextModelSnapshot.cs +++ b/src/EllieBot/Migrations/Mysql/MysqlContextModelSnapshot.cs @@ -1718,41 +1718,6 @@ namespace EllieBot.Migrations.Mysql b.ToTable("expressions", (string)null); }); - modelBuilder.Entity("EllieBot.Db.Models.PatronQuota", b => - { - b.Property("UserId") - .HasColumnType("bigint unsigned") - .HasColumnName("userid"); - - b.Property("FeatureType") - .HasColumnType("int") - .HasColumnName("featuretype"); - - b.Property("Feature") - .HasColumnType("varchar(255)") - .HasColumnName("feature"); - - b.Property("DailyCount") - .HasColumnType("int unsigned") - .HasColumnName("dailycount"); - - b.Property("HourlyCount") - .HasColumnType("int unsigned") - .HasColumnName("hourlycount"); - - b.Property("MonthlyCount") - .HasColumnType("int unsigned") - .HasColumnName("monthlycount"); - - b.HasKey("UserId", "FeatureType", "Feature") - .HasName("pk_patronquotas"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_patronquotas_userid"); - - b.ToTable("patronquotas", (string)null); - }); - modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b => { b.Property("UserId") diff --git a/src/EllieBot/Migrations/PostgreSql/20220428044547_stondel.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220428044547_stondel.Designer.cs index dd928e9..296f158 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220428044547_stondel.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220428044547_stondel.Designer.cs @@ -1490,7 +1490,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220429044808_bank.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220429044808_bank.Designer.cs index b4135e5..2368670 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220429044808_bank.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220429044808_bank.Designer.cs @@ -1521,7 +1521,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220504162457_new-rero.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220504162457_new-rero.Designer.cs index ab78250..24c7cdb 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220504162457_new-rero.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220504162457_new-rero.Designer.cs @@ -1521,7 +1521,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220614071421_patronage-system.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220614071421_patronage-system.Designer.cs index 0684976..7f9e828 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220614071421_patronage-system.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220614071421_patronage-system.Designer.cs @@ -1591,7 +1591,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220623090729_stondel-db-cache.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220623090729_stondel-db-cache.Designer.cs index f452d57..b8ec8ea 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220623090729_stondel-db-cache.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220623090729_stondel-db-cache.Designer.cs @@ -1626,7 +1626,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220703194412_logwarns.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220703194412_logwarns.Designer.cs index 964d6bd..2c19566 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220703194412_logwarns.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220703194412_logwarns.Designer.cs @@ -1630,7 +1630,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220725155941_xpitemshop.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220725155941_xpitemshop.Designer.cs index 1c2bb86..0ad20f8 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220725155941_xpitemshop.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220725155941_xpitemshop.Designer.cs @@ -1670,7 +1670,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220727033944_linkonly-channels.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220727033944_linkonly-channels.Designer.cs index 8a9bb37..a6d9203 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220727033944_linkonly-channels.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220727033944_linkonly-channels.Designer.cs @@ -1674,7 +1674,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220808142559_remove-obsolete-xp-columns.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220808142559_remove-obsolete-xp-columns.Designer.cs index e315f4d..60ef9a6 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220808142559_remove-obsolete-xp-columns.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220808142559_remove-obsolete-xp-columns.Designer.cs @@ -1662,7 +1662,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220831142735_banprune.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220831142735_banprune.Designer.cs index ce4b1a7..812f165 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220831142735_banprune.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220831142735_banprune.Designer.cs @@ -1666,7 +1666,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220913192529_shop-role-req.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220913192529_shop-role-req.Designer.cs index 04644ac..564fb8d 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220913192529_shop-role-req.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220913192529_shop-role-req.Designer.cs @@ -1666,7 +1666,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20220916194523_autopub.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20220916194523_autopub.Designer.cs index 41eb2c9..b372469 100644 --- a/src/EllieBot/Migrations/PostgreSql/20220916194523_autopub.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20220916194523_autopub.Designer.cs @@ -1697,7 +1697,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20221003175752_gambling-stats.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20221003175752_gambling-stats.Designer.cs index 3740b60..78021a9 100644 --- a/src/EllieBot/Migrations/PostgreSql/20221003175752_gambling-stats.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20221003175752_gambling-stats.Designer.cs @@ -1732,7 +1732,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20221021192807_toggle-global-expressions.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20221021192807_toggle-global-expressions.Designer.cs index 44486f6..813ffd1 100644 --- a/src/EllieBot/Migrations/PostgreSql/20221021192807_toggle-global-expressions.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20221021192807_toggle-global-expressions.Designer.cs @@ -1736,7 +1736,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20221118195200_log-thread.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20221118195200_log-thread.Designer.cs index 07a42f2..51c8a35 100644 --- a/src/EllieBot/Migrations/PostgreSql/20221118195200_log-thread.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20221118195200_log-thread.Designer.cs @@ -1744,7 +1744,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20221122204423_feed-text.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20221122204423_feed-text.Designer.cs index 24bfefc..a0a8272 100644 --- a/src/EllieBot/Migrations/PostgreSql/20221122204423_feed-text.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20221122204423_feed-text.Designer.cs @@ -1748,7 +1748,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Services.Database.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Services.Database.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20240502233202_v5.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20240502233202_v5.Designer.cs index abbe420..2546c39 100644 --- a/src/EllieBot/Migrations/PostgreSql/20240502233202_v5.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20240502233202_v5.Designer.cs @@ -1699,7 +1699,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Db.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Db.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20240518221432_guidlconfig-cleanup.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20240518221432_guidlconfig-cleanup.Designer.cs index 2227f4a..fde53c6 100644 --- a/src/EllieBot/Migrations/PostgreSql/20240518221432_guidlconfig-cleanup.Designer.cs +++ b/src/EllieBot/Migrations/PostgreSql/20240518221432_guidlconfig-cleanup.Designer.cs @@ -1669,7 +1669,7 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("muteduserid", (string)null); }); - modelBuilder.Entity("EllieBot.Db.Models.NadekoExpression", b => + modelBuilder.Entity("EllieBot.Db.Models.EllieExpression", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/EllieBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs b/src/EllieBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs new file mode 100644 index 0000000..18a4651 --- /dev/null +++ b/src/EllieBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.Designer.cs @@ -0,0 +1,3781 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using EllieBot.Db; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace EllieBot.Migrations.PostgreSql +{ + [DbContext(typeof(PostgreSqlContext))] + [Migration("20240611180506_remove-patron-limits")] + partial class removepatronlimits + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("EllieBot.Db.Models.AntiAltSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("integer") + .HasColumnName("action"); + + b.Property("ActionDurationMinutes") + .HasColumnType("integer") + .HasColumnName("actiondurationminutes"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("MinAge") + .HasColumnType("interval") + .HasColumnName("minage"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_antialtsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antialtsetting_guildconfigid"); + + b.ToTable("antialtsetting", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("integer") + .HasColumnName("action"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("PunishDuration") + .HasColumnType("integer") + .HasColumnName("punishduration"); + + b.Property("Seconds") + .HasColumnType("integer") + .HasColumnName("seconds"); + + b.Property("UserThreshold") + .HasColumnType("integer") + .HasColumnName("userthreshold"); + + b.HasKey("Id") + .HasName("pk_antiraidsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antiraidsetting_guildconfigid"); + + b.ToTable("antiraidsetting", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AntiSpamSettingId") + .HasColumnType("integer") + .HasColumnName("antispamsettingid"); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.HasKey("Id") + .HasName("pk_antispamignore"); + + b.HasIndex("AntiSpamSettingId") + .HasDatabaseName("ix_antispamignore_antispamsettingid"); + + b.ToTable("antispamignore", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Action") + .HasColumnType("integer") + .HasColumnName("action"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("MessageThreshold") + .HasColumnType("integer") + .HasColumnName("messagethreshold"); + + b.Property("MuteTime") + .HasColumnType("integer") + .HasColumnName("mutetime"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_antispamsetting"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_antispamsetting_guildconfigid"); + + b.ToTable("antispamsetting", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ArchivedTodoListModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_todosarchive"); + + b.ToTable("todosarchive", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("ChannelName") + .HasColumnType("text") + .HasColumnName("channelname"); + + b.Property("CommandText") + .HasColumnType("text") + .HasColumnName("commandtext"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("GuildName") + .HasColumnType("text") + .HasColumnName("guildname"); + + b.Property("Interval") + .HasColumnType("integer") + .HasColumnName("interval"); + + b.Property("VoiceChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("voicechannelid"); + + b.Property("VoiceChannelName") + .HasColumnType("text") + .HasColumnName("voicechannelname"); + + b.HasKey("Id") + .HasName("pk_autocommands"); + + b.ToTable("autocommands", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoPublishChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.HasKey("Id") + .HasName("pk_autopublishchannel"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_autopublishchannel_guildid"); + + b.ToTable("autopublishchannel", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AutoDelete") + .HasColumnType("boolean") + .HasColumnName("autodelete"); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.HasKey("Id") + .HasName("pk_autotranslatechannels"); + + b.HasIndex("ChannelId") + .IsUnique() + .HasDatabaseName("ix_autotranslatechannels_channelid"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_autotranslatechannels_guildid"); + + b.ToTable("autotranslatechannels", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("integer") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Source") + .HasColumnType("text") + .HasColumnName("source"); + + b.Property("Target") + .HasColumnType("text") + .HasColumnName("target"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_autotranslateusers"); + + b.HasAlternateKey("ChannelId", "UserId") + .HasName("ak_autotranslateusers_channelid_userid"); + + b.ToTable("autotranslateusers", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.BanTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("PruneDays") + .HasColumnType("integer") + .HasColumnName("prunedays"); + + b.Property("Text") + .HasColumnType("text") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_bantemplates"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_bantemplates_guildid"); + + b.ToTable("bantemplates", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.BankUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Balance") + .HasColumnType("bigint") + .HasColumnName("balance"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_bankusers"); + + b.HasIndex("UserId") + .IsUnique() + .HasDatabaseName("ix_bankusers_userid"); + + b.ToTable("bankusers", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.BlacklistEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ItemId") + .HasColumnType("numeric(20,0)") + .HasColumnName("itemid"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_blacklist"); + + b.ToTable("blacklist", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubApplicants", b => + { + b.Property("ClubId") + .HasColumnType("integer") + .HasColumnName("clubid"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("userid"); + + b.HasKey("ClubId", "UserId") + .HasName("pk_clubapplicants"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_clubapplicants_userid"); + + b.ToTable("clubapplicants", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubBans", b => + { + b.Property("ClubId") + .HasColumnType("integer") + .HasColumnName("clubid"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("userid"); + + b.HasKey("ClubId", "UserId") + .HasName("pk_clubbans"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_clubbans_userid"); + + b.ToTable("clubbans", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("ImageUrl") + .HasColumnType("text") + .HasColumnName("imageurl"); + + b.Property("Name") + .HasMaxLength(20) + .HasColumnType("character varying(20)") + .HasColumnName("name"); + + b.Property("OwnerId") + .HasColumnType("integer") + .HasColumnName("ownerid"); + + b.Property("Xp") + .HasColumnType("integer") + .HasColumnName("xp"); + + b.HasKey("Id") + .HasName("pk_clubs"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_clubs_name"); + + b.HasIndex("OwnerId") + .IsUnique() + .HasDatabaseName("ix_clubs_ownerid"); + + b.ToTable("clubs", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Mapping") + .HasColumnType("text") + .HasColumnName("mapping"); + + b.Property("Trigger") + .HasColumnType("text") + .HasColumnName("trigger"); + + b.HasKey("Id") + .HasName("pk_commandalias"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_commandalias_guildconfigid"); + + b.ToTable("commandalias", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CommandName") + .HasColumnType("text") + .HasColumnName("commandname"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Seconds") + .HasColumnType("integer") + .HasColumnName("seconds"); + + b.HasKey("Id") + .HasName("pk_commandcooldown"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_commandcooldown_guildconfigid"); + + b.ToTable("commandcooldown", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("bigint") + .HasColumnName("amount"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Extra") + .IsRequired() + .HasColumnType("text") + .HasColumnName("extra"); + + b.Property("Note") + .HasColumnType("text") + .HasColumnName("note"); + + b.Property("OtherId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)") + .HasColumnName("otherid") + .HasDefaultValueSql("NULL"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text") + .HasColumnName("type"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_currencytransactions"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_currencytransactions_userid"); + + b.ToTable("currencytransactions", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("State") + .HasColumnType("boolean") + .HasColumnName("state"); + + b.HasKey("Id") + .HasName("pk_delmsgoncmdchannel"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_delmsgoncmdchannel_guildconfigid"); + + b.ToTable("delmsgoncmdchannel", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DiscordPermOverride", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Command") + .HasColumnType("text") + .HasColumnName("command"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Perm") + .HasColumnType("numeric(20,0)") + .HasColumnName("perm"); + + b.HasKey("Id") + .HasName("pk_discordpermoverrides"); + + b.HasIndex("GuildId", "Command") + .IsUnique() + .HasDatabaseName("ix_discordpermoverrides_guildid_command"); + + b.ToTable("discordpermoverrides", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AvatarId") + .HasColumnType("text") + .HasColumnName("avatarid"); + + b.Property("ClubId") + .HasColumnType("integer") + .HasColumnName("clubid"); + + b.Property("CurrencyAmount") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L) + .HasColumnName("currencyamount"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Discriminator") + .HasColumnType("text") + .HasColumnName("discriminator"); + + b.Property("IsClubAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("isclubadmin"); + + b.Property("NotifyOnLevelUp") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("notifyonlevelup"); + + b.Property("TotalXp") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(0L) + .HasColumnName("totalxp"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_discorduser"); + + b.HasAlternateKey("UserId") + .HasName("ak_discorduser_userid"); + + b.HasIndex("ClubId") + .HasDatabaseName("ix_discorduser_clubid"); + + b.HasIndex("CurrencyAmount") + .HasDatabaseName("ix_discorduser_currencyamount"); + + b.HasIndex("TotalXp") + .HasDatabaseName("ix_discorduser_totalxp"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_discorduser_userid"); + + b.ToTable("discorduser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ItemId") + .HasColumnType("numeric(20,0)") + .HasColumnName("itemid"); + + b.Property("ItemType") + .HasColumnType("integer") + .HasColumnName("itemtype"); + + b.Property("XpSettingsId") + .HasColumnType("integer") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_excludeditem"); + + b.HasIndex("XpSettingsId") + .HasDatabaseName("ix_excludeditem_xpsettingsid"); + + b.ToTable("excludeditem", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text") + .HasColumnName("url"); + + b.HasKey("Id") + .HasName("pk_feedsub"); + + b.HasAlternateKey("GuildConfigId", "Url") + .HasName("ak_feedsub_guildconfigid_url"); + + b.ToTable("feedsub", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterchannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterchannelid_guildconfigid"); + + b.ToTable("filterchannelid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterLinksChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterlinkschannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterlinkschannelid_guildconfigid"); + + b.ToTable("filterlinkschannelid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterWordsChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_filterwordschannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filterwordschannelid_guildconfigid"); + + b.ToTable("filterwordschannelid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Word") + .HasColumnType("text") + .HasColumnName("word"); + + b.HasKey("Id") + .HasName("pk_filteredword"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_filteredword_guildconfigid"); + + b.ToTable("filteredword", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("Username") + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_followedstream"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_followedstream_guildconfigid"); + + b.ToTable("followedstream", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.HasKey("Id") + .HasName("pk_gcchannelid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_gcchannelid_guildconfigid"); + + b.ToTable("gcchannelid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GamblingStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Bet") + .HasColumnType("numeric") + .HasColumnName("bet"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Feature") + .HasColumnType("text") + .HasColumnName("feature"); + + b.Property("PaidOut") + .HasColumnType("numeric") + .HasColumnName("paidout"); + + b.HasKey("Id") + .HasName("pk_gamblingstats"); + + b.HasIndex("Feature") + .IsUnique() + .HasDatabaseName("ix_gamblingstats_feature"); + + b.ToTable("gamblingstats", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("EndsAt") + .HasColumnType("timestamp without time zone") + .HasColumnName("endsat"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("MessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageid"); + + b.HasKey("Id") + .HasName("pk_giveawaymodel"); + + b.ToTable("giveawaymodel", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("GiveawayId") + .HasColumnType("integer") + .HasColumnName("giveawayid"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_giveawayuser"); + + b.HasIndex("GiveawayId", "UserId") + .IsUnique() + .HasDatabaseName("ix_giveawayuser_giveawayid_userid"); + + b.ToTable("giveawayuser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GroupName", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Number") + .HasColumnType("integer") + .HasColumnName("number"); + + b.HasKey("Id") + .HasName("pk_groupname"); + + b.HasIndex("GuildConfigId", "Number") + .IsUnique() + .HasDatabaseName("ix_groupname_guildconfigid_number"); + + b.ToTable("groupname", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AutoAssignRoleIds") + .HasColumnType("text") + .HasColumnName("autoassignroleids"); + + b.Property("AutoDeleteByeMessagesTimer") + .HasColumnType("integer") + .HasColumnName("autodeletebyemessagestimer"); + + b.Property("AutoDeleteGreetMessagesTimer") + .HasColumnType("integer") + .HasColumnName("autodeletegreetmessagestimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages") + .HasColumnType("boolean") + .HasColumnName("autodeleteselfassignedrolemessages"); + + b.Property("BoostMessage") + .HasColumnType("text") + .HasColumnName("boostmessage"); + + b.Property("BoostMessageChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("boostmessagechannelid"); + + b.Property("BoostMessageDeleteAfter") + .HasColumnType("integer") + .HasColumnName("boostmessagedeleteafter"); + + b.Property("ByeMessageChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("byemessagechannelid"); + + b.Property("ChannelByeMessageText") + .HasColumnType("text") + .HasColumnName("channelbyemessagetext"); + + b.Property("ChannelGreetMessageText") + .HasColumnType("text") + .HasColumnName("channelgreetmessagetext"); + + b.Property("CleverbotEnabled") + .HasColumnType("boolean") + .HasColumnName("cleverbotenabled"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("DeleteMessageOnCommand") + .HasColumnType("boolean") + .HasColumnName("deletemessageoncommand"); + + b.Property("DeleteStreamOnlineMessage") + .HasColumnType("boolean") + .HasColumnName("deletestreamonlinemessage"); + + b.Property("DisableGlobalExpressions") + .HasColumnType("boolean") + .HasColumnName("disableglobalexpressions"); + + b.Property("DmGreetMessageText") + .HasColumnType("text") + .HasColumnName("dmgreetmessagetext"); + + b.Property("ExclusiveSelfAssignedRoles") + .HasColumnType("boolean") + .HasColumnName("exclusiveselfassignedroles"); + + b.Property("FilterInvites") + .HasColumnType("boolean") + .HasColumnName("filterinvites"); + + b.Property("FilterLinks") + .HasColumnType("boolean") + .HasColumnName("filterlinks"); + + b.Property("FilterWords") + .HasColumnType("boolean") + .HasColumnName("filterwords"); + + b.Property("GameVoiceChannel") + .HasColumnType("numeric(20,0)") + .HasColumnName("gamevoicechannel"); + + b.Property("GreetMessageChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("greetmessagechannelid"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Locale") + .HasColumnType("text") + .HasColumnName("locale"); + + b.Property("MuteRoleName") + .HasColumnType("text") + .HasColumnName("muterolename"); + + b.Property("NotifyStreamOffline") + .HasColumnType("boolean") + .HasColumnName("notifystreamoffline"); + + b.Property("PermissionRole") + .HasColumnType("text") + .HasColumnName("permissionrole"); + + b.Property("Prefix") + .HasColumnType("text") + .HasColumnName("prefix"); + + b.Property("SendBoostMessage") + .HasColumnType("boolean") + .HasColumnName("sendboostmessage"); + + b.Property("SendChannelByeMessage") + .HasColumnType("boolean") + .HasColumnName("sendchannelbyemessage"); + + b.Property("SendChannelGreetMessage") + .HasColumnType("boolean") + .HasColumnName("sendchannelgreetmessage"); + + b.Property("SendDmGreetMessage") + .HasColumnType("boolean") + .HasColumnName("senddmgreetmessage"); + + b.Property("StickyRoles") + .HasColumnType("boolean") + .HasColumnName("stickyroles"); + + b.Property("TimeZoneId") + .HasColumnType("text") + .HasColumnName("timezoneid"); + + b.Property("VerboseErrors") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true) + .HasColumnName("verboseerrors"); + + b.Property("VerbosePermissions") + .HasColumnType("boolean") + .HasColumnName("verbosepermissions"); + + b.Property("WarnExpireAction") + .HasColumnType("integer") + .HasColumnName("warnexpireaction"); + + b.Property("WarnExpireHours") + .HasColumnType("integer") + .HasColumnName("warnexpirehours"); + + b.Property("WarningsInitialized") + .HasColumnType("boolean") + .HasColumnName("warningsinitialized"); + + b.HasKey("Id") + .HasName("pk_guildconfigs"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_guildconfigs_guildid"); + + b.HasIndex("WarnExpireHours") + .HasDatabaseName("ix_guildconfigs_warnexpirehours"); + + b.ToTable("guildconfigs", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ItemType") + .HasColumnType("integer") + .HasColumnName("itemtype"); + + b.Property("LogItemId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logitemid"); + + b.Property("LogSettingId") + .HasColumnType("integer") + .HasColumnName("logsettingid"); + + b.HasKey("Id") + .HasName("pk_ignoredlogchannels"); + + b.HasIndex("LogSettingId", "LogItemId", "ItemType") + .IsUnique() + .HasDatabaseName("ix_ignoredlogchannels_logsettingid_logitemid_itemtype"); + + b.ToTable("ignoredlogchannels", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ImageOnlyChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_imageonlychannels"); + + b.HasIndex("ChannelId") + .IsUnique() + .HasDatabaseName("ix_imageonlychannels_channelid"); + + b.ToTable("imageonlychannels", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelCreatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelcreatedid"); + + b.Property("ChannelDestroyedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channeldestroyedid"); + + b.Property("ChannelUpdatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelupdatedid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("LogOtherId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logotherid"); + + b.Property("LogUserPresenceId") + .HasColumnType("numeric(20,0)") + .HasColumnName("loguserpresenceid"); + + b.Property("LogVoicePresenceId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logvoicepresenceid"); + + b.Property("LogVoicePresenceTTSId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logvoicepresencettsid"); + + b.Property("LogWarnsId") + .HasColumnType("numeric(20,0)") + .HasColumnName("logwarnsid"); + + b.Property("MessageDeletedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messagedeletedid"); + + b.Property("MessageUpdatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageupdatedid"); + + b.Property("ThreadCreatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("threadcreatedid"); + + b.Property("ThreadDeletedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("threaddeletedid"); + + b.Property("UserBannedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userbannedid"); + + b.Property("UserJoinedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userjoinedid"); + + b.Property("UserLeftId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userleftid"); + + b.Property("UserMutedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("usermutedid"); + + b.Property("UserUnbannedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userunbannedid"); + + b.Property("UserUpdatedId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userupdatedid"); + + b.HasKey("Id") + .HasName("pk_logsettings"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_logsettings_guildid"); + + b.ToTable("logsettings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MusicPlayerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AutoDisconnect") + .HasColumnType("boolean") + .HasColumnName("autodisconnect"); + + b.Property("AutoPlay") + .HasColumnType("boolean") + .HasColumnName("autoplay"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("MusicChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("musicchannelid"); + + b.Property("PlayerRepeat") + .HasColumnType("integer") + .HasColumnName("playerrepeat"); + + b.Property("QualityPreset") + .HasColumnType("integer") + .HasColumnName("qualitypreset"); + + b.Property("Volume") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(100) + .HasColumnName("volume"); + + b.HasKey("Id") + .HasName("pk_musicplayersettings"); + + b.HasIndex("GuildId") + .IsUnique() + .HasDatabaseName("ix_musicplayersettings_guildid"); + + b.ToTable("musicplayersettings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Author") + .HasColumnType("text") + .HasColumnName("author"); + + b.Property("AuthorId") + .HasColumnType("numeric(20,0)") + .HasColumnName("authorid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.HasKey("Id") + .HasName("pk_musicplaylists"); + + b.ToTable("musicplaylists", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_muteduserid"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_muteduserid_guildconfigid"); + + b.ToTable("muteduserid", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.EllieExpression", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AllowTarget") + .HasColumnType("boolean") + .HasColumnName("allowtarget"); + + b.Property("AutoDeleteTrigger") + .HasColumnType("boolean") + .HasColumnName("autodeletetrigger"); + + b.Property("ContainsAnywhere") + .HasColumnType("boolean") + .HasColumnName("containsanywhere"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("DmResponse") + .HasColumnType("boolean") + .HasColumnName("dmresponse"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Reactions") + .HasColumnType("text") + .HasColumnName("reactions"); + + b.Property("Response") + .HasColumnType("text") + .HasColumnName("response"); + + b.Property("Trigger") + .HasColumnType("text") + .HasColumnName("trigger"); + + b.HasKey("Id") + .HasName("pk_expressions"); + + b.ToTable("expressions", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("AmountCents") + .HasColumnType("integer") + .HasColumnName("amountcents"); + + b.Property("LastCharge") + .HasColumnType("timestamp without time zone") + .HasColumnName("lastcharge"); + + b.Property("UniquePlatformUserId") + .HasColumnType("text") + .HasColumnName("uniqueplatformuserid"); + + b.Property("ValidThru") + .HasColumnType("timestamp without time zone") + .HasColumnName("validthru"); + + b.HasKey("UserId") + .HasName("pk_patrons"); + + b.HasIndex("UniquePlatformUserId") + .IsUnique() + .HasDatabaseName("ix_patrons_uniqueplatformuserid"); + + b.ToTable("patrons", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Index") + .HasColumnType("integer") + .HasColumnName("index"); + + b.Property("IsCustomCommand") + .HasColumnType("boolean") + .HasColumnName("iscustomcommand"); + + b.Property("PrimaryTarget") + .HasColumnType("integer") + .HasColumnName("primarytarget"); + + b.Property("PrimaryTargetId") + .HasColumnType("numeric(20,0)") + .HasColumnName("primarytargetid"); + + b.Property("SecondaryTarget") + .HasColumnType("integer") + .HasColumnName("secondarytarget"); + + b.Property("SecondaryTargetName") + .HasColumnType("text") + .HasColumnName("secondarytargetname"); + + b.Property("State") + .HasColumnType("boolean") + .HasColumnName("state"); + + b.HasKey("Id") + .HasName("pk_permissions"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_permissions_guildconfigid"); + + b.ToTable("permissions", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PlantedCurrency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("bigint") + .HasColumnName("amount"); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("MessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageid"); + + b.Property("Password") + .HasColumnType("text") + .HasColumnName("password"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_plantedcurrency"); + + b.HasIndex("ChannelId") + .HasDatabaseName("ix_plantedcurrency_channelid"); + + b.HasIndex("MessageId") + .IsUnique() + .HasDatabaseName("ix_plantedcurrency_messageid"); + + b.ToTable("plantedcurrency", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("MusicPlaylistId") + .HasColumnType("integer") + .HasColumnName("musicplaylistid"); + + b.Property("Provider") + .HasColumnType("text") + .HasColumnName("provider"); + + b.Property("ProviderType") + .HasColumnType("integer") + .HasColumnName("providertype"); + + b.Property("Query") + .HasColumnType("text") + .HasColumnName("query"); + + b.Property("Title") + .HasColumnType("text") + .HasColumnName("title"); + + b.Property("Uri") + .HasColumnType("text") + .HasColumnName("uri"); + + b.HasKey("Id") + .HasName("pk_playlistsong"); + + b.HasIndex("MusicPlaylistId") + .HasDatabaseName("ix_playlistsong_musicplaylistid"); + + b.ToTable("playlistsong", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AuthorId") + .HasColumnType("numeric(20,0)") + .HasColumnName("authorid"); + + b.Property("AuthorName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("authorname"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Keyword") + .IsRequired() + .HasColumnType("text") + .HasColumnName("keyword"); + + b.Property("Text") + .IsRequired() + .HasColumnType("text") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_quotes"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_quotes_guildid"); + + b.HasIndex("Keyword") + .HasDatabaseName("ix_quotes_keyword"); + + b.ToTable("quotes", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ReactionRoleV2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Emote") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("emote"); + + b.Property("Group") + .HasColumnType("integer") + .HasColumnName("group"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("LevelReq") + .HasColumnType("integer") + .HasColumnName("levelreq"); + + b.Property("MessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageid"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_reactionroles"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_reactionroles_guildid"); + + b.HasIndex("MessageId", "Emote") + .IsUnique() + .HasDatabaseName("ix_reactionroles_messageid_emote"); + + b.ToTable("reactionroles", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("IsPrivate") + .HasColumnType("boolean") + .HasColumnName("isprivate"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("ServerId") + .HasColumnType("numeric(20,0)") + .HasColumnName("serverid"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("When") + .HasColumnType("timestamp without time zone") + .HasColumnName("when"); + + b.HasKey("Id") + .HasName("pk_reminders"); + + b.HasIndex("When") + .HasDatabaseName("ix_reminders_when"); + + b.ToTable("reminders", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Repeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Interval") + .HasColumnType("interval") + .HasColumnName("interval"); + + b.Property("LastMessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("lastmessageid"); + + b.Property("Message") + .HasColumnType("text") + .HasColumnName("message"); + + b.Property("NoRedundant") + .HasColumnType("boolean") + .HasColumnName("noredundant"); + + b.Property("StartTimeOfDay") + .HasColumnType("interval") + .HasColumnName("starttimeofday"); + + b.HasKey("Id") + .HasName("pk_repeaters"); + + b.ToTable("repeaters", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AmountRewardedThisMonth") + .HasColumnType("bigint") + .HasColumnName("amountrewardedthismonth"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("LastReward") + .HasColumnType("timestamp without time zone") + .HasColumnName("lastreward"); + + b.Property("PlatformUserId") + .HasColumnType("text") + .HasColumnName("platformuserid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_rewardedusers"); + + b.HasIndex("PlatformUserId") + .IsUnique() + .HasDatabaseName("ix_rewardedusers_platformuserid"); + + b.ToTable("rewardedusers", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.RotatingPlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Status") + .HasColumnType("text") + .HasColumnName("status"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_rotatingstatus"); + + b.ToTable("rotatingstatus", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Group") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("group"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("LevelRequirement") + .HasColumnType("integer") + .HasColumnName("levelrequirement"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_selfassignableroles"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique() + .HasDatabaseName("ix_selfassignableroles_guildid_roleid"); + + b.ToTable("selfassignableroles", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AuthorId") + .HasColumnType("numeric(20,0)") + .HasColumnName("authorid"); + + b.Property("Command") + .HasColumnType("text") + .HasColumnName("command"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Index") + .HasColumnType("integer") + .HasColumnName("index"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Price") + .HasColumnType("integer") + .HasColumnName("price"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("RoleName") + .HasColumnType("text") + .HasColumnName("rolename"); + + b.Property("RoleRequirement") + .HasColumnType("numeric(20,0)") + .HasColumnName("rolerequirement"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_shopentry"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_shopentry_guildconfigid"); + + b.ToTable("shopentry", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ShopEntryId") + .HasColumnType("integer") + .HasColumnName("shopentryid"); + + b.Property("Text") + .HasColumnType("text") + .HasColumnName("text"); + + b.HasKey("Id") + .HasName("pk_shopentryitem"); + + b.HasIndex("ShopEntryId") + .HasDatabaseName("ix_shopentryitem_shopentryid"); + + b.ToTable("shopentryitem", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.HasKey("Id") + .HasName("pk_slowmodeignoredrole"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_slowmodeignoredrole_guildconfigid"); + + b.ToTable("slowmodeignoredrole", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_slowmodeignoreduser"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_slowmodeignoreduser_guildconfigid"); + + b.ToTable("slowmodeignoreduser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StickyRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("RoleIds") + .HasColumnType("text") + .HasColumnName("roleids"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_stickyroles"); + + b.HasIndex("GuildId", "UserId") + .IsUnique() + .HasDatabaseName("ix_stickyroles_guildid_userid"); + + b.ToTable("stickyroles", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamOnlineMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("channelid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("MessageId") + .HasColumnType("numeric(20,0)") + .HasColumnName("messageid"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_streamonlinemessages"); + + b.ToTable("streamonlinemessages", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("integer") + .HasColumnName("streamrolesettingsid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_streamroleblacklisteduser"); + + b.HasIndex("StreamRoleSettingsId") + .HasDatabaseName("ix_streamroleblacklisteduser_streamrolesettingsid"); + + b.ToTable("streamroleblacklisteduser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddRoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("addroleid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Enabled") + .HasColumnType("boolean") + .HasColumnName("enabled"); + + b.Property("FromRoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("fromroleid"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Keyword") + .HasColumnType("text") + .HasColumnName("keyword"); + + b.HasKey("Id") + .HasName("pk_streamrolesettings"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_streamrolesettings_guildconfigid"); + + b.ToTable("streamrolesettings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("integer") + .HasColumnName("streamrolesettingsid"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Username") + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_streamrolewhitelisteduser"); + + b.HasIndex("StreamRoleSettingsId") + .HasDatabaseName("ix_streamrolewhitelisteduser_streamrolesettingsid"); + + b.ToTable("streamrolewhitelisteduser", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ArchiveId") + .HasColumnType("integer") + .HasColumnName("archiveid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("IsDone") + .HasColumnType("boolean") + .HasColumnName("isdone"); + + b.Property("Todo") + .HasColumnType("text") + .HasColumnName("todo"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_todos"); + + b.HasIndex("ArchiveId") + .HasDatabaseName("ix_todos_archiveid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_todos_userid"); + + b.ToTable("todos", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnbanTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("UnbanAt") + .HasColumnType("timestamp without time zone") + .HasColumnName("unbanat"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unbantimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unbantimer_guildconfigid"); + + b.ToTable("unbantimer", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("UnmuteAt") + .HasColumnType("timestamp without time zone") + .HasColumnName("unmuteat"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unmutetimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unmutetimer_guildconfigid"); + + b.ToTable("unmutetimer", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnroleTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("UnbanAt") + .HasColumnType("timestamp without time zone") + .HasColumnName("unbanat"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_unroletimer"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_unroletimer_guildconfigid"); + + b.ToTable("unroletimer", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UserXpStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AwardedXp") + .HasColumnType("bigint") + .HasColumnName("awardedxp"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("NotifyOnLevelUp") + .HasColumnType("integer") + .HasColumnName("notifyonlevelup"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Xp") + .HasColumnType("bigint") + .HasColumnName("xp"); + + b.HasKey("Id") + .HasName("pk_userxpstats"); + + b.HasIndex("AwardedXp") + .HasDatabaseName("ix_userxpstats_awardedxp"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_userxpstats_guildid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_userxpstats_userid"); + + b.HasIndex("Xp") + .HasDatabaseName("ix_userxpstats_xp"); + + b.HasIndex("UserId", "GuildId") + .IsUnique() + .HasDatabaseName("ix_userxpstats_userid_guildid"); + + b.ToTable("userxpstats", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("VoiceChannelId") + .HasColumnType("numeric(20,0)") + .HasColumnName("voicechannelid"); + + b.HasKey("Id") + .HasName("pk_vcroleinfo"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_vcroleinfo_guildconfigid"); + + b.ToTable("vcroleinfo", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AffinityId") + .HasColumnType("integer") + .HasColumnName("affinityid"); + + b.Property("ClaimerId") + .HasColumnType("integer") + .HasColumnName("claimerid"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Price") + .HasColumnType("bigint") + .HasColumnName("price"); + + b.Property("WaifuId") + .HasColumnType("integer") + .HasColumnName("waifuid"); + + b.HasKey("Id") + .HasName("pk_waifuinfo"); + + b.HasIndex("AffinityId") + .HasDatabaseName("ix_waifuinfo_affinityid"); + + b.HasIndex("ClaimerId") + .HasDatabaseName("ix_waifuinfo_claimerid"); + + b.HasIndex("Price") + .HasDatabaseName("ix_waifuinfo_price"); + + b.HasIndex("WaifuId") + .IsUnique() + .HasDatabaseName("ix_waifuinfo_waifuid"); + + b.ToTable("waifuinfo", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("ItemEmoji") + .HasColumnType("text") + .HasColumnName("itememoji"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("WaifuInfoId") + .HasColumnType("integer") + .HasColumnName("waifuinfoid"); + + b.HasKey("Id") + .HasName("pk_waifuitem"); + + b.HasIndex("WaifuInfoId") + .HasDatabaseName("ix_waifuitem_waifuinfoid"); + + b.ToTable("waifuitem", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("NewId") + .HasColumnType("integer") + .HasColumnName("newid"); + + b.Property("OldId") + .HasColumnType("integer") + .HasColumnName("oldid"); + + b.Property("UpdateType") + .HasColumnType("integer") + .HasColumnName("updatetype"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_waifuupdates"); + + b.HasIndex("NewId") + .HasDatabaseName("ix_waifuupdates_newid"); + + b.HasIndex("OldId") + .HasDatabaseName("ix_waifuupdates_oldid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_waifuupdates_userid"); + + b.ToTable("waifuupdates", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Forgiven") + .HasColumnType("boolean") + .HasColumnName("forgiven"); + + b.Property("ForgivenBy") + .HasColumnType("text") + .HasColumnName("forgivenby"); + + b.Property("GuildId") + .HasColumnType("numeric(20,0)") + .HasColumnName("guildid"); + + b.Property("Moderator") + .HasColumnType("text") + .HasColumnName("moderator"); + + b.Property("Reason") + .HasColumnType("text") + .HasColumnName("reason"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.Property("Weight") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasDefaultValue(1L) + .HasColumnName("weight"); + + b.HasKey("Id") + .HasName("pk_warnings"); + + b.HasIndex("DateAdded") + .HasDatabaseName("ix_warnings_dateadded"); + + b.HasIndex("GuildId") + .HasDatabaseName("ix_warnings_guildid"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_warnings_userid"); + + b.ToTable("warnings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("integer") + .HasColumnName("count"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("Punishment") + .HasColumnType("integer") + .HasColumnName("punishment"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("Time") + .HasColumnType("integer") + .HasColumnName("time"); + + b.HasKey("Id") + .HasName("pk_warningpunishment"); + + b.HasIndex("GuildConfigId") + .HasDatabaseName("ix_warningpunishment_guildconfigid"); + + b.ToTable("warningpunishment", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpCurrencyReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Amount") + .HasColumnType("integer") + .HasColumnName("amount"); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Level") + .HasColumnType("integer") + .HasColumnName("level"); + + b.Property("XpSettingsId") + .HasColumnType("integer") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_xpcurrencyreward"); + + b.HasIndex("XpSettingsId") + .HasDatabaseName("ix_xpcurrencyreward_xpsettingsid"); + + b.ToTable("xpcurrencyreward", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpRoleReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("Level") + .HasColumnType("integer") + .HasColumnName("level"); + + b.Property("Remove") + .HasColumnType("boolean") + .HasColumnName("remove"); + + b.Property("RoleId") + .HasColumnType("numeric(20,0)") + .HasColumnName("roleid"); + + b.Property("XpSettingsId") + .HasColumnType("integer") + .HasColumnName("xpsettingsid"); + + b.HasKey("Id") + .HasName("pk_xprolereward"); + + b.HasIndex("XpSettingsId", "Level") + .IsUnique() + .HasDatabaseName("ix_xprolereward_xpsettingsid_level"); + + b.ToTable("xprolereward", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("GuildConfigId") + .HasColumnType("integer") + .HasColumnName("guildconfigid"); + + b.Property("ServerExcluded") + .HasColumnType("boolean") + .HasColumnName("serverexcluded"); + + b.HasKey("Id") + .HasName("pk_xpsettings"); + + b.HasIndex("GuildConfigId") + .IsUnique() + .HasDatabaseName("ix_xpsettings_guildconfigid"); + + b.ToTable("xpsettings", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpShopOwnedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("DateAdded") + .HasColumnType("timestamp without time zone") + .HasColumnName("dateadded"); + + b.Property("IsUsing") + .HasColumnType("boolean") + .HasColumnName("isusing"); + + b.Property("ItemKey") + .IsRequired() + .HasColumnType("text") + .HasColumnName("itemkey"); + + b.Property("ItemType") + .HasColumnType("integer") + .HasColumnName("itemtype"); + + b.Property("UserId") + .HasColumnType("numeric(20,0)") + .HasColumnName("userid"); + + b.HasKey("Id") + .HasName("pk_xpshopowneditem"); + + b.HasIndex("UserId", "ItemType", "ItemKey") + .IsUnique() + .HasDatabaseName("ix_xpshopowneditem_userid_itemtype_itemkey"); + + b.ToTable("xpshopowneditem", (string)null); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiAltSetting", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithOne("AntiAltSetting") + .HasForeignKey("EllieBot.Db.Models.AntiAltSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antialtsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiRaidSetting", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithOne("AntiRaidSetting") + .HasForeignKey("EllieBot.Db.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antiraidsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamIgnore", b => + { + b.HasOne("EllieBot.Db.Models.AntiSpamSetting", null) + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_antispamignore_antispamsetting_antispamsettingid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamSetting", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithOne("AntiSpamSetting") + .HasForeignKey("EllieBot.Db.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_antispamsetting_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateUser", b => + { + b.HasOne("EllieBot.Db.Models.AutoTranslateChannel", "Channel") + .WithMany("Users") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_autotranslateusers_autotranslatechannels_channelid"); + + b.Navigation("Channel"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubApplicants", b => + { + b.HasOne("EllieBot.Db.Models.ClubInfo", "Club") + .WithMany("Applicants") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubapplicants_clubs_clubid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubapplicants_discorduser_userid"); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubBans", b => + { + b.HasOne("EllieBot.Db.Models.ClubInfo", "Club") + .WithMany("Bans") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubbans_clubs_clubid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_clubbans_discorduser_userid"); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubInfo", b => + { + b.HasOne("EllieBot.Db.Models.DiscordUser", "Owner") + .WithOne() + .HasForeignKey("EllieBot.Db.Models.ClubInfo", "OwnerId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_clubs_discorduser_ownerid"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandAlias", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_commandalias_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandCooldown", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_commandcooldown_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("DelMsgOnCmdChannels") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_delmsgoncmdchannel_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DiscordUser", b => + { + b.HasOne("EllieBot.Db.Models.ClubInfo", "Club") + .WithMany("Members") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.NoAction) + .HasConstraintName("fk_discorduser_clubs_clubid"); + + b.Navigation("Club"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b => + { + b.HasOne("EllieBot.Db.Models.XpSettings", "XpSettings") + .WithMany("ExclusionList") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_excludeditem_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("FeedSubs") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_feedsub_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterchannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterLinksChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilterLinksChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterlinkschannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterWordsChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filterwordschannelid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilteredWord", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_filteredword_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FollowedStream", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_followedstream_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GCChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_gcchannelid_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayUser", b => + { + b.HasOne("EllieBot.Db.Models.GiveawayModel", null) + .WithMany("Participants") + .HasForeignKey("GiveawayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_giveawayuser_giveawaymodel_giveawayid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GroupName", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("SelfAssignableRoleGroupNames") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_groupname_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b => + { + b.HasOne("EllieBot.Db.Models.LogSetting", "LogSetting") + .WithMany("LogIgnores") + .HasForeignKey("LogSettingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_ignoredlogchannels_logsettings_logsettingid"); + + b.Navigation("LogSetting"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MutedUserId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_muteduserid_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Permissionv2", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("Permissions") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_permissions_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PlaylistSong", b => + { + b.HasOne("EllieBot.Db.Models.MusicPlaylist", null) + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_playlistsong_musicplaylists_musicplaylistid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_shopentry_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntryItem", b => + { + b.HasOne("EllieBot.Db.Models.ShopEntry", null) + .WithMany("Items") + .HasForeignKey("ShopEntryId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_shopentryitem_shopentry_shopentryid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_slowmodeignoredrole_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_slowmodeignoreduser_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.HasOne("EllieBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Blacklist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamroleblacklisteduser_streamrolesettings_streamrolesett~"); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleSettings", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("StreamRole") + .HasForeignKey("EllieBot.Db.Models.StreamRoleSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamrolesettings_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.HasOne("EllieBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Whitelist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_streamrolewhitelisteduser_streamrolesettings_streamrolesett~"); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b => + { + b.HasOne("EllieBot.Db.Models.ArchivedTodoListModel", null) + .WithMany("Items") + .HasForeignKey("ArchiveId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_todos_todosarchive_archiveid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnbanTimer", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("UnbanTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unbantimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnmuteTimer", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unmutetimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnroleTimer", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("UnroleTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_unroletimer_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.VcRoleInfo", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_vcroleinfo_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuInfo", b => + { + b.HasOne("EllieBot.Db.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId") + .HasConstraintName("fk_waifuinfo_discorduser_affinityid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId") + .HasConstraintName("fk_waifuinfo_discorduser_claimerid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("EllieBot.Db.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_waifuinfo_discorduser_waifuid"); + + b.Navigation("Affinity"); + + b.Navigation("Claimer"); + + b.Navigation("Waifu"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuItem", b => + { + b.HasOne("EllieBot.Db.Models.WaifuInfo", "WaifuInfo") + .WithMany("Items") + .HasForeignKey("WaifuInfoId") + .HasConstraintName("fk_waifuitem_waifuinfo_waifuinfoid"); + + b.Navigation("WaifuInfo"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuUpdate", b => + { + b.HasOne("EllieBot.Db.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId") + .HasConstraintName("fk_waifuupdates_discorduser_newid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId") + .HasConstraintName("fk_waifuupdates_discorduser_oldid"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_waifuupdates_discorduser_userid"); + + b.Navigation("New"); + + b.Navigation("Old"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WarningPunishment", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_warningpunishment_guildconfigs_guildconfigid"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpCurrencyReward", b => + { + b.HasOne("EllieBot.Db.Models.XpSettings", "XpSettings") + .WithMany("CurrencyRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xpcurrencyreward_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpRoleReward", b => + { + b.HasOne("EllieBot.Db.Models.XpSettings", "XpSettings") + .WithMany("RoleRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xprolereward_xpsettings_xpsettingsid"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpSettings", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("XpSettings") + .HasForeignKey("EllieBot.Db.Models.XpSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_xpsettings_guildconfigs_guildconfigid"); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamSetting", b => + { + b.Navigation("IgnoredChannels"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ArchivedTodoListModel", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateChannel", b => + { + b.Navigation("Users"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubInfo", b => + { + b.Navigation("Applicants"); + + b.Navigation("Bans"); + + b.Navigation("Members"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayModel", b => + { + b.Navigation("Participants"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b => + { + b.Navigation("AntiAltSetting"); + + b.Navigation("AntiRaidSetting"); + + b.Navigation("AntiSpamSetting"); + + b.Navigation("CommandAliases"); + + b.Navigation("CommandCooldowns"); + + b.Navigation("DelMsgOnCmdChannels"); + + b.Navigation("FeedSubs"); + + b.Navigation("FilterInvitesChannelIds"); + + b.Navigation("FilterLinksChannelIds"); + + b.Navigation("FilterWordsChannelIds"); + + b.Navigation("FilteredWords"); + + b.Navigation("FollowedStreams"); + + b.Navigation("GenerateCurrencyChannelIds"); + + b.Navigation("MutedUsers"); + + b.Navigation("Permissions"); + + b.Navigation("SelfAssignableRoleGroupNames"); + + b.Navigation("ShopEntries"); + + b.Navigation("SlowmodeIgnoredRoles"); + + b.Navigation("SlowmodeIgnoredUsers"); + + b.Navigation("StreamRole"); + + b.Navigation("UnbanTimer"); + + b.Navigation("UnmuteTimers"); + + b.Navigation("UnroleTimer"); + + b.Navigation("VcRoleInfos"); + + b.Navigation("WarnPunishments"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.LogSetting", b => + { + b.Navigation("LogIgnores"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MusicPlaylist", b => + { + b.Navigation("Songs"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleSettings", b => + { + b.Navigation("Blacklist"); + + b.Navigation("Whitelist"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuInfo", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpSettings", b => + { + b.Navigation("CurrencyRewards"); + + b.Navigation("ExclusionList"); + + b.Navigation("RoleRewards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/EllieBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.cs b/src/EllieBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.cs new file mode 100644 index 0000000..7fb11bc --- /dev/null +++ b/src/EllieBot/Migrations/PostgreSql/20240611180506_remove-patron-limits.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace EllieBot.Migrations.PostgreSql +{ + /// + public partial class removepatronlimits : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "patronquotas"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "patronquotas", + columns: table => new + { + userid = table.Column(type: "numeric(20,0)", nullable: false), + featuretype = table.Column(type: "integer", nullable: false), + feature = table.Column(type: "text", nullable: false), + dailycount = table.Column(type: "bigint", nullable: false), + hourlycount = table.Column(type: "bigint", nullable: false), + monthlycount = table.Column(type: "bigint", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_patronquotas", x => new { x.userid, x.featuretype, x.feature }); + }); + + migrationBuilder.CreateIndex( + name: "ix_patronquotas_userid", + table: "patronquotas", + column: "userid"); + } + } +} diff --git a/src/EllieBot/Migrations/PostgreSql/PostgreSqlContextModelSnapshot.cs b/src/EllieBot/Migrations/PostgreSql/PostgreSqlContextModelSnapshot.cs index 02d425e..5873be8 100644 --- a/src/EllieBot/Migrations/PostgreSql/PostgreSqlContextModelSnapshot.cs +++ b/src/EllieBot/Migrations/PostgreSql/PostgreSqlContextModelSnapshot.cs @@ -1717,41 +1717,6 @@ namespace EllieBot.Migrations.PostgreSql b.ToTable("expressions", (string)null); }); - modelBuilder.Entity("EllieBot.Db.Models.PatronQuota", b => - { - b.Property("UserId") - .HasColumnType("numeric(20,0)") - .HasColumnName("userid"); - - b.Property("FeatureType") - .HasColumnType("integer") - .HasColumnName("featuretype"); - - b.Property("Feature") - .HasColumnType("text") - .HasColumnName("feature"); - - b.Property("DailyCount") - .HasColumnType("bigint") - .HasColumnName("dailycount"); - - b.Property("HourlyCount") - .HasColumnType("bigint") - .HasColumnName("hourlycount"); - - b.Property("MonthlyCount") - .HasColumnType("bigint") - .HasColumnName("monthlycount"); - - b.HasKey("UserId", "FeatureType", "Feature") - .HasName("pk_patronquotas"); - - b.HasIndex("UserId") - .HasDatabaseName("ix_patronquotas_userid"); - - b.ToTable("patronquotas", (string)null); - }); - modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b => { b.Property("UserId") diff --git a/src/EllieBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.cs b/src/EllieBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.cs index faaf454..cc33c61 100644 --- a/src/EllieBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.cs +++ b/src/EllieBot/Migrations/Sqlite/20240518221424_guidlconfig-cleanup.cs @@ -12,7 +12,7 @@ namespace EllieBot.Migrations protected override void Up(MigrationBuilder migrationBuilder) { MigrationQueries.GuildConfigCleanup(migrationBuilder); - + migrationBuilder.DropForeignKey( name: "FK_AntiRaidSetting_GuildConfigs_GuildConfigId", table: "AntiRaidSetting"); diff --git a/src/EllieBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs b/src/EllieBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs new file mode 100644 index 0000000..c0d277c --- /dev/null +++ b/src/EllieBot/Migrations/Sqlite/20240611180456_remove-patron-limits.Designer.cs @@ -0,0 +1,2921 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using EllieBot.Db; + +#nullable disable + +namespace EllieBot.Migrations +{ + [DbContext(typeof(SqliteContext))] + [Migration("20240611180456_remove-patron-limits")] + partial class removepatronlimits + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.4"); + + modelBuilder.Entity("EllieBot.Db.Models.AntiAltSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasColumnType("INTEGER"); + + b.Property("ActionDurationMinutes") + .HasColumnType("INTEGER"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("MinAge") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiAltSetting"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("PunishDuration") + .HasColumnType("INTEGER"); + + b.Property("Seconds") + .HasColumnType("INTEGER"); + + b.Property("UserThreshold") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AntiSpamSettingId") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Action") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("MessageThreshold") + .HasColumnType("INTEGER"); + + b.Property("MuteTime") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ArchivedTodoListModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("TodosArchive"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("ChannelName") + .HasColumnType("TEXT"); + + b.Property("CommandText") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("GuildName") + .HasColumnType("TEXT"); + + b.Property("Interval") + .HasColumnType("INTEGER"); + + b.Property("VoiceChannelId") + .HasColumnType("INTEGER"); + + b.Property("VoiceChannelName") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AutoCommands"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoPublishChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("AutoPublishChannel"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoDelete") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId") + .IsUnique(); + + b.HasIndex("GuildId"); + + b.ToTable("AutoTranslateChannels"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Source") + .HasColumnType("TEXT"); + + b.Property("Target") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasAlternateKey("ChannelId", "UserId"); + + b.ToTable("AutoTranslateUsers"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.BanTemplate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("PruneDays") + .HasColumnType("INTEGER"); + + b.Property("Text") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("BanTemplates"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.BankUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Balance") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("BankUsers"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.BlacklistEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Blacklist"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubApplicants", b => + { + b.Property("ClubId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("ClubId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("ClubApplicants"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubBans", b => + { + b.Property("ClubId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("ClubId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("ClubBans"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasColumnType("TEXT"); + + b.Property("ImageUrl") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(20) + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .HasColumnType("INTEGER"); + + b.Property("Xp") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.HasIndex("OwnerId") + .IsUnique(); + + b.ToTable("Clubs"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Mapping") + .HasColumnType("TEXT"); + + b.Property("Trigger") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CommandName") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Seconds") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Extra") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Note") + .HasColumnType("TEXT"); + + b.Property("OtherId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValueSql("NULL"); + + b.Property("Type") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("DelMsgOnCmdChannel"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DiscordPermOverride", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Command") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Perm") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "Command") + .IsUnique(); + + b.ToTable("DiscordPermOverrides"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AvatarId") + .HasColumnType("TEXT"); + + b.Property("ClubId") + .HasColumnType("INTEGER"); + + b.Property("CurrencyAmount") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0L); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Discriminator") + .HasColumnType("TEXT"); + + b.Property("IsClubAdmin") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(false); + + b.Property("NotifyOnLevelUp") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("TotalXp") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0L); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.HasIndex("ClubId"); + + b.HasIndex("CurrencyAmount"); + + b.HasIndex("TotalXp"); + + b.HasIndex("UserId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ItemId") + .HasColumnType("INTEGER"); + + b.Property("ItemType") + .HasColumnType("INTEGER"); + + b.Property("XpSettingsId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("XpSettingsId"); + + b.ToTable("ExcludedItem"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("Url") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasAlternateKey("GuildConfigId", "Url"); + + b.ToTable("FeedSub"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterLinksChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilterLinksChannelId"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterWordsChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilterWordsChannelId"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Word") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GamblingStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Bet") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Feature") + .HasColumnType("TEXT"); + + b.Property("PaidOut") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("Feature") + .IsUnique(); + + b.ToTable("GamblingStats"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("EndsAt") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("GiveawayModel"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("GiveawayId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GiveawayId", "UserId") + .IsUnique(); + + b.ToTable("GiveawayUser"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GroupName", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Number") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId", "Number") + .IsUnique(); + + b.ToTable("GroupName"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoAssignRoleIds") + .HasColumnType("TEXT"); + + b.Property("AutoDeleteByeMessagesTimer") + .HasColumnType("INTEGER"); + + b.Property("AutoDeleteGreetMessagesTimer") + .HasColumnType("INTEGER"); + + b.Property("AutoDeleteSelfAssignedRoleMessages") + .HasColumnType("INTEGER"); + + b.Property("BoostMessage") + .HasColumnType("TEXT"); + + b.Property("BoostMessageChannelId") + .HasColumnType("INTEGER"); + + b.Property("BoostMessageDeleteAfter") + .HasColumnType("INTEGER"); + + b.Property("ByeMessageChannelId") + .HasColumnType("INTEGER"); + + b.Property("ChannelByeMessageText") + .HasColumnType("TEXT"); + + b.Property("ChannelGreetMessageText") + .HasColumnType("TEXT"); + + b.Property("CleverbotEnabled") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DeleteMessageOnCommand") + .HasColumnType("INTEGER"); + + b.Property("DeleteStreamOnlineMessage") + .HasColumnType("INTEGER"); + + b.Property("DisableGlobalExpressions") + .HasColumnType("INTEGER"); + + b.Property("DmGreetMessageText") + .HasColumnType("TEXT"); + + b.Property("ExclusiveSelfAssignedRoles") + .HasColumnType("INTEGER"); + + b.Property("FilterInvites") + .HasColumnType("INTEGER"); + + b.Property("FilterLinks") + .HasColumnType("INTEGER"); + + b.Property("FilterWords") + .HasColumnType("INTEGER"); + + b.Property("GameVoiceChannel") + .HasColumnType("INTEGER"); + + b.Property("GreetMessageChannelId") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Locale") + .HasColumnType("TEXT"); + + b.Property("MuteRoleName") + .HasColumnType("TEXT"); + + b.Property("NotifyStreamOffline") + .HasColumnType("INTEGER"); + + b.Property("PermissionRole") + .HasColumnType("TEXT"); + + b.Property("Prefix") + .HasColumnType("TEXT"); + + b.Property("SendBoostMessage") + .HasColumnType("INTEGER"); + + b.Property("SendChannelByeMessage") + .HasColumnType("INTEGER"); + + b.Property("SendChannelGreetMessage") + .HasColumnType("INTEGER"); + + b.Property("SendDmGreetMessage") + .HasColumnType("INTEGER"); + + b.Property("StickyRoles") + .HasColumnType("INTEGER"); + + b.Property("TimeZoneId") + .HasColumnType("TEXT"); + + b.Property("VerboseErrors") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(true); + + b.Property("VerbosePermissions") + .HasColumnType("INTEGER"); + + b.Property("WarnExpireAction") + .HasColumnType("INTEGER"); + + b.Property("WarnExpireHours") + .HasColumnType("INTEGER"); + + b.Property("WarningsInitialized") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("WarnExpireHours"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ItemType") + .HasColumnType("INTEGER"); + + b.Property("LogItemId") + .HasColumnType("INTEGER"); + + b.Property("LogSettingId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId", "LogItemId", "ItemType") + .IsUnique(); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ImageOnlyChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId") + .IsUnique(); + + b.ToTable("ImageOnlyChannels"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelCreatedId") + .HasColumnType("INTEGER"); + + b.Property("ChannelDestroyedId") + .HasColumnType("INTEGER"); + + b.Property("ChannelUpdatedId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("LogOtherId") + .HasColumnType("INTEGER"); + + b.Property("LogUserPresenceId") + .HasColumnType("INTEGER"); + + b.Property("LogVoicePresenceId") + .HasColumnType("INTEGER"); + + b.Property("LogVoicePresenceTTSId") + .HasColumnType("INTEGER"); + + b.Property("LogWarnsId") + .HasColumnType("INTEGER"); + + b.Property("MessageDeletedId") + .HasColumnType("INTEGER"); + + b.Property("MessageUpdatedId") + .HasColumnType("INTEGER"); + + b.Property("ThreadCreatedId") + .HasColumnType("INTEGER"); + + b.Property("ThreadDeletedId") + .HasColumnType("INTEGER"); + + b.Property("UserBannedId") + .HasColumnType("INTEGER"); + + b.Property("UserJoinedId") + .HasColumnType("INTEGER"); + + b.Property("UserLeftId") + .HasColumnType("INTEGER"); + + b.Property("UserMutedId") + .HasColumnType("INTEGER"); + + b.Property("UserUnbannedId") + .HasColumnType("INTEGER"); + + b.Property("UserUpdatedId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MusicPlayerSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AutoDisconnect") + .HasColumnType("INTEGER"); + + b.Property("AutoPlay") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("MusicChannelId") + .HasColumnType("INTEGER"); + + b.Property("PlayerRepeat") + .HasColumnType("INTEGER"); + + b.Property("QualityPreset") + .HasColumnType("INTEGER"); + + b.Property("Volume") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(100); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.ToTable("MusicPlayerSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Author") + .HasColumnType("TEXT"); + + b.Property("AuthorId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.EllieExpression", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AllowTarget") + .HasColumnType("INTEGER"); + + b.Property("AutoDeleteTrigger") + .HasColumnType("INTEGER"); + + b.Property("ContainsAnywhere") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("DmResponse") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Reactions") + .HasColumnType("TEXT"); + + b.Property("Response") + .HasColumnType("TEXT"); + + b.Property("Trigger") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Expressions"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AmountCents") + .HasColumnType("INTEGER"); + + b.Property("LastCharge") + .HasColumnType("TEXT"); + + b.Property("UniquePlatformUserId") + .HasColumnType("TEXT"); + + b.Property("ValidThru") + .HasColumnType("TEXT"); + + b.HasKey("UserId"); + + b.HasIndex("UniquePlatformUserId") + .IsUnique(); + + b.ToTable("Patrons"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("IsCustomCommand") + .HasColumnType("INTEGER"); + + b.Property("PrimaryTarget") + .HasColumnType("INTEGER"); + + b.Property("PrimaryTargetId") + .HasColumnType("INTEGER"); + + b.Property("SecondaryTarget") + .HasColumnType("INTEGER"); + + b.Property("SecondaryTargetName") + .HasColumnType("TEXT"); + + b.Property("State") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissions"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PlantedCurrency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.Property("Password") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ChannelId"); + + b.HasIndex("MessageId") + .IsUnique(); + + b.ToTable("PlantedCurrency"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("MusicPlaylistId") + .HasColumnType("INTEGER"); + + b.Property("Provider") + .HasColumnType("TEXT"); + + b.Property("ProviderType") + .HasColumnType("INTEGER"); + + b.Property("Query") + .HasColumnType("TEXT"); + + b.Property("Title") + .HasColumnType("TEXT"); + + b.Property("Uri") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AuthorId") + .HasColumnType("INTEGER"); + + b.Property("AuthorName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Keyword") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Text") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.HasIndex("Keyword"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ReactionRoleV2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Emote") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Group") + .HasColumnType("INTEGER"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("LevelReq") + .HasColumnType("INTEGER"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId"); + + b.HasIndex("MessageId", "Emote") + .IsUnique(); + + b.ToTable("ReactionRoles"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("IsPrivate") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("ServerId") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("When") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("When"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Repeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Interval") + .HasColumnType("TEXT"); + + b.Property("LastMessageId") + .HasColumnType("INTEGER"); + + b.Property("Message") + .HasColumnType("TEXT"); + + b.Property("NoRedundant") + .HasColumnType("INTEGER"); + + b.Property("StartTimeOfDay") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Repeaters"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AmountRewardedThisMonth") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("LastReward") + .HasColumnType("TEXT"); + + b.Property("PlatformUserId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("PlatformUserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.RotatingPlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("RotatingStatus"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Group") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("LevelRequirement") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AuthorId") + .HasColumnType("INTEGER"); + + b.Property("Command") + .HasColumnType("TEXT"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Index") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("RoleName") + .HasColumnType("TEXT"); + + b.Property("RoleRequirement") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("ShopEntry"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntryItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ShopEntryId") + .HasColumnType("INTEGER"); + + b.Property("Text") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ShopEntryId"); + + b.ToTable("ShopEntryItem"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StickyRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("RoleIds") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "UserId") + .IsUnique(); + + b.ToTable("StickyRoles"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamOnlineMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ChannelId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("MessageId") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("StreamOnlineMessages"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("StreamRoleSettingsId"); + + b.ToTable("StreamRoleBlacklistedUser"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AddRoleId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("FromRoleId") + .HasColumnType("INTEGER"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Keyword") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("StreamRoleSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("StreamRoleSettingsId") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Username") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("StreamRoleSettingsId"); + + b.ToTable("StreamRoleWhitelistedUser"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ArchiveId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("IsDone") + .HasColumnType("INTEGER"); + + b.Property("Todo") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ArchiveId"); + + b.HasIndex("UserId"); + + b.ToTable("Todos"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnbanTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("UnbanAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnbanTimer"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("UnmuteAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnroleTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("UnbanAt") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnroleTimer"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UserXpStats", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AwardedXp") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("NotifyOnLevelUp") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Xp") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AwardedXp"); + + b.HasIndex("GuildId"); + + b.HasIndex("UserId"); + + b.HasIndex("Xp"); + + b.HasIndex("UserId", "GuildId") + .IsUnique(); + + b.ToTable("UserXpStats"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("VoiceChannelId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AffinityId") + .HasColumnType("INTEGER"); + + b.Property("ClaimerId") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Price") + .HasColumnType("INTEGER"); + + b.Property("WaifuId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("Price"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("ItemEmoji") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("WaifuInfoId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("WaifuInfoId"); + + b.ToTable("WaifuItem"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("NewId") + .HasColumnType("INTEGER"); + + b.Property("OldId") + .HasColumnType("INTEGER"); + + b.Property("UpdateType") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Forgiven") + .HasColumnType("INTEGER"); + + b.Property("ForgivenBy") + .HasColumnType("TEXT"); + + b.Property("GuildId") + .HasColumnType("INTEGER"); + + b.Property("Moderator") + .HasColumnType("TEXT"); + + b.Property("Reason") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.Property("Weight") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(1L); + + b.HasKey("Id"); + + b.HasIndex("DateAdded"); + + b.HasIndex("GuildId"); + + b.HasIndex("UserId"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Count") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("Punishment") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("Time") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpCurrencyReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("XpSettingsId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("XpSettingsId"); + + b.ToTable("XpCurrencyReward"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpRoleReward", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("Level") + .HasColumnType("INTEGER"); + + b.Property("Remove") + .HasColumnType("INTEGER"); + + b.Property("RoleId") + .HasColumnType("INTEGER"); + + b.Property("XpSettingsId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("XpSettingsId", "Level") + .IsUnique(); + + b.ToTable("XpRoleReward"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("GuildConfigId") + .HasColumnType("INTEGER"); + + b.Property("ServerExcluded") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpShopOwnedItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("DateAdded") + .HasColumnType("TEXT"); + + b.Property("IsUsing") + .HasColumnType("INTEGER"); + + b.Property("ItemKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ItemType") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "ItemType", "ItemKey") + .IsUnique(); + + b.ToTable("XpShopOwnedItem"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiAltSetting", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithOne("AntiAltSetting") + .HasForeignKey("EllieBot.Db.Models.AntiAltSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiRaidSetting", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithOne("AntiRaidSetting") + .HasForeignKey("EllieBot.Db.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamIgnore", b => + { + b.HasOne("EllieBot.Db.Models.AntiSpamSetting", null) + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamSetting", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithOne("AntiSpamSetting") + .HasForeignKey("EllieBot.Db.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateUser", b => + { + b.HasOne("EllieBot.Db.Models.AutoTranslateChannel", "Channel") + .WithMany("Users") + .HasForeignKey("ChannelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Channel"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubApplicants", b => + { + b.HasOne("EllieBot.Db.Models.ClubInfo", "Club") + .WithMany("Applicants") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubBans", b => + { + b.HasOne("EllieBot.Db.Models.ClubInfo", "Club") + .WithMany("Bans") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Club"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubInfo", b => + { + b.HasOne("EllieBot.Db.Models.DiscordUser", "Owner") + .WithOne() + .HasForeignKey("EllieBot.Db.Models.ClubInfo", "OwnerId") + .OnDelete(DeleteBehavior.SetNull); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandAlias", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.CommandCooldown", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DelMsgOnCmdChannel", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("DelMsgOnCmdChannels") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("EllieBot.Db.Models.DiscordUser", b => + { + b.HasOne("EllieBot.Db.Models.ClubInfo", "Club") + .WithMany("Members") + .HasForeignKey("ClubId") + .OnDelete(DeleteBehavior.NoAction); + + b.Navigation("Club"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b => + { + b.HasOne("EllieBot.Db.Models.XpSettings", "XpSettings") + .WithMany("ExclusionList") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("FeedSubs") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterLinksChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilterLinksChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilterWordsChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FilteredWord", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.FollowedStream", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GCChannelId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayUser", b => + { + b.HasOne("EllieBot.Db.Models.GiveawayModel", null) + .WithMany("Participants") + .HasForeignKey("GiveawayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GroupName", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithMany("SelfAssignableRoleGroupNames") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.IgnoredLogItem", b => + { + b.HasOne("EllieBot.Db.Models.LogSetting", "LogSetting") + .WithMany("LogIgnores") + .HasForeignKey("LogSettingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LogSetting"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MutedUserId", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.Permissionv2", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("Permissions") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.PlaylistSong", b => + { + b.HasOne("EllieBot.Db.Models.MusicPlaylist", null) + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("ShopEntries") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntryItem", b => + { + b.HasOne("EllieBot.Db.Models.ShopEntry", null) + .WithMany("Items") + .HasForeignKey("ShopEntryId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleBlacklistedUser", b => + { + b.HasOne("EllieBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Blacklist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleSettings", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("StreamRole") + .HasForeignKey("EllieBot.Db.Models.StreamRoleSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleWhitelistedUser", b => + { + b.HasOne("EllieBot.Db.Models.StreamRoleSettings", "StreamRoleSettings") + .WithMany("Whitelist") + .HasForeignKey("StreamRoleSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("StreamRoleSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.TodoModel", b => + { + b.HasOne("EllieBot.Db.Models.ArchivedTodoListModel", null) + .WithMany("Items") + .HasForeignKey("ArchiveId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnbanTimer", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("UnbanTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnmuteTimer", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.UnroleTimer", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("UnroleTimer") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.VcRoleInfo", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuInfo", b => + { + b.HasOne("EllieBot.Db.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("EllieBot.Db.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Affinity"); + + b.Navigation("Claimer"); + + b.Navigation("Waifu"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuItem", b => + { + b.HasOne("EllieBot.Db.Models.WaifuInfo", "WaifuInfo") + .WithMany("Items") + .HasForeignKey("WaifuInfoId"); + + b.Navigation("WaifuInfo"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuUpdate", b => + { + b.HasOne("EllieBot.Db.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("EllieBot.Db.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("New"); + + b.Navigation("Old"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WarningPunishment", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", null) + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpCurrencyReward", b => + { + b.HasOne("EllieBot.Db.Models.XpSettings", "XpSettings") + .WithMany("CurrencyRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpRoleReward", b => + { + b.HasOne("EllieBot.Db.Models.XpSettings", "XpSettings") + .WithMany("RoleRewards") + .HasForeignKey("XpSettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpSettings", b => + { + b.HasOne("EllieBot.Db.Models.GuildConfig", "GuildConfig") + .WithOne("XpSettings") + .HasForeignKey("EllieBot.Db.Models.XpSettings", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GuildConfig"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AntiSpamSetting", b => + { + b.Navigation("IgnoredChannels"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ArchivedTodoListModel", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.AutoTranslateChannel", b => + { + b.Navigation("Users"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ClubInfo", b => + { + b.Navigation("Applicants"); + + b.Navigation("Bans"); + + b.Navigation("Members"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GiveawayModel", b => + { + b.Navigation("Participants"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.GuildConfig", b => + { + b.Navigation("AntiAltSetting"); + + b.Navigation("AntiRaidSetting"); + + b.Navigation("AntiSpamSetting"); + + b.Navigation("CommandAliases"); + + b.Navigation("CommandCooldowns"); + + b.Navigation("DelMsgOnCmdChannels"); + + b.Navigation("FeedSubs"); + + b.Navigation("FilterInvitesChannelIds"); + + b.Navigation("FilterLinksChannelIds"); + + b.Navigation("FilterWordsChannelIds"); + + b.Navigation("FilteredWords"); + + b.Navigation("FollowedStreams"); + + b.Navigation("GenerateCurrencyChannelIds"); + + b.Navigation("MutedUsers"); + + b.Navigation("Permissions"); + + b.Navigation("SelfAssignableRoleGroupNames"); + + b.Navigation("ShopEntries"); + + b.Navigation("SlowmodeIgnoredRoles"); + + b.Navigation("SlowmodeIgnoredUsers"); + + b.Navigation("StreamRole"); + + b.Navigation("UnbanTimer"); + + b.Navigation("UnmuteTimers"); + + b.Navigation("UnroleTimer"); + + b.Navigation("VcRoleInfos"); + + b.Navigation("WarnPunishments"); + + b.Navigation("XpSettings"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.LogSetting", b => + { + b.Navigation("LogIgnores"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.MusicPlaylist", b => + { + b.Navigation("Songs"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.ShopEntry", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.StreamRoleSettings", b => + { + b.Navigation("Blacklist"); + + b.Navigation("Whitelist"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.WaifuInfo", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("EllieBot.Db.Models.XpSettings", b => + { + b.Navigation("CurrencyRewards"); + + b.Navigation("ExclusionList"); + + b.Navigation("RoleRewards"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/EllieBot/Migrations/Sqlite/20240611180456_remove-patron-limits.cs b/src/EllieBot/Migrations/Sqlite/20240611180456_remove-patron-limits.cs new file mode 100644 index 0000000..1091268 --- /dev/null +++ b/src/EllieBot/Migrations/Sqlite/20240611180456_remove-patron-limits.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace EllieBot.Migrations +{ + /// + public partial class removepatronlimits : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "PatronQuotas"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "PatronQuotas", + columns: table => new + { + UserId = table.Column(type: "INTEGER", nullable: false), + FeatureType = table.Column(type: "INTEGER", nullable: false), + Feature = table.Column(type: "TEXT", nullable: false), + DailyCount = table.Column(type: "INTEGER", nullable: false), + HourlyCount = table.Column(type: "INTEGER", nullable: false), + MonthlyCount = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PatronQuotas", x => new { x.UserId, x.FeatureType, x.Feature }); + }); + + migrationBuilder.CreateIndex( + name: "IX_PatronQuotas_UserId", + table: "PatronQuotas", + column: "UserId"); + } + } +} diff --git a/src/EllieBot/Migrations/Sqlite/EllieSqliteContextModelSnapshot.cs b/src/EllieBot/Migrations/Sqlite/EllieSqliteContextModelSnapshot.cs index 1d5dcf6..947c521 100644 --- a/src/EllieBot/Migrations/Sqlite/EllieSqliteContextModelSnapshot.cs +++ b/src/EllieBot/Migrations/Sqlite/EllieSqliteContextModelSnapshot.cs @@ -1279,33 +1279,6 @@ namespace EllieBot.Migrations b.ToTable("Expressions"); }); - modelBuilder.Entity("EllieBot.Db.Models.PatronQuota", b => - { - b.Property("UserId") - .HasColumnType("INTEGER"); - - b.Property("FeatureType") - .HasColumnType("INTEGER"); - - b.Property("Feature") - .HasColumnType("TEXT"); - - b.Property("DailyCount") - .HasColumnType("INTEGER"); - - b.Property("HourlyCount") - .HasColumnType("INTEGER"); - - b.Property("MonthlyCount") - .HasColumnType("INTEGER"); - - b.HasKey("UserId", "FeatureType", "Feature"); - - b.HasIndex("UserId"); - - b.ToTable("PatronQuotas"); - }); - modelBuilder.Entity("EllieBot.Db.Models.PatronUser", b => { b.Property("UserId") From a4adabb3ea3853cbec6bfda4543a3f8e9a491ffa Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 21:23:06 +1200 Subject: [PATCH 07/25] Updated common files again --- .../Replacements/Impl/ReplacementRegistrator.default.cs | 2 +- src/EllieBot/_common/Sender/MessageSenderService.cs | 8 ++++---- src/EllieBot/_common/Settings/ConfigServiceBase.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs b/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs index acecd9e..d42bba6 100644 --- a/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs +++ b/src/EllieBot/_common/Replacements/Impl/ReplacementRegistrator.default.cs @@ -95,7 +95,7 @@ public sealed partial class ReplacementPatternStore Register(_rngRegex, match => { - var rng = new NadekoRandom(); + var rng = new EllieRandom(); if (!int.TryParse(match.Groups["from"].ToString(), out var from)) from = 0; if (!int.TryParse(match.Groups["to"].ToString(), out var to)) diff --git a/src/EllieBot/_common/Sender/MessageSenderService.cs b/src/EllieBot/_common/Sender/MessageSenderService.cs index c6e34ad..f91f1ab 100644 --- a/src/EllieBot/_common/Sender/MessageSenderService.cs +++ b/src/EllieBot/_common/Sender/MessageSenderService.cs @@ -33,15 +33,15 @@ public sealed class MessageSenderService : IMessageSenderService, IEService => new ResponseBuilder(_bs, _bcs, _client) .Channel(smc.Channel); - public NadekoEmbedBuilder CreateEmbed() - => new NadekoEmbedBuilder(_bcs); + public EllieEmbedBuilder CreateEmbed() + => new EllieEmbedBuilder(_bcs); } -public class NadekoEmbedBuilder : EmbedBuilder +public class EllieEmbedBuilder : EmbedBuilder { private readonly BotConfig _bc; - public NadekoEmbedBuilder(BotConfigService bcs) + public EllieEmbedBuilder(BotConfigService bcs) { _bc = bcs.Data; } diff --git a/src/EllieBot/_common/Settings/ConfigServiceBase.cs b/src/EllieBot/_common/Settings/ConfigServiceBase.cs index ab4a15f..df6a0b9 100644 --- a/src/EllieBot/_common/Settings/ConfigServiceBase.cs +++ b/src/EllieBot/_common/Settings/ConfigServiceBase.cs @@ -3,7 +3,7 @@ using EllieBot.Common.Yml; using System.Linq.Expressions; using System.Reflection; -namespace NadekoBot.Services; +namespace EllieBot.Services; /// /// Base service for all settings services From 888994dd677c182acaa11a5bda2512b6a5bd9c57 Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 22:20:28 +1200 Subject: [PATCH 08/25] Updated Permissions module --- .../Modules/Permissions/Blacklist/BlacklistCommands.cs | 4 ++-- .../Modules/Permissions/CommandCooldown/CmdCdService.cs | 8 ++++---- src/EllieBot/Modules/Permissions/Filter/FilterService.cs | 4 ++-- .../Modules/Permissions/Filter/ServerFilterSettings.cs | 2 +- .../GlobalPermissions/GlobalPermissionService.cs | 2 +- src/EllieBot/Modules/Permissions/PermissionCache.cs | 2 +- src/EllieBot/Modules/Permissions/PermissionExtensions.cs | 2 +- src/EllieBot/Modules/Permissions/Permissions.cs | 2 +- src/EllieBot/Modules/Permissions/PermissionsCollection.cs | 2 +- src/EllieBot/Modules/Permissions/PermissionsService.cs | 6 ++---- 10 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/EllieBot/Modules/Permissions/Blacklist/BlacklistCommands.cs b/src/EllieBot/Modules/Permissions/Blacklist/BlacklistCommands.cs index 9db46fb..b552636 100644 --- a/src/EllieBot/Modules/Permissions/Blacklist/BlacklistCommands.cs +++ b/src/EllieBot/Modules/Permissions/Blacklist/BlacklistCommands.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Modules.Permissions.Services; using EllieBot.Db.Models; @@ -46,7 +46,7 @@ public partial class Permissions Log.Warning("Can't get {BlacklistType} [{BlacklistItemId}]", i.Type, i.ItemId); - + return Task.FromResult(Format.Code(i.ItemId.ToString())); } }) diff --git a/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdService.cs b/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdService.cs index f4ea9e8..9f5c6e2 100644 --- a/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdService.cs +++ b/src/EllieBot/Modules/Permissions/CommandCooldown/CmdCdService.cs @@ -33,7 +33,7 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, IEService { if (guild is null) return Task.FromResult(false); - + if (!_settings.TryGetValue(guild.Id, out var cooldownSettings)) return Task.FromResult(false); @@ -82,7 +82,7 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, IEService _activeCooldowns.Remove((guildId, commandName), out _); continue; } - + Cleanup(dict, cdSeconds); } } @@ -103,7 +103,7 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, IEService dict.TryRemove(cmdName, out _); _activeCooldowns.TryRemove((guildId, cmdName), out _); - + using var ctx = _db.GetDbContext(); var gc = ctx.GuildConfigsForId(guildId, x => x.Include(x => x.CommandCooldowns)); gc.CommandCooldowns.RemoveWhere(x => x.CommandName == cmdName); @@ -120,7 +120,7 @@ public sealed class CmdCdService : IExecPreCommand, IReadyExecutor, IEService // force cleanup if (_activeCooldowns.TryGetValue((guildId, name), out var dict)) Cleanup(dict, secs); - + using var ctx = _db.GetDbContext(); var gc = ctx.GuildConfigsForId(guildId, x => x.Include(x => x.CommandCooldowns)); gc.CommandCooldowns.RemoveWhere(x => x.CommandName == name); diff --git a/src/EllieBot/Modules/Permissions/Filter/FilterService.cs b/src/EllieBot/Modules/Permissions/Filter/FilterService.cs index 9dfe01e..139d0d5 100644 --- a/src/EllieBot/Modules/Permissions/Filter/FilterService.cs +++ b/src/EllieBot/Modules/Permissions/Filter/FilterService.cs @@ -171,7 +171,7 @@ public sealed class FilterService : IExecOnMessage // if user has manage messages perm, don't filter if (usrMsg.Channel is ITextChannel ch && usrMsg.Author is IGuildUser gu && gu.GetPermissions(ch).ManageMessages) return false; - + if ((InviteFilteringChannels.Contains(usrMsg.Channel.Id) || InviteFilteringServers.Contains(guild.Id)) && usrMsg.Content.IsDiscordInvite()) { @@ -207,7 +207,7 @@ public sealed class FilterService : IExecOnMessage // if user has manage messages perm, don't filter if (usrMsg.Channel is ITextChannel ch && usrMsg.Author is IGuildUser gu && gu.GetPermissions(ch).ManageMessages) return false; - + if ((LinkFilteringChannels.Contains(usrMsg.Channel.Id) || LinkFilteringServers.Contains(guild.Id)) && usrMsg.Content.TryGetUrlPath(out _)) { diff --git a/src/EllieBot/Modules/Permissions/Filter/ServerFilterSettings.cs b/src/EllieBot/Modules/Permissions/Filter/ServerFilterSettings.cs index bf8454b..3c60a9f 100644 --- a/src/EllieBot/Modules/Permissions/Filter/ServerFilterSettings.cs +++ b/src/EllieBot/Modules/Permissions/Filter/ServerFilterSettings.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Modules.Permissions.Services; public readonly struct ServerFilterSettings diff --git a/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionService.cs b/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionService.cs index 00dfd78..42ad5d7 100644 --- a/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionService.cs +++ b/src/EllieBot/Modules/Permissions/GlobalPermissions/GlobalPermissionService.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Common.ModuleBehaviors; namespace EllieBot.Modules.Permissions.Services; diff --git a/src/EllieBot/Modules/Permissions/PermissionCache.cs b/src/EllieBot/Modules/Permissions/PermissionCache.cs index 47b5983..75bd501 100644 --- a/src/EllieBot/Modules/Permissions/PermissionCache.cs +++ b/src/EllieBot/Modules/Permissions/PermissionCache.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Db.Models; namespace EllieBot.Modules.Permissions.Common; diff --git a/src/EllieBot/Modules/Permissions/PermissionExtensions.cs b/src/EllieBot/Modules/Permissions/PermissionExtensions.cs index 04eee4e..776664e 100644 --- a/src/EllieBot/Modules/Permissions/PermissionExtensions.cs +++ b/src/EllieBot/Modules/Permissions/PermissionExtensions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Db.Models; namespace EllieBot.Modules.Permissions.Common; diff --git a/src/EllieBot/Modules/Permissions/Permissions.cs b/src/EllieBot/Modules/Permissions/Permissions.cs index 90de56b..447dd19 100644 --- a/src/EllieBot/Modules/Permissions/Permissions.cs +++ b/src/EllieBot/Modules/Permissions/Permissions.cs @@ -541,4 +541,4 @@ public partial class Permissions : EllieModule else await Response().Confirm(strs.asm_disable).SendAsync(); } -} +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Permissions/PermissionsCollection.cs b/src/EllieBot/Modules/Permissions/PermissionsCollection.cs index c2526ea..e869bc7 100644 --- a/src/EllieBot/Modules/Permissions/PermissionsCollection.cs +++ b/src/EllieBot/Modules/Permissions/PermissionsCollection.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Modules.Permissions.Common; public class PermissionsCollection : IndexedCollection diff --git a/src/EllieBot/Modules/Permissions/PermissionsService.cs b/src/EllieBot/Modules/Permissions/PermissionsService.cs index 7bca184..95b6388 100644 --- a/src/EllieBot/Modules/Permissions/PermissionsService.cs +++ b/src/EllieBot/Modules/Permissions/PermissionsService.cs @@ -149,8 +149,7 @@ public class PermissionService : IExecPreCommand, IEService returnMsg = "You need Admin permissions in order to use permission commands."; if (pc.Verbose) { - try - { await _sender.Response(channel).Error(returnMsg).SendAsync(); } + try { await _sender.Response(channel).Error(returnMsg).SendAsync(); } catch { } } @@ -162,8 +161,7 @@ public class PermissionService : IExecPreCommand, IEService returnMsg = $"You need the {Format.Bold(role.Name)} role in order to use permission commands."; if (pc.Verbose) { - try - { await _sender.Response(channel).Error(returnMsg).SendAsync(); } + try { await _sender.Response(channel).Error(returnMsg).SendAsync(); } catch { } } From 0466701e28f7a727b1333e0cad2d12f6d037f142 Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 23:51:35 +1200 Subject: [PATCH 09/25] Updated Searches module --- .../Modules/Searches/Crypto/CryptoService.cs | 2 +- .../Crypto/DefaultStockDataService.cs | 43 +-- .../Modules/Searches/Feeds/FeedCommands.cs | 16 +- .../Modules/Searches/Feeds/FeedsService.cs | 76 +++-- .../Modules/Searches/PathOfExileCommands.cs | 312 ------------------ src/EllieBot/Modules/Searches/Searches.cs | 3 +- .../Modules/Searches/SearchesService.cs | 4 +- .../Searches/_common/Config/SearchesConfig.cs | 4 +- 8 files changed, 77 insertions(+), 383 deletions(-) delete mode 100644 src/EllieBot/Modules/Searches/PathOfExileCommands.cs diff --git a/src/EllieBot/Modules/Searches/Crypto/CryptoService.cs b/src/EllieBot/Modules/Searches/Crypto/CryptoService.cs index 146dac3..a28f96e 100644 --- a/src/EllieBot/Modules/Searches/Crypto/CryptoService.cs +++ b/src/EllieBot/Modules/Searches/Crypto/CryptoService.cs @@ -130,7 +130,7 @@ public class CryptoService : IEService await _getCryptoLock.WaitAsync(); try { - var data = await _cache.GetOrAddAsync(new("ellie:crypto_data"), + var data = await _cache.GetOrAddAsync(new("nadeko:crypto_data"), async () => { try diff --git a/src/EllieBot/Modules/Searches/Crypto/DefaultStockDataService.cs b/src/EllieBot/Modules/Searches/Crypto/DefaultStockDataService.cs index 5b5bf40..feb0548 100644 --- a/src/EllieBot/Modules/Searches/Crypto/DefaultStockDataService.cs +++ b/src/EllieBot/Modules/Searches/Crypto/DefaultStockDataService.cs @@ -1,6 +1,7 @@ using AngleSharp; using CsvHelper; using CsvHelper.Configuration; +using System.Diagnostics; using System.Globalization; using System.Text.Json; @@ -22,46 +23,32 @@ public sealed class DefaultStockDataService : IStockDataService, IEService using var http = _httpClientFactory.CreateClient(); - - var quoteHtmlPage = $"https://finance.yahoo.com/quote/{query.ToUpperInvariant()}"; var config = Configuration.Default.WithDefaultLoader(); using var document = await BrowsingContext.New(config).OpenAsync(quoteHtmlPage); - var divElem = - document.QuerySelector( - "#quote-header-info > div:nth-child(2) > div > div > h1"); - var tickerName = (divElem)?.TextContent; + var tickerName = document.QuerySelector("div.top > .left > .container > h1") + ?.TextContent; + + if (tickerName is null) + return default; + var marketcap = document - .QuerySelectorAll("table") - .Skip(1) - .First() - .QuerySelector("tbody > tr > td:nth-child(2)") + .QuerySelector("li > span > fin-streamer[data-field='marketCap']") ?.TextContent; - var volume = document.QuerySelector("td[data-test='AVERAGE_VOLUME_3MONTH-value']") + var volume = document.QuerySelector("li > span > fin-streamer[data-field='regularMarketVolume']") ?.TextContent; - - var close= document.QuerySelector("td[data-test='PREV_CLOSE-value']") - ?.TextContent ?? "0"; - - var price = document - .QuerySelector("#quote-header-info") - ?.QuerySelector("fin-streamer[data-field='regularMarketPrice']") - ?.TextContent ?? close; - - // var data = await http.GetFromJsonAsync( - // $"https://query1.finance.yahoo.com/v7/finance/quote?symbols={query}"); - // - // if (data is null) - // return default; - // var symbol = data.QuoteResponse.Result.FirstOrDefault(); + var close = document.QuerySelector("li > span > fin-streamer[data-field='regularMarketPreviousClose']") + ?.TextContent + ?? "0"; - // if (symbol is null) - // return default; + var price = document.QuerySelector("fin-streamer.livePrice > span") + ?.TextContent + ?? "0"; return new() { diff --git a/src/EllieBot/Modules/Searches/Feeds/FeedCommands.cs b/src/EllieBot/Modules/Searches/Feeds/FeedCommands.cs index 37376f0..316fc73 100644 --- a/src/EllieBot/Modules/Searches/Feeds/FeedCommands.cs +++ b/src/EllieBot/Modules/Searches/Feeds/FeedCommands.cs @@ -1,5 +1,4 @@ -#nullable disable -using CodeHollow.FeedReader; +using CodeHollow.FeedReader; using EllieBot.Modules.Searches.Services; using System.Text.RegularExpressions; @@ -17,19 +16,21 @@ public partial class Searches [RequireContext(ContextType.Guild)] [UserPerm(GuildPerm.ManageMessages)] [Priority(1)] - public Task YtUploadNotif(string url, [Leftover] string message = null) + public Task YtUploadNotif(string url, [Leftover] string? message = null) => YtUploadNotif(url, null, message); [Cmd] [RequireContext(ContextType.Guild)] [UserPerm(GuildPerm.ManageMessages)] [Priority(2)] - public Task YtUploadNotif(string url, ITextChannel channel = null, [Leftover] string message = null) + public Task YtUploadNotif(string url, ITextChannel? channel = null, [Leftover] string? message = null) { var m = _ytChannelRegex.Match(url); if (!m.Success) return Response().Error(strs.invalid_input).SendAsync(); + channel ??= ctx.Channel as ITextChannel; + if (!((IGuildUser)ctx.User).GetPermissions(channel).MentionEveryone) message = message?.SanitizeAllMentions(); @@ -42,7 +43,7 @@ public partial class Searches [RequireContext(ContextType.Guild)] [UserPerm(GuildPerm.ManageMessages)] [Priority(0)] - public Task Feed(string url, [Leftover] string message = null) + public Task Feed(string url, [Leftover] string? message = null) => Feed(url, null, message); @@ -50,7 +51,7 @@ public partial class Searches [RequireContext(ContextType.Guild)] [UserPerm(GuildPerm.ManageMessages)] [Priority(1)] - public async Task Feed(string url, ITextChannel channel = null, [Leftover] string message = null) + public async Task Feed(string url, ITextChannel? channel = null, [Leftover] string? message = null) { if (!Uri.TryCreate(url, UriKind.Absolute, out var uri) || (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)) @@ -59,10 +60,11 @@ public partial class Searches return; } + channel ??= (ITextChannel)ctx.Channel; + if (!((IGuildUser)ctx.User).GetPermissions(channel).MentionEveryone) message = message?.SanitizeAllMentions(); - channel ??= (ITextChannel)ctx.Channel; try { await FeedReader.ReadAsync(url); diff --git a/src/EllieBot/Modules/Searches/Feeds/FeedsService.cs b/src/EllieBot/Modules/Searches/Feeds/FeedsService.cs index d19195c..43ad71f 100644 --- a/src/EllieBot/Modules/Searches/Feeds/FeedsService.cs +++ b/src/EllieBot/Modules/Searches/Feeds/FeedsService.cs @@ -79,6 +79,15 @@ public class FeedsService : IEService } } + private DateTime? GetPubDate(FeedItem item) + { + if (item.PublishingDate is not null) + return item.PublishingDate; + if (item.SpecificItem is AtomFeedItem atomItem) + return atomItem.UpdatedDate; + return null; + } + public async Task TrackFeeds() { while (true) @@ -94,24 +103,32 @@ public class FeedsService : IEService { var feed = await FeedReader.ReadAsync(rssUrl); - var items = feed - .Items.Select(item => (Item: item, - LastUpdate: item.PublishingDate?.ToUniversalTime() - ?? (item.SpecificItem as AtomFeedItem)?.UpdatedDate?.ToUniversalTime())) - .Where(data => data.LastUpdate is not null) - .Select(data => (data.Item, LastUpdate: (DateTime)data.LastUpdate)) - .OrderByDescending(data => data.LastUpdate) - .Reverse() // start from the oldest - .ToList(); + var items = new List<(FeedItem Item, DateTime LastUpdate)>(); + foreach (var item in feed.Items) + { + var pubDate = GetPubDate(item); + + if (pubDate is null) + continue; + + items.Add((item, pubDate.Value.ToUniversalTime())); + + // show at most 3 items if you're behind + if (items.Count > 2) + break; + } + + if (items.Count == 0) + continue; if (!_lastPosts.TryGetValue(kvp.Key, out var lastFeedUpdate)) { - lastFeedUpdate = _lastPosts[kvp.Key] = - items.Any() ? items[items.Count - 1].LastUpdate : DateTime.UtcNow; + lastFeedUpdate = _lastPosts[kvp.Key] = items[0].LastUpdate; } - foreach (var (feedItem, itemUpdateDate) in items) + for (var index = 1; index <= items.Count; index++) { + var (feedItem, itemUpdateDate) = items[^index]; if (itemUpdateDate <= lastFeedUpdate) continue; @@ -168,27 +185,26 @@ public class FeedsService : IEService if (!string.IsNullOrWhiteSpace(feedItem.Description)) embed.WithDescription(desc.TrimTo(2048)); - //send the created embed to all subscribed channels - var feedSendTasks = kvp.Value - .Where(x => x.GuildConfig is not null) - .Select(x => - { - var ch = _client.GetGuild(x.GuildConfig.GuildId) - ?.GetTextChannel(x.ChannelId); - if (ch is null) - return null; + var tasks = new List(); - return _sender.Response(ch) - .Embed(embed) - .Text(string.IsNullOrWhiteSpace(x.Message) - ? string.Empty - : x.Message) - .SendAsync(); - }) - .Where(x => x is not null); + foreach (var val in kvp.Value) + { + var ch = _client.GetGuild(val.GuildConfig.GuildId).GetTextChannel(val.ChannelId); - allSendTasks.Add(feedSendTasks.WhenAll()); + if (ch is null) + continue; + + var sendTask = _sender.Response(ch) + .Embed(embed) + .Text(string.IsNullOrWhiteSpace(val.Message) + ? string.Empty + : val.Message) + .SendAsync(); + tasks.Add(sendTask); + } + + allSendTasks.Add(tasks.WhenAll()); // as data retrieval was successful, reset error counter ClearErrors(rssUrl); diff --git a/src/EllieBot/Modules/Searches/PathOfExileCommands.cs b/src/EllieBot/Modules/Searches/PathOfExileCommands.cs deleted file mode 100644 index a966a5b..0000000 --- a/src/EllieBot/Modules/Searches/PathOfExileCommands.cs +++ /dev/null @@ -1,312 +0,0 @@ -#nullable disable -using EllieBot.Modules.Searches.Common; -using EllieBot.Modules.Searches.Services; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System.Globalization; -using System.Text; - -namespace EllieBot.Modules.Searches; - -public partial class Searches -{ - [Group] - public partial class PathOfExileCommands : EllieModule - { - private const string POE_URL = "https://www.pathofexile.com/character-window/get-characters?accountName="; - private const string PON_URL = "http://poe.ninja/api/Data/GetCurrencyOverview?league="; - private const string POGS_URL = "http://pathofexile.gamepedia.com/api.php?action=opensearch&search="; - - private const string POG_URL = - "https://pathofexile.gamepedia.com/api.php?action=browsebysubject&format=json&subject="; - - private const string POGI_URL = - "https://pathofexile.gamepedia.com/api.php?action=query&prop=imageinfo&iiprop=url&format=json&titles=File:"; - - private const string PROFILE_URL = "https://www.pathofexile.com/account/view-profile/"; - - private readonly IHttpClientFactory _httpFactory; - - private Dictionary currencyDictionary = new(StringComparer.OrdinalIgnoreCase) - { - { "Chaos Orb", "Chaos Orb" }, - { "Orb of Alchemy", "Orb of Alchemy" }, - { "Jeweller's Orb", "Jeweller's Orb" }, - { "Exalted Orb", "Exalted Orb" }, - { "Mirror of Kalandra", "Mirror of Kalandra" }, - { "Vaal Orb", "Vaal Orb" }, - { "Orb of Alteration", "Orb of Alteration" }, - { "Orb of Scouring", "Orb of Scouring" }, - { "Divine Orb", "Divine Orb" }, - { "Orb of Annulment", "Orb of Annulment" }, - { "Master Cartographer's Sextant", "Master Cartographer's Sextant" }, - { "Journeyman Cartographer's Sextant", "Journeyman Cartographer's Sextant" }, - { "Apprentice Cartographer's Sextant", "Apprentice Cartographer's Sextant" }, - { "Blessed Orb", "Blessed Orb" }, - { "Orb of Regret", "Orb of Regret" }, - { "Gemcutter's Prism", "Gemcutter's Prism" }, - { "Glassblower's Bauble", "Glassblower's Bauble" }, - { "Orb of Fusing", "Orb of Fusing" }, - { "Cartographer's Chisel", "Cartographer's Chisel" }, - { "Chromatic Orb", "Chromatic Orb" }, - { "Orb of Augmentation", "Orb of Augmentation" }, - { "Blacksmith's Whetstone", "Blacksmith's Whetstone" }, - { "Orb of Transmutation", "Orb of Transmutation" }, - { "Armourer's Scrap", "Armourer's Scrap" }, - { "Scroll of Wisdom", "Scroll of Wisdom" }, - { "Regal Orb", "Regal Orb" }, - { "Chaos", "Chaos Orb" }, - { "Alch", "Orb of Alchemy" }, - { "Alchs", "Orb of Alchemy" }, - { "Jews", "Jeweller's Orb" }, - { "Jeweller", "Jeweller's Orb" }, - { "Jewellers", "Jeweller's Orb" }, - { "Jeweller's", "Jeweller's Orb" }, - { "X", "Exalted Orb" }, - { "Ex", "Exalted Orb" }, - { "Exalt", "Exalted Orb" }, - { "Exalts", "Exalted Orb" }, - { "Mirror", "Mirror of Kalandra" }, - { "Mirrors", "Mirror of Kalandra" }, - { "Vaal", "Vaal Orb" }, - { "Alt", "Orb of Alteration" }, - { "Alts", "Orb of Alteration" }, - { "Scour", "Orb of Scouring" }, - { "Scours", "Orb of Scouring" }, - { "Divine", "Divine Orb" }, - { "Annul", "Orb of Annulment" }, - { "Annulment", "Orb of Annulment" }, - { "Master Sextant", "Master Cartographer's Sextant" }, - { "Journeyman Sextant", "Journeyman Cartographer's Sextant" }, - { "Apprentice Sextant", "Apprentice Cartographer's Sextant" }, - { "Blessed", "Blessed Orb" }, - { "Regret", "Orb of Regret" }, - { "Regrets", "Orb of Regret" }, - { "Gcp", "Gemcutter's Prism" }, - { "Glassblowers", "Glassblower's Bauble" }, - { "Glassblower's", "Glassblower's Bauble" }, - { "Fusing", "Orb of Fusing" }, - { "Fuses", "Orb of Fusing" }, - { "Fuse", "Orb of Fusing" }, - { "Chisel", "Cartographer's Chisel" }, - { "Chisels", "Cartographer's Chisel" }, - { "Chance", "Orb of Chance" }, - { "Chances", "Orb of Chance" }, - { "Chrome", "Chromatic Orb" }, - { "Chromes", "Chromatic Orb" }, - { "Aug", "Orb of Augmentation" }, - { "Augmentation", "Orb of Augmentation" }, - { "Augment", "Orb of Augmentation" }, - { "Augments", "Orb of Augmentation" }, - { "Whetstone", "Blacksmith's Whetstone" }, - { "Whetstones", "Blacksmith's Whetstone" }, - { "Transmute", "Orb of Transmutation" }, - { "Transmutes", "Orb of Transmutation" }, - { "Armourers", "Armourer's Scrap" }, - { "Armourer's", "Armourer's Scrap" }, - { "Wisdom Scroll", "Scroll of Wisdom" }, - { "Wisdom Scrolls", "Scroll of Wisdom" }, - { "Regal", "Regal Orb" }, - { "Regals", "Regal Orb" } - }; - - public PathOfExileCommands(IHttpClientFactory httpFactory) - => _httpFactory = httpFactory; - - [Cmd] - public async Task PathOfExile(string usr, string league = "", int page = 1) - { - if (--page < 0) - return; - - if (string.IsNullOrWhiteSpace(usr)) - { - await Response().Error("Please provide an account name.").SendAsync(); - return; - } - - var characters = new List(); - - try - { - using var http = _httpFactory.CreateClient(); - var res = await http.GetStringAsync($"{POE_URL}{usr}"); - characters = JsonConvert.DeserializeObject>(res); - } - catch - { - var embed = _sender.CreateEmbed().WithDescription(GetText(strs.account_not_found)).WithErrorColor(); - - await Response().Embed(embed).SendAsync(); - return; - } - - if (!string.IsNullOrWhiteSpace(league)) - characters.RemoveAll(c => c.League != league); - - await Response() - .Paginated() - .Items(characters) - .PageSize(9) - .CurrentPage(page) - .Page((items, curPage) => - { - var embed = _sender.CreateEmbed() - .WithAuthor($"Characters on {usr}'s account", - "https://web.poecdn.com/image/favicon/ogimage.png", - $"{PROFILE_URL}{usr}") - .WithOkColor(); - - if (characters.Count == 0) - return embed.WithDescription("This account has no characters."); - - var sb = new StringBuilder(); - sb.AppendLine($"```{"#",-5}{"Character Name",-23}{"League",-10}{"Class",-13}{"Level",-3}"); - for (var i = 0; i < items.Count; i++) - { - var character = items[i]; - - sb.AppendLine( - $"#{i + 1 + (curPage * 9),-4}{character.Name,-23}{ShortLeagueName(character.League),-10}{character.Class,-13}{character.Level,-3}"); - } - - sb.AppendLine("```"); - embed.WithDescription(sb.ToString()); - - return embed; - }) - .SendAsync(); - } - - [Cmd] - public async Task PathOfExileLeagues() - { - var leagues = new List(); - - try - { - using var http = _httpFactory.CreateClient(); - var res = await http.GetStringAsync("http://api.pathofexile.com/leagues?type=main&compact=1"); - leagues = JsonConvert.DeserializeObject>(res); - } - catch - { - var eembed = _sender.CreateEmbed().WithDescription(GetText(strs.leagues_not_found)).WithErrorColor(); - - await Response().Embed(eembed).SendAsync(); - return; - } - - var embed = _sender.CreateEmbed() - .WithAuthor("Path of Exile Leagues", - "https://web.poecdn.com/image/favicon/ogimage.png", - "https://www.pathofexile.com") - .WithOkColor(); - - var sb = new StringBuilder(); - sb.AppendLine($"```{"#",-5}{"League Name",-23}"); - for (var i = 0; i < leagues.Count; i++) - { - var league = leagues[i]; - - sb.AppendLine($"#{i + 1,-4}{league.Id,-23}"); - } - - sb.AppendLine("```"); - - embed.WithDescription(sb.ToString()); - - await Response().Embed(embed).SendAsync(); - } - - [Cmd] - public async Task PathOfExileCurrency( - string leagueName, - string currencyName, - string convertName = "Chaos Orb") - { - if (string.IsNullOrWhiteSpace(leagueName)) - { - await Response().Error("Please provide league name.").SendAsync(); - return; - } - - if (string.IsNullOrWhiteSpace(currencyName)) - { - await Response().Error("Please provide currency name.").SendAsync(); - return; - } - - var cleanCurrency = ShortCurrencyName(currencyName); - var cleanConvert = ShortCurrencyName(convertName); - - try - { - var res = $"{PON_URL}{leagueName}"; - using var http = _httpFactory.CreateClient(); - var obj = JObject.Parse(await http.GetStringAsync(res)); - - var chaosEquivalent = 0.0F; - var conversionEquivalent = 0.0F; - - // poe.ninja API does not include a "chaosEquivalent" property for Chaos Orbs. - if (cleanCurrency == "Chaos Orb") - chaosEquivalent = 1.0F; - else - { - var currencyInput = obj["lines"] - .Values() - .Where(i => i["currencyTypeName"].Value() == cleanCurrency) - .FirstOrDefault(); - chaosEquivalent = float.Parse(currencyInput["chaosEquivalent"].ToString(), - CultureInfo.InvariantCulture); - } - - if (cleanConvert == "Chaos Orb") - conversionEquivalent = 1.0F; - else - { - var currencyOutput = obj["lines"] - .Values() - .Where(i => i["currencyTypeName"].Value() == cleanConvert) - .FirstOrDefault(); - conversionEquivalent = float.Parse(currencyOutput["chaosEquivalent"].ToString(), - CultureInfo.InvariantCulture); - } - - var embed = _sender.CreateEmbed() - .WithAuthor($"{leagueName} Currency Exchange", - "https://web.poecdn.com/image/favicon/ogimage.png", - "http://poe.ninja") - .AddField("Currency Type", cleanCurrency, true) - .AddField($"{cleanConvert} Equivalent", chaosEquivalent / conversionEquivalent, true) - .WithOkColor(); - - await Response().Embed(embed).SendAsync(); - } - catch - { - var embed = _sender.CreateEmbed().WithDescription(GetText(strs.ninja_not_found)).WithErrorColor(); - - await Response().Embed(embed).SendAsync(); - } - } - - private string ShortCurrencyName(string str) - { - if (currencyDictionary.ContainsValue(str)) - return str; - - var currency = currencyDictionary[str]; - - return currency; - } - - private static string ShortLeagueName(string str) - { - var league = str.Replace("Hardcore", "HC", StringComparison.InvariantCultureIgnoreCase); - - return league; - } - } -} \ No newline at end of file diff --git a/src/EllieBot/Modules/Searches/Searches.cs b/src/EllieBot/Modules/Searches/Searches.cs index 04050e6..7fa6067 100644 --- a/src/EllieBot/Modules/Searches/Searches.cs +++ b/src/EllieBot/Modules/Searches/Searches.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Caching.Memory; using EllieBot.Modules.Searches.Common; using EllieBot.Modules.Searches.Services; +using EllieBot.Modules.Utility; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SixLabors.ImageSharp; @@ -168,7 +169,7 @@ public partial class Searches : EllieModule .AddField("Rating", movie.ImdbRating, true) .AddField("Genre", movie.Genre, true) .AddField("Year", movie.Year, true) - .WithImageUrl(movie.Poster)) + .WithImageUrl(Uri.IsWellFormedUriString(movie.Poster, UriKind.Absolute) ? movie.Poster : null)) .SendAsync(); } diff --git a/src/EllieBot/Modules/Searches/SearchesService.cs b/src/EllieBot/Modules/Searches/SearchesService.cs index f5e3be4..0a9431e 100644 --- a/src/EllieBot/Modules/Searches/SearchesService.cs +++ b/src/EllieBot/Modules/Searches/SearchesService.cs @@ -126,7 +126,7 @@ public class SearchesService : IEService { query = query.Trim().ToLowerInvariant(); - return await _c.GetOrAddAsync(new($"ellie_weather_{query}"), + return await _c.GetOrAddAsync(new($"nadeko_weather_{query}"), async () => await GetWeatherDataFactory(query), TimeSpan.FromHours(3)); } @@ -156,7 +156,7 @@ public class SearchesService : IEService public Task<((string Address, DateTime Time, string TimeZoneName), TimeErrors?)> GetTimeDataAsync(string arg) => GetTimeDataFactory(arg); - //return _cache.GetOrAddCachedDataAsync($"ellie_time_{arg}", + //return _cache.GetOrAddCachedDataAsync($"nadeko_time_{arg}", // GetTimeDataFactory, // arg, // TimeSpan.FromMinutes(1)); diff --git a/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs b/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs index fb64849..c1c73aa 100644 --- a/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs +++ b/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs @@ -40,7 +40,7 @@ public partial class SearchesConfig : ICloneable [Comment(""" Set the searx instance urls in case you want to use 'searx' for either img or web search. - Ellie will use a random one for each request. + Nadeko will use a random one for each request. Use a fully qualified url. Example: `https://my-searx-instance.mydomain.com` Instances specified must support 'format=json' query parameter. - In case you're running your own searx instance, set @@ -57,7 +57,7 @@ public partial class SearchesConfig : ICloneable [Comment(""" Set the invidious instance urls in case you want to use 'invidious' for `.youtube` search - Ellie will use a random one for each request. + Nadeko will use a random one for each request. These instances may be used for music queue functionality in the future. Use a fully qualified url. Example: https://my-invidious-instance.mydomain.com From 4732254805702e42b04a4ce7fd6dd1a1f93bb590 Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 23:52:29 +1200 Subject: [PATCH 10/25] Updated Utility module --- .../Modules/Utility/Ai/AiAssistantService.cs | 314 ++++++++++++++++++ .../Modules/Utility/Ai/AiCommandModel.cs | 15 + .../Modules/Utility/Ai/AiCommandParamModel.cs | 12 + .../Utility/Ai/CommandPromptResultModel.cs | 16 + .../Utility/Ai/EllieCommandCallModel.cs | 8 + .../Modules/Utility/Ai/IAiAssistantService.cs | 20 ++ .../Modules/Utility/Ai/UtilityCommands.cs | 23 ++ .../Calc/{CalcCommand.cs => CalcCommands.cs} | 0 .../Modules/Utility/ConfigCommands.cs | 14 +- .../Utility/Giveaway/GiveawayCommands.cs | 20 +- src/EllieBot/Modules/Utility/GuildColors.cs | 4 +- .../Modules/Utility/Info/InfoCommands.cs | 8 +- .../Modules/Utility/Invite/InviteService.cs | 4 +- .../Modules/Utility/Quote/IQuoteService.cs | 2 +- .../Modules/Utility/Quote/QuoteCommands.cs | 8 +- .../Modules/Utility/Quote/QuoteService.cs | 4 +- .../Modules/Utility/Remind/RemindCommands.cs | 12 +- .../Utility/Repeater/RepeaterService.cs | 2 +- .../Utility/Repeater/RunningRepeater.cs | 2 +- .../Utility/StreamRole/StreamRoleService.cs | 2 +- .../Modules/Utility/Todo/TodoService.cs | 4 +- .../UnitConversion/ConverterService.cs | 20 +- src/EllieBot/Modules/Utility/Utility.cs | 2 +- .../Modules/Utility/VerboseErrorsService.cs | 2 +- .../Modules/Utility/_common/ConvertUnit.cs | 2 +- .../Modules/Utility/_common/EvalGlobals.cs | 2 +- .../Exceptions/StreamRoleNotFoundException.cs | 8 +- .../StreamRolePermissionException.cs | 2 +- .../Utility/_common/StreamRoleListType.cs | 2 +- 29 files changed, 470 insertions(+), 64 deletions(-) create mode 100644 src/EllieBot/Modules/Utility/Ai/AiAssistantService.cs create mode 100644 src/EllieBot/Modules/Utility/Ai/AiCommandModel.cs create mode 100644 src/EllieBot/Modules/Utility/Ai/AiCommandParamModel.cs create mode 100644 src/EllieBot/Modules/Utility/Ai/CommandPromptResultModel.cs create mode 100644 src/EllieBot/Modules/Utility/Ai/EllieCommandCallModel.cs create mode 100644 src/EllieBot/Modules/Utility/Ai/IAiAssistantService.cs create mode 100644 src/EllieBot/Modules/Utility/Ai/UtilityCommands.cs rename src/EllieBot/Modules/Utility/Calc/{CalcCommand.cs => CalcCommands.cs} (100%) diff --git a/src/EllieBot/Modules/Utility/Ai/AiAssistantService.cs b/src/EllieBot/Modules/Utility/Ai/AiAssistantService.cs new file mode 100644 index 0000000..422aae6 --- /dev/null +++ b/src/EllieBot/Modules/Utility/Ai/AiAssistantService.cs @@ -0,0 +1,314 @@ +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Modules.Administration; +using EllieBot.Modules.Games.Services; +using System.Net; +using System.Net.Http.Json; +using System.Text; +using System.Text.Json; +using JsonSerializer = System.Text.Json.JsonSerializer; + +namespace EllieBot.Modules.Utility; + +public enum GetCommandErrorResult +{ + RateLimitHit, + NotAuthorized, + Disregard, + Unknown +} + +public sealed class AiAssistantService + : IAiAssistantService, IReadyExecutor, + IExecOnMessage, + IEService +{ + private IReadOnlyCollection _commands = []; + + private readonly IBotStrings _strings; + private readonly IHttpClientFactory _httpFactory; + private readonly CommandService _cmds; + private readonly IBotCredsProvider _credsProvider; + private readonly DiscordSocketClient _client; + private readonly ICommandHandler _cmdHandler; + private readonly BotConfigService _bcs; + private readonly IMessageSenderService _sender; + + private readonly JsonSerializerOptions _serializerOptions = new(); + private readonly IPermissionChecker _permChecker; + private readonly IBotCache _botCache; + private readonly ChatterBotService _cbs; + + public AiAssistantService( + DiscordSocketClient client, + IBotStrings strings, + IHttpClientFactory httpFactory, + CommandService cmds, + IBotCredsProvider credsProvider, + ICommandHandler cmdHandler, + BotConfigService bcs, + IPermissionChecker permChecker, + IBotCache botCache, + ChatterBotService cbs, + IMessageSenderService sender) + { + _client = client; + _strings = strings; + _httpFactory = httpFactory; + _cmds = cmds; + _credsProvider = credsProvider; + _cmdHandler = cmdHandler; + _bcs = bcs; + _sender = sender; + _permChecker = permChecker; + _botCache = botCache; + _cbs = cbs; + } + + public async Task> TryGetCommandAsync( + ulong userId, + string prompt, + IReadOnlyCollection commands, + string prefix) + { + using var content = new StringContent( + JsonSerializer.Serialize(new + { + query = prompt, + commands = commands.ToDictionary(x => x.Name, + x => new AiCommandModel() + { + Desc = string.Format(x.Desc ?? "", prefix), + Params = x.Params, + Name = x.Name + }), + }), + Encoding.UTF8, + "application/json" + ); + + using var request = new HttpRequestMessage(); + request.Method = HttpMethod.Post; + // request.RequestUri = new("https://nai.nadeko.bot/get-command"); + request.RequestUri = new("https://nai.nadeko.bot/get-command"); + request.Content = content; + + var creds = _credsProvider.GetCreds(); + + request.Headers.TryAddWithoutValidation("x-auth-token", creds.EllieAiToken); + request.Headers.TryAddWithoutValidation("x-auth-userid", userId.ToString()); + + + using var client = _httpFactory.CreateClient(); + + // todo customize according to the bot's config + // - CurrencyName + // - + + using var response = await client.SendAsync(request); + + if (response.StatusCode == HttpStatusCode.TooManyRequests) + { + return GetCommandErrorResult.RateLimitHit; + } + else if (response.StatusCode == HttpStatusCode.Unauthorized) + { + return GetCommandErrorResult.NotAuthorized; + } + + var funcModel = await response.Content.ReadFromJsonAsync(); + + + if (funcModel?.Name == "disregard") + { + Log.Warning("Disregarding the prompt: {Prompt}", prompt); + return GetCommandErrorResult.Disregard; + } + + if (funcModel is null) + return GetCommandErrorResult.Unknown; + + var comModel = new EllieCommandCallModel() + { + Name = funcModel.Name, + Arguments = funcModel.Arguments + .OrderBy(param => _commands.FirstOrDefault(x => x.Name == funcModel.Name) + ?.Params + .Select((x, i) => (x, i)) + .Where(x => x.x.Name == param.Key) + .Select(x => x.i) + .FirstOrDefault()) + .Select(x => x.Value) + .Where(x => !string.IsNullOrWhiteSpace(x)) + .ToArray(), + Remaining = funcModel.Remaining + }; + + return comModel; + } + + public IReadOnlyCollection GetCommands() + => _commands; + + public Task OnReadyAsync() + { + var cmds = _cmds.Commands + .Select(x => (MethodName: x.Summary, CommandName: x.Aliases[0])) + .Where(x => !x.MethodName.Contains("///")) + .Distinct() + .ToList(); + + var funcs = new List(); + foreach (var (method, cmd) in cmds) + { + var commandStrings = _strings.GetCommandStrings(method); + + if (commandStrings is null) + continue; + + funcs.Add(new() + { + Name = cmd, + Desc = commandStrings?.Desc?.Replace("currency", "flowers") ?? string.Empty, + Params = commandStrings?.Params.FirstOrDefault() + ?.Select(x => new AiCommandParamModel() + { + Desc = x.Value.Desc, + Name = x.Key, + }) + .ToArray() + ?? [] + }); + } + + _commands = funcs; + + return Task.CompletedTask; + } + + public int Priority + => 2; + + public async Task ExecOnMessageAsync(IGuild guild, IUserMessage msg) + { + if (string.IsNullOrWhiteSpace(_credsProvider.GetCreds().EllieAiToken)) + return false; + + if (guild is not SocketGuild sg) + return false; + + var nadekoId = _client.CurrentUser.Id; + + var channel = msg.Channel as ITextChannel; + if (channel is null) + return false; + + var normalMention = $"<@{nadekoId}> "; + var nickMention = $"<@!{nadekoId}> "; + string query; + if (msg.Content.StartsWith(normalMention, StringComparison.InvariantCulture)) + query = msg.Content[normalMention.Length..].Trim(); + else if (msg.Content.StartsWith(nickMention, StringComparison.InvariantCulture)) + query = msg.Content[nickMention.Length..].Trim(); + else + return false; + + var success = await TryExecuteAiCommand(guild, msg, channel, query); + + return success; + } + + public async Task TryExecuteAiCommand( + IGuild guild, + IUserMessage msg, + ITextChannel channel, + string query) + { + // check permissions + var pcResult = await _permChecker.CheckPermsAsync( + guild, + msg.Channel, + msg.Author, + "Utility", + "prompt" + ); + + if (!pcResult.IsAllowed) + return false; + + using var _ = channel.EnterTypingState(); + + var result = await TryGetCommandAsync(msg.Author.Id, query, _commands, _cmdHandler.GetPrefix(guild.Id)); + + if (result.TryPickT0(out var model, out var error)) + { + if (model.Name == ".ai_chat") + { + if (guild is not SocketGuild sg) + return false; + + var sess = _cbs.GetOrCreateSession(guild.Id); + if (sess is null) + return false; + + await _cbs.RunChatterBot(sg, msg, channel, sess, query); + return false; + } + + var commandString = GetCommandString(model); + + var msgTask = _sender.Response(channel) + .Embed(_sender.CreateEmbed() + .WithOkColor() + .WithAuthor(msg.Author.GlobalName, + msg.Author.RealAvatarUrl().ToString()) + .WithDescription(commandString)) + .SendAsync(); + + + await _cmdHandler.TryRunCommand( + (SocketGuild)guild, + (ISocketMessageChannel)channel, + new DoAsUserMessage((SocketUserMessage)msg, msg.Author, commandString)); + + var cmdMsg = await msgTask; + + cmdMsg.DeleteAfter(5); + + return true; + } + + if (error == GetCommandErrorResult.Disregard) + { + // await msg.ErrorAsync(); + return false; + } + + var key = new TypedKey($"sub_error:{msg.Author.Id}:{error}"); + + if (!await _botCache.AddAsync(key, true, TimeSpan.FromDays(1), overwrite: false)) + return false; + + var errorMsg = error switch + { + GetCommandErrorResult.RateLimitHit + => "You've spent your daily requests quota.", + GetCommandErrorResult.NotAuthorized + => "In order to use this command you have to have a 5$ or higher subscription at ", + GetCommandErrorResult.Unknown + => "The service is temporarily unavailable.", + _ => throw new ArgumentOutOfRangeException() + }; + + await _sender.Response(channel) + .Error(errorMsg) + .SendAsync(); + + return true; + } + + private string GetCommandString(EllieCommandCallModel res) + => $"{_bcs.Data.Prefix}{res.Name} {res.Arguments.Select((x, i) => GetParamString(x, i + 1 == res.Arguments.Count)).Join(" ")}"; + + private static string GetParamString(string val, bool isLast) + => isLast ? val : "\"" + val + "\""; +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Ai/AiCommandModel.cs b/src/EllieBot/Modules/Utility/Ai/AiCommandModel.cs new file mode 100644 index 0000000..eeaf38b --- /dev/null +++ b/src/EllieBot/Modules/Utility/Ai/AiCommandModel.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Utility; + +public sealed class AiCommandModel +{ + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("desc")] + public required string Desc { get; set; } + + [JsonPropertyName("params")] + public required IReadOnlyList Params { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Ai/AiCommandParamModel.cs b/src/EllieBot/Modules/Utility/Ai/AiCommandParamModel.cs new file mode 100644 index 0000000..594d581 --- /dev/null +++ b/src/EllieBot/Modules/Utility/Ai/AiCommandParamModel.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Utility; + +public sealed class AiCommandParamModel +{ + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("desc")] + public required string Desc { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Ai/CommandPromptResultModel.cs b/src/EllieBot/Modules/Utility/Ai/CommandPromptResultModel.cs new file mode 100644 index 0000000..78d6179 --- /dev/null +++ b/src/EllieBot/Modules/Utility/Ai/CommandPromptResultModel.cs @@ -0,0 +1,16 @@ +using System.Text.Json.Serialization; + +namespace EllieBot.Modules.Utility; + +public sealed class CommandPromptResultModel +{ + [JsonPropertyName("name")] + public required string Name { get; set; } + + [JsonPropertyName("arguments")] + public required Dictionary Arguments { get; set; } + + [JsonPropertyName("remaining")] + [JsonConverter(typeof(NumberToStringConverter))] + public required string Remaining { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Ai/EllieCommandCallModel.cs b/src/EllieBot/Modules/Utility/Ai/EllieCommandCallModel.cs new file mode 100644 index 0000000..4de388e --- /dev/null +++ b/src/EllieBot/Modules/Utility/Ai/EllieCommandCallModel.cs @@ -0,0 +1,8 @@ +namespace EllieBot.Modules.Utility; + +public sealed class EllieCommandCallModel +{ + public required string Name { get; set; } + public required IReadOnlyList Arguments { get; set; } + public required string Remaining { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Ai/IAiAssistantService.cs b/src/EllieBot/Modules/Utility/Ai/IAiAssistantService.cs new file mode 100644 index 0000000..0fc17e2 --- /dev/null +++ b/src/EllieBot/Modules/Utility/Ai/IAiAssistantService.cs @@ -0,0 +1,20 @@ +using OneOf; + +namespace EllieBot.Modules.Utility; + +public interface IAiAssistantService +{ + Task> TryGetCommandAsync( + ulong userId, + string prompt, + IReadOnlyCollection commands, + string prefix); + + IReadOnlyCollection GetCommands(); + + Task TryExecuteAiCommand( + IGuild guild, + IUserMessage msg, + ITextChannel channel, + string query); +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Ai/UtilityCommands.cs b/src/EllieBot/Modules/Utility/Ai/UtilityCommands.cs new file mode 100644 index 0000000..52fe4d5 --- /dev/null +++ b/src/EllieBot/Modules/Utility/Ai/UtilityCommands.cs @@ -0,0 +1,23 @@ +using EllieBot.Modules.Administration; + +namespace EllieBot.Modules.Utility; + +public partial class UtilityCommands +{ + public class PromptCommands : EllieModule + { + [Cmd] + [RequireContext(ContextType.Guild)] + public async Task Prompt([Leftover] string query) + { + await ctx.Channel.TriggerTypingAsync(); + var res = await _service.TryExecuteAiCommand(ctx.Guild, ctx.Message, (ITextChannel)ctx.Channel, query); + } + + private string GetCommandString(EllieCommandCallModel res) + => $"{_bcs.Data.Prefix}{res.Name} {res.Arguments.Select((x, i) => GetParamString(x, i + 1 == res.Arguments.Count)).Join(" ")}"; + + private static string GetParamString(string val, bool isLast) + => isLast ? val : "\"" + val + "\""; + } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Calc/CalcCommand.cs b/src/EllieBot/Modules/Utility/Calc/CalcCommands.cs similarity index 100% rename from src/EllieBot/Modules/Utility/Calc/CalcCommand.cs rename to src/EllieBot/Modules/Utility/Calc/CalcCommands.cs diff --git a/src/EllieBot/Modules/Utility/ConfigCommands.cs b/src/EllieBot/Modules/Utility/ConfigCommands.cs index 28f9772..57b8f4c 100644 --- a/src/EllieBot/Modules/Utility/ConfigCommands.cs +++ b/src/EllieBot/Modules/Utility/ConfigCommands.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Modules.Utility; public partial class Utility @@ -138,12 +138,12 @@ public partial class Utility private string GetPropsAndValuesString(IConfigService config, IReadOnlyCollection names) { var propValues = names.Select(pr => - { - var val = config.GetSetting(pr); - if (pr != "currency.sign") - val = val?.TrimTo(28); - return val?.Replace("\n", "") ?? "-"; - }) + { + var val = config.GetSetting(pr); + if (pr != "currency.sign") + val = val?.TrimTo(28); + return val?.Replace("\n", "") ?? "-"; + }) .ToList(); var strings = names.Zip(propValues, (name, value) => $"{name,-25} = {value}\n"); diff --git a/src/EllieBot/Modules/Utility/Giveaway/GiveawayCommands.cs b/src/EllieBot/Modules/Utility/Giveaway/GiveawayCommands.cs index a2ebf58..2109eef 100644 --- a/src/EllieBot/Modules/Utility/Giveaway/GiveawayCommands.cs +++ b/src/EllieBot/Modules/Utility/Giveaway/GiveawayCommands.cs @@ -48,30 +48,30 @@ public partial class Utility [UserPerm(GuildPerm.ManageMessages)] public async Task GiveawayEnd(kwum id) { - var success = await _service.EndGiveawayAsync(ctx.Guild.Id, id); + var success = await _service.EndGiveawayAsync(ctx.Guild.Id, id); - if (!success) - { - await Response().Error(strs.giveaway_not_found).SendAsync(); - return; - } + if(!success) + { + await Response().Error(strs.giveaway_not_found).SendAsync(); + return; + } - await ctx.OkAsync(); + await ctx.OkAsync(); _ = ctx.Message.DeleteAfter(5); } [Cmd] [UserPerm(GuildPerm.ManageMessages)] public async Task GiveawayReroll(kwum id) - { + { var success = await _service.RerollGiveawayAsync(ctx.Guild.Id, id); if (!success) { await Response().Error(strs.giveaway_not_found).SendAsync(); return; } - - + + await ctx.OkAsync(); _ = ctx.Message.DeleteAfter(5); } diff --git a/src/EllieBot/Modules/Utility/GuildColors.cs b/src/EllieBot/Modules/Utility/GuildColors.cs index bf50902..7f787e6 100644 --- a/src/EllieBot/Modules/Utility/GuildColors.cs +++ b/src/EllieBot/Modules/Utility/GuildColors.cs @@ -4,7 +4,7 @@ namespace EllieBot.Modules.Utility; public interface IGuildColorsService { - + } public sealed class GuildColorsService : IGuildColorsService, IEService @@ -34,6 +34,6 @@ public partial class Utility { public class GuildColorsCommands : EllieModule { - + } } \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Info/InfoCommands.cs b/src/EllieBot/Modules/Utility/Info/InfoCommands.cs index 87b8aa1..e2533e0 100644 --- a/src/EllieBot/Modules/Utility/Info/InfoCommands.cs +++ b/src/EllieBot/Modules/Utility/Info/InfoCommands.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System.Text; using EllieBot.Modules.Patronage; @@ -34,7 +34,7 @@ public partial class Utility { var guild = (IGuild)_client.GetGuild(guildId) ?? await _client.Rest.GetGuildAsync(guildId); - + if (guild is null) return; @@ -144,9 +144,9 @@ public partial class Utility true) .WithOkColor(); - var patron = await _ps.GetPatronAsync(user.Id); + var mPatron = await _ps.GetPatronAsync(user.Id); - if (patron.Tier != PatronTier.None) + if (mPatron is {} patron && patron.Tier != PatronTier.None) { embed.WithFooter(patron.Tier switch { diff --git a/src/EllieBot/Modules/Utility/Invite/InviteService.cs b/src/EllieBot/Modules/Utility/Invite/InviteService.cs index aa6946b..d89ec28 100644 --- a/src/EllieBot/Modules/Utility/Invite/InviteService.cs +++ b/src/EllieBot/Modules/Utility/Invite/InviteService.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using CommandLine; namespace EllieBot.Modules.Utility.Services; @@ -45,4 +45,4 @@ public class InviteService : IEService Expire = 0; } } -} +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Quote/IQuoteService.cs b/src/EllieBot/Modules/Utility/Quote/IQuoteService.cs index 55dc96b..ccf360e 100644 --- a/src/EllieBot/Modules/Utility/Quote/IQuoteService.cs +++ b/src/EllieBot/Modules/Utility/Quote/IQuoteService.cs @@ -3,4 +3,4 @@ public interface IQuoteService { Task DeleteAllAuthorQuotesAsync(ulong guildId, ulong userId); -} +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/Quote/QuoteCommands.cs b/src/EllieBot/Modules/Utility/Quote/QuoteCommands.cs index cea5914..913781b 100644 --- a/src/EllieBot/Modules/Utility/Quote/QuoteCommands.cs +++ b/src/EllieBot/Modules/Utility/Quote/QuoteCommands.cs @@ -1,4 +1,4 @@ -#nullable disable warnings +#nullable disable warnings using LinqToDB; using LinqToDB.EntityFrameworkCore; using EllieBot.Common.Yml; @@ -157,8 +157,8 @@ public partial class Utility async (sm) => { var msg = sm.Data.Components.FirstOrDefault()?.Value; - - if (!string.IsNullOrWhiteSpace(msg)) + + if(!string.IsNullOrWhiteSpace(msg)) await QuoteEdit(id, msg); } ); @@ -307,7 +307,7 @@ public partial class Utility .UpdateWithOutputAsync((del, ins) => ins); q = result.FirstOrDefault(); - + await uow.SaveChangesAsync(); } diff --git a/src/EllieBot/Modules/Utility/Quote/QuoteService.cs b/src/EllieBot/Modules/Utility/Quote/QuoteService.cs index bebed66..db49648 100644 --- a/src/EllieBot/Modules/Utility/Quote/QuoteService.cs +++ b/src/EllieBot/Modules/Utility/Quote/QuoteService.cs @@ -1,4 +1,4 @@ -#nullable disable warnings +#nullable disable warnings using LinqToDB; using LinqToDB.EntityFrameworkCore; using EllieBot.Db.Models; @@ -13,7 +13,7 @@ public sealed class QuoteService : IQuoteService, IEService { _db = db; } - + /// /// Delete all quotes created by the author in a guild /// diff --git a/src/EllieBot/Modules/Utility/Remind/RemindCommands.cs b/src/EllieBot/Modules/Utility/Remind/RemindCommands.cs index 8a414dc..67b87af 100644 --- a/src/EllieBot/Modules/Utility/Remind/RemindCommands.cs +++ b/src/EllieBot/Modules/Utility/Remind/RemindCommands.cs @@ -113,10 +113,9 @@ public partial class Utility foreach (var rem in rems) { var when = rem.When; - var diff = when - DateTime.UtcNow; embed.AddField( $"#{++i + (page * 10)} {rem.When:HH:mm yyyy-MM-dd} UTC " - + $"(in {diff.ToPrettyStringHm()})", + + $"{TimestampTag.FromDateTime(when)}", $@"`Target:` {(rem.IsPrivate ? "DM" : "Channel")} `TargetId:` {rem.ChannelId} `Message:` {rem.Message?.TrimTo(50)}"); @@ -203,16 +202,15 @@ public partial class Utility await uow.SaveChangesAsync(); } - var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id)); + // var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id)); try { await Response() - .Confirm($"\u23f0 {GetText(strs.remind( + .Confirm($"\u23f0 {GetText(strs.remind2( Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username), Format.Bold(message), - ts.ToPrettyStringHm(), - gTime, - gTime))}") + TimestampTag.FromDateTime(DateTime.UtcNow.Add(ts), TimestampTagStyles.Relative), + TimestampTag.FormatFromDateTime(time, TimestampTagStyles.ShortDateTime)))}") .SendAsync(); } catch diff --git a/src/EllieBot/Modules/Utility/Repeater/RepeaterService.cs b/src/EllieBot/Modules/Utility/Repeater/RepeaterService.cs index 6adb2c0..07d05cc 100644 --- a/src/EllieBot/Modules/Utility/Repeater/RepeaterService.cs +++ b/src/EllieBot/Modules/Utility/Repeater/RepeaterService.cs @@ -273,7 +273,7 @@ public sealed class RepeaterService : IReadyExecutor, IEService .Text(text) .Sanitize(false) .SendAsync(); - + _ = newMsg.AddReactionAsync(new Emoji("🔄")); if (_noRedundant.Contains(repeater.Id)) diff --git a/src/EllieBot/Modules/Utility/Repeater/RunningRepeater.cs b/src/EllieBot/Modules/Utility/Repeater/RunningRepeater.cs index 52f4072..509347f 100644 --- a/src/EllieBot/Modules/Utility/Repeater/RunningRepeater.cs +++ b/src/EllieBot/Modules/Utility/Repeater/RunningRepeater.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Db.Models; namespace EllieBot.Modules.Utility.Services; diff --git a/src/EllieBot/Modules/Utility/StreamRole/StreamRoleService.cs b/src/EllieBot/Modules/Utility/StreamRole/StreamRoleService.cs index 1b5796a..4ded9d0 100644 --- a/src/EllieBot/Modules/Utility/StreamRole/StreamRoleService.cs +++ b/src/EllieBot/Modules/Utility/StreamRole/StreamRoleService.cs @@ -30,7 +30,7 @@ public class StreamRoleService : IReadyExecutor, IEService private Task OnPresenceUpdate(SocketUser user, SocketPresence? oldPresence, SocketPresence? newPresence) { - + _ = Task.Run(async () => { if (oldPresence?.Activities?.Count != newPresence?.Activities?.Count) diff --git a/src/EllieBot/Modules/Utility/Todo/TodoService.cs b/src/EllieBot/Modules/Utility/Todo/TodoService.cs index 72a7d13..38ea848 100644 --- a/src/EllieBot/Modules/Utility/Todo/TodoService.cs +++ b/src/EllieBot/Modules/Utility/Todo/TodoService.cs @@ -140,7 +140,7 @@ public sealed class TodoService : IEService return ArchiveTodoResult.NoTodos; } - + await tr.CommitAsync(); return ArchiveTodoResult.Success; @@ -183,7 +183,7 @@ public sealed class TodoService : IEService public async Task GetTodoAsync(ulong userId, int todoId) { await using var ctx = _db.GetDbContext(); - + return await ctx .GetTable() .Where(x => x.UserId == userId && x.Id == todoId) diff --git a/src/EllieBot/Modules/Utility/UnitConversion/ConverterService.cs b/src/EllieBot/Modules/Utility/UnitConversion/ConverterService.cs index 85c299d..12d9f8e 100644 --- a/src/EllieBot/Modules/Utility/UnitConversion/ConverterService.cs +++ b/src/EllieBot/Modules/Utility/UnitConversion/ConverterService.cs @@ -63,20 +63,20 @@ public class ConverterService : IEService, IReadyExecutor UnitType = unitTypeString }; var units = currencyRates.ConversionRates.Select(u => new ConvertUnit - { - Triggers = [u.Key], - Modifier = u.Value, - UnitType = unitTypeString - }) + { + Triggers = [u.Key], + Modifier = u.Value, + UnitType = unitTypeString + }) .ToList(); - var stream = File.OpenRead("data/units.json"); + var stream = File.OpenRead("data/units.json"); var defaultUnits = await JsonSerializer.DeserializeAsync(stream); - if (defaultUnits is not null) + if(defaultUnits is not null) units.AddRange(defaultUnits); - + units.Add(baseType); - + await _cache.AddAsync(_convertKey, units); } @@ -90,7 +90,7 @@ public class Rates { [JsonPropertyName("base")] public string Base { get; set; } - + [JsonPropertyName("date")] public DateTime Date { get; set; } diff --git a/src/EllieBot/Modules/Utility/Utility.cs b/src/EllieBot/Modules/Utility/Utility.cs index 1c53f8c..7382403 100644 --- a/src/EllieBot/Modules/Utility/Utility.cs +++ b/src/EllieBot/Modules/Utility/Utility.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Modules.Utility.Services; using Newtonsoft.Json; using System.Diagnostics; diff --git a/src/EllieBot/Modules/Utility/VerboseErrorsService.cs b/src/EllieBot/Modules/Utility/VerboseErrorsService.cs index e80f889..c5cf886 100644 --- a/src/EllieBot/Modules/Utility/VerboseErrorsService.cs +++ b/src/EllieBot/Modules/Utility/VerboseErrorsService.cs @@ -58,7 +58,7 @@ public class VerboseErrorsService : IEService if (maybeEnabled is bool isEnabled) // set it gc.VerboseErrors = isEnabled; else // toggle it - isEnabled = gc.VerboseErrors = !gc.VerboseErrors; + isEnabled = gc.VerboseErrors = !gc.VerboseErrors; uow.SaveChanges(); diff --git a/src/EllieBot/Modules/Utility/_common/ConvertUnit.cs b/src/EllieBot/Modules/Utility/_common/ConvertUnit.cs index e38cbe4..b65fdea 100644 --- a/src/EllieBot/Modules/Utility/_common/ConvertUnit.cs +++ b/src/EllieBot/Modules/Utility/_common/ConvertUnit.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System.Diagnostics; namespace EllieBot.Modules.Utility.Common; diff --git a/src/EllieBot/Modules/Utility/_common/EvalGlobals.cs b/src/EllieBot/Modules/Utility/_common/EvalGlobals.cs index ffe3ecd..a31c056 100644 --- a/src/EllieBot/Modules/Utility/_common/EvalGlobals.cs +++ b/src/EllieBot/Modules/Utility/_common/EvalGlobals.cs @@ -1,4 +1,4 @@ -// ReSharper disable InconsistentNaming +// ReSharper disable InconsistentNaming #nullable disable namespace EllieBot.Modules.Utility; diff --git a/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRoleNotFoundException.cs b/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRoleNotFoundException.cs index 45e007e..d1880b2 100644 --- a/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRoleNotFoundException.cs +++ b/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRoleNotFoundException.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Modules.Utility.Common.Exceptions; public class StreamRoleNotFoundException : Exception @@ -8,13 +8,13 @@ public class StreamRoleNotFoundException : Exception { } - public StreamRoleNotFoundException(string message) + public StreamRoleNotFoundException(string message) : base(message) { } - public StreamRoleNotFoundException(string message, Exception innerException) + public StreamRoleNotFoundException(string message, Exception innerException) : base(message, innerException) { } -} +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRolePermissionException.cs b/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRolePermissionException.cs index 97fd187..d75c53c 100644 --- a/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRolePermissionException.cs +++ b/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRolePermissionException.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Modules.Utility.Common.Exceptions; public class StreamRolePermissionException : Exception diff --git a/src/EllieBot/Modules/Utility/_common/StreamRoleListType.cs b/src/EllieBot/Modules/Utility/_common/StreamRoleListType.cs index 775b346..aca487b 100644 --- a/src/EllieBot/Modules/Utility/_common/StreamRoleListType.cs +++ b/src/EllieBot/Modules/Utility/_common/StreamRoleListType.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Modules.Utility.Common; public enum StreamRoleListType From f9b21520fbb6937a33097c83f303d81533d2fb64 Mon Sep 17 00:00:00 2001 From: Toastie Date: Wed, 26 Jun 2024 23:58:21 +1200 Subject: [PATCH 11/25] Updated Music module --- src/EllieBot/Modules/Music/Music.cs | 1 + src/EllieBot/Modules/Music/Services/MusicService.cs | 2 +- src/EllieBot/Modules/Music/_common/db/MusicPlaylist.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/EllieBot/Modules/Music/Music.cs b/src/EllieBot/Modules/Music/Music.cs index 3b1393c..a36c440 100644 --- a/src/EllieBot/Modules/Music/Music.cs +++ b/src/EllieBot/Modules/Music/Music.cs @@ -1,6 +1,7 @@ #nullable disable using EllieBot.Modules.Music.Services; using EllieBot.Db.Models; +using EllieBot.Modules.Utility; namespace EllieBot.Modules.Music; diff --git a/src/EllieBot/Modules/Music/Services/MusicService.cs b/src/EllieBot/Modules/Music/Services/MusicService.cs index b2b3da3..c92d8de 100644 --- a/src/EllieBot/Modules/Music/Services/MusicService.cs +++ b/src/EllieBot/Modules/Music/Services/MusicService.cs @@ -212,7 +212,7 @@ public sealed class MusicService : IMusicService, IPlaceholderProvider if (settings.AutoDisconnect) return LeaveVoiceChannelAsync(guildId); } - + return Task.CompletedTask; }; diff --git a/src/EllieBot/Modules/Music/_common/db/MusicPlaylist.cs b/src/EllieBot/Modules/Music/_common/db/MusicPlaylist.cs index 16a755b..697e35e 100644 --- a/src/EllieBot/Modules/Music/_common/db/MusicPlaylist.cs +++ b/src/EllieBot/Modules/Music/_common/db/MusicPlaylist.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Db.Models; public class MusicPlaylist : DbEntity From 3181f4dcaaae8373bb32fcf867a937dfc0bfcc43 Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 16:16:52 +1200 Subject: [PATCH 12/25] Updated Gambling module --- .../Gambling/BlackJack/BlackJackCommands.cs | 1 + .../Modules/Gambling/BlackJack/Blackjack.cs | 2 +- src/EllieBot/Modules/Gambling/Gambling.cs | 49 ++++++++++++------- .../Modules/Gambling/Shop/ShopCommands.cs | 10 +++- .../Modules/Gambling/Slot/SlotCommands.cs | 1 + .../Modules/Gambling/Waifus/db/Waifu.cs | 2 +- .../Gambling/Waifus/db/WaifuExtensions.cs | 12 ++--- .../Modules/Gambling/Waifus/db/WaifuItem.cs | 2 +- .../Modules/Gambling/Waifus/db/WaifuUpdate.cs | 2 +- .../Modules/Gambling/_common/RollDuelGame.cs | 2 +- 10 files changed, 53 insertions(+), 30 deletions(-) diff --git a/src/EllieBot/Modules/Gambling/BlackJack/BlackJackCommands.cs b/src/EllieBot/Modules/Gambling/BlackJack/BlackJackCommands.cs index 772cb4f..ea9c8b8 100644 --- a/src/EllieBot/Modules/Gambling/BlackJack/BlackJackCommands.cs +++ b/src/EllieBot/Modules/Gambling/BlackJack/BlackJackCommands.cs @@ -3,6 +3,7 @@ using EllieBot.Common.TypeReaders; using EllieBot.Modules.Gambling.Common; using EllieBot.Modules.Gambling.Common.Blackjack; using EllieBot.Modules.Gambling.Services; +using EllieBot.Modules.Utility; namespace EllieBot.Modules.Gambling; diff --git a/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs b/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs index e21d2cd..c36845e 100644 --- a/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs +++ b/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs @@ -93,7 +93,7 @@ public class Blackjack } catch (Exception ex) { - Log.Error(ex, "REPORT THE MESSAGE BELOW IN Ellie's Home SERVER PLEASE"); + Log.Error(ex, "REPORT THE MESSAGE BELOW IN #NadekoLog SERVER PLEASE"); State = GameState.Ended; _ = GameEnded?.Invoke(this); } diff --git a/src/EllieBot/Modules/Gambling/Gambling.cs b/src/EllieBot/Modules/Gambling/Gambling.cs index 428f756..52789d0 100644 --- a/src/EllieBot/Modules/Gambling/Gambling.cs +++ b/src/EllieBot/Modules/Gambling/Gambling.cs @@ -1,7 +1,6 @@ #nullable disable using LinqToDB; using LinqToDB.EntityFrameworkCore; -using EllieBot.Db; using EllieBot.Db.Models; using EllieBot.Modules.Gambling.Bank; using EllieBot.Modules.Gambling.Common; @@ -14,6 +13,7 @@ using System.Text; using EllieBot.Modules.Gambling.Rps; using EllieBot.Common.TypeReaders; using EllieBot.Modules.Patronage; +using EllieBot.Modules.Utility; namespace EllieBot.Modules.Gambling; @@ -27,9 +27,9 @@ public partial class Gambling : GamblingModule private readonly DownloadTracker _tracker; private readonly GamblingConfigService _configService; private readonly IBankService _bank; - private readonly IPatronageService _ps; private readonly IRemindService _remind; private readonly GamblingTxTracker _gamblingTxTracker; + private readonly IPatronageService _ps; private IUserMessage rdMsg; @@ -41,8 +41,8 @@ public partial class Gambling : GamblingModule DownloadTracker tracker, GamblingConfigService configService, IBankService bank, - IPatronageService ps, IRemindService remind, + IPatronageService patronage, GamblingTxTracker gamblingTxTracker) : base(configService) { @@ -51,9 +51,9 @@ public partial class Gambling : GamblingModule _cs = currency; _client = client; _bank = bank; - _ps = ps; _remind = remind; _gamblingTxTracker = gamblingTxTracker; + _ps = patronage; _enUsCulture = new CultureInfo("en-US", false).NumberFormat; _enUsCulture.NumberDecimalDigits = 0; @@ -133,12 +133,6 @@ public partial class Gambling : GamblingModule await Response().Embed(embed).SendAsync(); } - private static readonly FeatureLimitKey _timelyKey = new FeatureLimitKey() - { - Key = "timely:extra_percent", - PrettyName = "Timely" - }; - private async Task RemindTimelyAction(SocketMessageComponent smc, DateTime when) { var tt = TimestampTag.FromDateTime(when, TimestampTagStyles.Relative); @@ -154,6 +148,7 @@ public partial class Gambling : GamblingModule await smc.RespondConfirmAsync(_sender, GetText(strs.remind_timely(tt)), ephemeral: true); } + // Creates timely reminder button, parameter in hours. private EllieInteractionBase CreateRemindMeInteraction(int period) => _inter .Create(ctx.User.Id, @@ -163,6 +158,17 @@ public partial class Gambling : GamblingModule customId: "timely:remind_me"), (smc) => RemindTimelyAction(smc, DateTime.UtcNow.Add(TimeSpan.FromHours(period))) ); + + // Creates timely reminder button, parameter in milliseconds. + private EllieInteractionBase CreateRemindMeInteraction(double ms) + => _inter + .Create(ctx.User.Id, + new ButtonBuilder( + label: "Remind me", + emote: Emoji.Parse("⏰"), + customId: "timely:remind_me"), + (smc) => RemindTimelyAction(smc, DateTime.UtcNow.Add(TimeSpan.FromMilliseconds(ms))) + ); [Cmd] public async Task Timely() @@ -175,25 +181,31 @@ public partial class Gambling : GamblingModule return; } - var inter = CreateRemindMeInteraction(period); - - if (await _service.ClaimTimelyAsync(ctx.User.Id, period) is { } rem) + if (await _service.ClaimTimelyAsync(ctx.User.Id, period) is { } remainder) { + // Get correct time form remainder + var interaction = CreateRemindMeInteraction(remainder.TotalMilliseconds); + // Removes timely button if there is a timely reminder in DB if (_service.UserHasTimelyReminder(ctx.User.Id)) { - inter = null; + interaction = null; } var now = DateTime.UtcNow; - var relativeTag = TimestampTag.FromDateTime(now.Add(rem), TimestampTagStyles.Relative); - await Response().Pending(strs.timely_already_claimed(relativeTag)).Interaction(inter).SendAsync(); + var relativeTag = TimestampTag.FromDateTime(now.Add(remainder), TimestampTagStyles.Relative); + await Response().Pending(strs.timely_already_claimed(relativeTag)).Interaction(interaction).SendAsync(); return; } + - var result = await _ps.TryGetFeatureLimitAsync(_timelyKey, ctx.User.Id, 0); + var patron = await _ps.GetPatronAsync(ctx.User.Id); - val = (int)(val * (1 + (result.Quota! * 0.01f))); + var percentBonus = (_ps.PercentBonus(patron) / 100f); + + val += (int)(val * percentBonus); + + var inter = CreateRemindMeInteraction(period); await _cs.AddAsync(ctx.User.Id, val, new("timely", "claim")); @@ -892,6 +904,7 @@ public partial class Gambling : GamblingModule private static readonly ImmutableArray _emojis = new[] { "⬆", "↖", "⬅", "↙", "⬇", "↘", "➡", "↗" }.ToImmutableArray(); + [Cmd] public async Task LuckyLadder([OverrideTypeReader(typeof(BalanceTypeReader))] long amount) { diff --git a/src/EllieBot/Modules/Gambling/Shop/ShopCommands.cs b/src/EllieBot/Modules/Gambling/Shop/ShopCommands.cs index 8b5230b..a7910de 100644 --- a/src/EllieBot/Modules/Gambling/Shop/ShopCommands.cs +++ b/src/EllieBot/Modules/Gambling/Shop/ShopCommands.cs @@ -247,7 +247,14 @@ public partial class Gambling } else { - var cmd = entry.Command.Replace("%you%", ctx.User.Id.ToString()); + var buyer = (IGuildUser)ctx.User; + var cmd = entry.Command + .Replace("%you%", buyer.Mention) + .Replace("%you.mention%", buyer.Mention) + .Replace("%you.username%", buyer.Username) + .Replace("%you.name%", buyer.GlobalName ?? buyer.Username) + .Replace("%you.nick%", buyer.DisplayName); + var eb = _sender.CreateEmbed() .WithPendingColor() .WithTitle("Executing shop command") @@ -259,6 +266,7 @@ public partial class Gambling GetProfitAmount(entry.Price), new("shop", "sell", entry.Name)); + await Task.Delay(250); await _cmdHandler.TryRunCommand(guild, channel, new DoAsUserMessage( diff --git a/src/EllieBot/Modules/Gambling/Slot/SlotCommands.cs b/src/EllieBot/Modules/Gambling/Slot/SlotCommands.cs index 238e97e..979cbae 100644 --- a/src/EllieBot/Modules/Gambling/Slot/SlotCommands.cs +++ b/src/EllieBot/Modules/Gambling/Slot/SlotCommands.cs @@ -9,6 +9,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using EllieBot.Modules.Gambling; using EllieBot.Common.TypeReaders; +using EllieBot.Modules.Utility; using Color = SixLabors.ImageSharp.Color; using Image = SixLabors.ImageSharp.Image; diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/Waifu.cs b/src/EllieBot/Modules/Gambling/Waifus/db/Waifu.cs index fa7c5d5..559f8ba 100644 --- a/src/EllieBot/Modules/Gambling/Waifus/db/Waifu.cs +++ b/src/EllieBot/Modules/Gambling/Waifus/db/Waifu.cs @@ -5,7 +5,7 @@ public class WaifuInfo : DbEntity { public int WaifuId { get; set; } public DiscordUser Waifu { get; set; } - + public int? ClaimerId { get; set; } public DiscordUser Claimer { get; set; } diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuExtensions.cs b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuExtensions.cs index 45f3055..a1b6142 100644 --- a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuExtensions.cs +++ b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuExtensions.cs @@ -66,12 +66,12 @@ public static class WaifuExtensions await ctx.Set() .ToLinqToDBTable() .InsertOrUpdateAsync(() => new() - { - AffinityId = null, - ClaimerId = null, - Price = 1, - WaifuId = ctx.Set().Where(x => x.UserId == userId).Select(x => x.Id).First() - }, + { + AffinityId = null, + ClaimerId = null, + Price = 1, + WaifuId = ctx.Set().Where(x => x.UserId == userId).Select(x => x.Id).First() + }, _ => new(), () => new() { diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuItem.cs b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuItem.cs index 89125c8..5b8630f 100644 --- a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuItem.cs +++ b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuItem.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Db.Models; public class WaifuItem : DbEntity diff --git a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdate.cs b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdate.cs index 736bd0d..64608c2 100644 --- a/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdate.cs +++ b/src/EllieBot/Modules/Gambling/Waifus/db/WaifuUpdate.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable namespace EllieBot.Db.Models; public class WaifuUpdate : DbEntity diff --git a/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs b/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs index 24b634a..1244252 100644 --- a/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs +++ b/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs @@ -34,7 +34,7 @@ public class RollDuelGame private readonly ICurrencyService _cs; private readonly Timer _timeoutTimer; - private readonly EllieRandom _rng = new(); + private readonly NadekoRandom _rng = new(); private readonly SemaphoreSlim _locker = new(1, 1); public RollDuelGame( From 496a0cc68cd0c06f895a2750b2663847e4853cb8 Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 16:38:10 +1200 Subject: [PATCH 13/25] Updated things to be right --- src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs | 2 +- src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs | 2 +- .../Modules/Searches/_common/Config/SearchesConfig.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs b/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs index c36845e..982454e 100644 --- a/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs +++ b/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs @@ -93,7 +93,7 @@ public class Blackjack } catch (Exception ex) { - Log.Error(ex, "REPORT THE MESSAGE BELOW IN #NadekoLog SERVER PLEASE"); + Log.Error(ex, "REPORT THE MESSAGE BELOW IN Ellie Support SERVER PLEASE"); State = GameState.Ended; _ = GameEnded?.Invoke(this); } diff --git a/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs b/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs index 1244252..24b634a 100644 --- a/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs +++ b/src/EllieBot/Modules/Gambling/_common/RollDuelGame.cs @@ -34,7 +34,7 @@ public class RollDuelGame private readonly ICurrencyService _cs; private readonly Timer _timeoutTimer; - private readonly NadekoRandom _rng = new(); + private readonly EllieRandom _rng = new(); private readonly SemaphoreSlim _locker = new(1, 1); public RollDuelGame( diff --git a/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs b/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs index c1c73aa..fb64849 100644 --- a/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs +++ b/src/EllieBot/Modules/Searches/_common/Config/SearchesConfig.cs @@ -40,7 +40,7 @@ public partial class SearchesConfig : ICloneable [Comment(""" Set the searx instance urls in case you want to use 'searx' for either img or web search. - Nadeko will use a random one for each request. + Ellie will use a random one for each request. Use a fully qualified url. Example: `https://my-searx-instance.mydomain.com` Instances specified must support 'format=json' query parameter. - In case you're running your own searx instance, set @@ -57,7 +57,7 @@ public partial class SearchesConfig : ICloneable [Comment(""" Set the invidious instance urls in case you want to use 'invidious' for `.youtube` search - Nadeko will use a random one for each request. + Ellie will use a random one for each request. These instances may be used for music queue functionality in the future. Use a fully qualified url. Example: https://my-invidious-instance.mydomain.com From 3df4f710daa6483a839acaf8ba4f78c5ea302b0b Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 16:40:00 +1200 Subject: [PATCH 14/25] Updated the Discord server name --- src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs b/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs index 982454e..e21d2cd 100644 --- a/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs +++ b/src/EllieBot/Modules/Gambling/BlackJack/Blackjack.cs @@ -93,7 +93,7 @@ public class Blackjack } catch (Exception ex) { - Log.Error(ex, "REPORT THE MESSAGE BELOW IN Ellie Support SERVER PLEASE"); + Log.Error(ex, "REPORT THE MESSAGE BELOW IN Ellie's Home SERVER PLEASE"); State = GameState.Ended; _ = GameEnded?.Invoke(this); } From 3a703702879fec1eabea37d936a1d19482e72bd6 Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 16:41:10 +1200 Subject: [PATCH 15/25] Updated Games module --- ...erBotCommands.cs => ChatterBotCommands.cs} | 7 +- .../Games/ChatterBot/ChatterbotService.cs | 146 ++++++++---------- .../Games/ChatterBot/_common/Gpt3Response.cs | 17 +- .../ChatterBot/_common/IChatterBotSession.cs | 5 +- .../_common/OfficialCleverbotSession.cs | 15 +- .../ChatterBot/_common/OfficialGpt3Session.cs | 105 ------------- .../ChatterBot/_common/OfficialGptSession.cs | 141 +++++++++++++++++ src/EllieBot/Modules/Games/GamesConfig.cs | 28 ++-- .../Modules/Games/GamesConfigService.cs | 23 +-- 9 files changed, 270 insertions(+), 217 deletions(-) rename src/EllieBot/Modules/Games/ChatterBot/{CleverBotCommands.cs => ChatterBotCommands.cs} (85%) delete mode 100644 src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs create mode 100644 src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGptSession.cs diff --git a/src/EllieBot/Modules/Games/ChatterBot/CleverBotCommands.cs b/src/EllieBot/Modules/Games/ChatterBot/ChatterBotCommands.cs similarity index 85% rename from src/EllieBot/Modules/Games/ChatterBot/CleverBotCommands.cs rename to src/EllieBot/Modules/Games/ChatterBot/ChatterBotCommands.cs index 1a41953..371c958 100644 --- a/src/EllieBot/Modules/Games/ChatterBot/CleverBotCommands.cs +++ b/src/EllieBot/Modules/Games/ChatterBot/ChatterBotCommands.cs @@ -18,7 +18,8 @@ public partial class Games [Cmd] [RequireContext(ContextType.Guild)] [UserPerm(GuildPerm.ManageMessages)] - public async Task Cleverbot() + [NoPublicBot] + public async Task CleverBot() { var channel = (ITextChannel)ctx.Channel; @@ -30,7 +31,7 @@ public partial class Games await uow.SaveChangesAsync(); } - await Response().Confirm(strs.cleverbot_disabled).SendAsync(); + await Response().Confirm(strs.chatbot_disabled).SendAsync(); return; } @@ -42,7 +43,7 @@ public partial class Games await uow.SaveChangesAsync(); } - await Response().Confirm(strs.cleverbot_enabled).SendAsync(); + await Response().Confirm(strs.chatbot_enabled).SendAsync(); } } } \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/ChatterbotService.cs b/src/EllieBot/Modules/Games/ChatterBot/ChatterbotService.cs index 30dc17e..532dd5a 100644 --- a/src/EllieBot/Modules/Games/ChatterBot/ChatterbotService.cs +++ b/src/EllieBot/Modules/Games/ChatterBot/ChatterbotService.cs @@ -15,43 +15,32 @@ public class ChatterBotService : IExecOnMessage public int Priority => 1; - private readonly FeatureLimitKey _flKey; - private readonly DiscordSocketClient _client; private readonly IPermissionChecker _perms; - private readonly CommandHandler _cmd; private readonly IBotCredentials _creds; private readonly IHttpClientFactory _httpFactory; - private readonly IPatronageService _ps; private readonly GamesConfigService _gcs; private readonly IMessageSenderService _sender; + public readonly IPatronageService _ps; public ChatterBotService( DiscordSocketClient client, IPermissionChecker perms, IBot bot, - CommandHandler cmd, + IPatronageService ps, IHttpClientFactory factory, IBotCredentials creds, - IPatronageService ps, GamesConfigService gcs, IMessageSenderService sender) { _client = client; _perms = perms; - _cmd = cmd; _creds = creds; _sender = sender; _httpFactory = factory; - _ps = ps; _perms = perms; _gcs = gcs; - - _flKey = new FeatureLimitKey() - { - Key = CleverBotResponseStr.CLEVERBOT_RESPONSE, - PrettyName = "Cleverbot Replies" - }; + _ps = ps; ChatterBotGuilds = new(bot.AllGuildConfigs .Where(gc => gc.CleverbotEnabled) @@ -69,9 +58,9 @@ public class ChatterBotService : IExecOnMessage Log.Information("Cleverbot will not work as the api key is missing"); return null; - case ChatBotImplementation.Gpt3: + case ChatBotImplementation.Gpt: if (!string.IsNullOrWhiteSpace(_creds.Gpt3ApiKey)) - return new OfficialGpt3Session(_creds.Gpt3ApiKey, + return new OfficialGptSession(_creds.Gpt3ApiKey, _gcs.Data.ChatGpt.ModelName, _gcs.Data.ChatGpt.ChatHistory, _gcs.Data.ChatGpt.MaxTokens, @@ -87,22 +76,21 @@ public class ChatterBotService : IExecOnMessage } } - public string PrepareMessage(IUserMessage msg, out IChatterBotSession cleverbot) + public IChatterBotSession GetOrCreateSession(ulong guildId) { - var channel = msg.Channel as ITextChannel; - cleverbot = null; + if (ChatterBotGuilds.TryGetValue(guildId, out var lazyChatBot)) + return lazyChatBot.Value; - if (channel is null) - return null; + lazyChatBot = new(() => CreateSession(), true); + ChatterBotGuilds.TryAdd(guildId, lazyChatBot); + return lazyChatBot.Value; + } - if (!ChatterBotGuilds.TryGetValue(channel.Guild.Id, out var lazyCleverbot)) - return null; - - cleverbot = lazyCleverbot.Value; - - var ellieId = _client.CurrentUser.Id; - var normalMention = $"<@{ellieId}> "; - var nickMention = $"<@!{ellieId}> "; + public string PrepareMessage(IUserMessage msg) + { + var nadekoId = _client.CurrentUser.Id; + var normalMention = $"<@{nadekoId}> "; + var nickMention = $"<@!{nadekoId}> "; string message; if (msg.Content.StartsWith(normalMention, StringComparison.InvariantCulture)) message = msg.Content[normalMention.Length..].Trim(); @@ -119,13 +107,31 @@ public class ChatterBotService : IExecOnMessage if (guild is not SocketGuild sg) return false; + var channel = usrMsg.Channel as ITextChannel; + if (channel is null) + return false; + + if (!ChatterBotGuilds.TryGetValue(channel.Guild.Id, out var lazyChatBot)) + return false; + + var chatBot = lazyChatBot.Value; + var message = PrepareMessage(usrMsg); + if (message is null) + return false; + + return await RunChatterBot(sg, usrMsg, channel, chatBot, message); + } + + public async Task RunChatterBot( + SocketGuild guild, + IUserMessage usrMsg, + ITextChannel channel, + IChatterBotSession chatBot, + string message) + { try { - var message = PrepareMessage(usrMsg, out var cbs); - if (message is null || cbs is null) - return false; - - var res = await _perms.CheckPermsAsync(sg, + var res = await _perms.CheckPermsAsync(guild, usrMsg.Channel, usrMsg.Author, CleverBotResponseStr.CLEVERBOT_RESPONSE, @@ -134,59 +140,33 @@ public class ChatterBotService : IExecOnMessage if (!res.IsAllowed) return false; - var channel = (ITextChannel)usrMsg.Channel; - var conf = _ps.GetConfig(); - if (!_creds.IsOwner(sg.OwnerId) && conf.IsEnabled) + if (!await _ps.LimitHitAsync(LimitedFeatureName.ChatBot, usrMsg.Author.Id, 2048 / 2)) { - var quota = await _ps.TryGetFeatureLimitAsync(_flKey, sg.OwnerId, 0); - - uint? daily = quota.Quota is int dVal and < 0 - ? (uint)-dVal - : null; - - uint? monthly = quota.Quota is int mVal and >= 0 - ? (uint)mVal - : null; - - var maybeLimit = await _ps.TryIncrementQuotaCounterAsync(sg.OwnerId, - sg.OwnerId == usrMsg.Author.Id, - FeatureType.Limit, - _flKey.Key, - null, - daily, - monthly); - - if (maybeLimit.TryPickT1(out var ql, out var counters)) - { - if (ql.Quota == 0) - { - await _sender.Response(channel) - .Error(null, - text: - "In order to use the cleverbot feature, the owner of this server should be [Patron Tier X](https://patreon.com/join/elliebot) on patreon.", - footer: - "You may disable the cleverbot feature, and this message via '.cleverbot' command") - .SendAsync(); - - return true; - } - - await _sender.Response(channel) - .Error( - null!, - $"You've reached your quota limit of **{ql.Quota}** responses {ql.QuotaPeriod.ToFullName()} for the cleverbot feature.", - footer: "You may wait for the quota reset or .") - .SendAsync(); - - return true; - } + // limit exceeded + return false; } _ = channel.TriggerTypingAsync(); - var response = await cbs.Think(message, usrMsg.Author.ToString()); - await _sender.Response(channel) - .Confirm(response) - .SendAsync(); + var response = await chatBot.Think(message, usrMsg.Author.ToString()); + + if (response.TryPickT0(out var result, out var error)) + { + // calculate the diff in case we overestimated user's usage + var inTokens = (result.TokensIn - 2048) / 2; + + // add the output tokens to the limit + await _ps.LimitForceHit(LimitedFeatureName.ChatBot, + usrMsg.Author.Id, + (inTokens) + (result.TokensOut / 2 * 3)); + + await _sender.Response(channel) + .Confirm(result.Text) + .SendAsync(); + } + else + { + Log.Warning("Error in chatterbot: {Error}", error); + } Log.Information(""" CleverBot Executed diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs index ad8692a..e983338 100644 --- a/src/EllieBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs +++ b/src/EllieBot/Modules/Games/ChatterBot/_common/Gpt3Response.cs @@ -3,10 +3,25 @@ using System.Text.Json.Serialization; namespace EllieBot.Modules.Games.Common.ChatterBot; -public class Gpt3Response +public class OpenAiCompletionResponse { [JsonPropertyName("choices")] public Choice[] Choices { get; set; } + + [JsonPropertyName("usage")] + public OpenAiUsageData Usage { get; set; } +} + +public class OpenAiUsageData +{ + [JsonPropertyName("prompt_tokens")] + public int PromptTokens { get; set; } + + [JsonPropertyName("completion_tokens")] + public int CompletionTokens { get; set; } + + [JsonPropertyName("total_tokens")] + public int TotalTokens { get; set; } } public class Choice diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs index 847d661..0372c87 100644 --- a/src/EllieBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs +++ b/src/EllieBot/Modules/Games/ChatterBot/_common/IChatterBotSession.cs @@ -1,7 +1,10 @@ #nullable disable +using OneOf; +using OneOf.Types; + namespace EllieBot.Modules.Games.Common.ChatterBot; public interface IChatterBotSession { - Task Think(string input, string username); + Task>> Think(string input, string username); } \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs index 83dc060..b20f1d0 100644 --- a/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs +++ b/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialCleverbotSession.cs @@ -1,5 +1,7 @@ #nullable disable using Newtonsoft.Json; +using OneOf; +using OneOf.Types; namespace EllieBot.Modules.Games.Common.ChatterBot; @@ -18,7 +20,7 @@ public class OfficialCleverbotSession : IChatterBotSession _httpFactory = factory; } - public async Task Think(string input, string username) + public async Task>> Think(string input, string username) { using var http = _httpFactory.CreateClient(); var dataString = await http.GetStringAsync(string.Format(QueryString, input, cs ?? "")); @@ -27,12 +29,17 @@ public class OfficialCleverbotSession : IChatterBotSession var data = JsonConvert.DeserializeObject(dataString); cs = data?.Cs; - return data?.Output; + return new ThinkResult + { + Text = data?.Output, + TokensIn = 2, + TokensOut = 1 + }; } catch { - Log.Warning("Unexpected cleverbot response received: {ResponseString}", dataString); - return null; + Log.Warning("Unexpected response from CleverBot: {ResponseString}", dataString); + return new Error("Unexpected CleverBot response received"); } } } \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs deleted file mode 100644 index 4711fd6..0000000 --- a/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGpt3Session.cs +++ /dev/null @@ -1,105 +0,0 @@ -#nullable disable -using Newtonsoft.Json; -using System.Net.Http.Json; -using SharpToken; - -namespace EllieBot.Modules.Games.Common.ChatterBot; - -public class OfficialGpt3Session : IChatterBotSession -{ - private string Uri - => $"https://api.openai.com/v1/chat/completions"; - - private readonly string _apiKey; - private readonly string _model; - private readonly int _maxHistory; - private readonly int _maxTokens; - private readonly int _minTokens; - private readonly string _ellieUsername; - private readonly GptEncoding _encoding; - private List messages = new(); - private readonly IHttpClientFactory _httpFactory; - - - - public OfficialGpt3Session( - string apiKey, - ChatGptModel model, - int chatHistory, - int maxTokens, - int minTokens, - string personality, - string ellieUsername, - IHttpClientFactory factory) - { - _apiKey = apiKey; - _httpFactory = factory; - switch (model) - { - case ChatGptModel.Gpt35Turbo: - _model = "gpt-3.5-turbo"; - break; - case ChatGptModel.Gpt4: - _model = "gpt-4"; - break; - case ChatGptModel.Gpt432k: - _model = "gpt-4-32k"; - break; - } - _maxHistory = chatHistory; - _maxTokens = maxTokens; - _minTokens = minTokens; - _ellieUsername = ellieUsername; - _encoding = GptEncoding.GetEncodingForModel(_model); - messages.Add(new GPTMessage(){Role = "user", Content = personality, Name = _ellieUsername}); - } - - public async Task Think(string input, string username) - { - messages.Add(new GPTMessage(){Role = "user", Content = input, Name = username}); - while(messages.Count > _maxHistory + 2){ - messages.RemoveAt(1); - } - int tokensUsed = 0; - foreach(GPTMessage message in messages){ - tokensUsed += _encoding.Encode(message.Content).Count; - } - tokensUsed *= 2; //Unsure why this is the case, but the token count chatgpt reports back is double what I calculate. - //check if we have the minimum number of tokens available to use. Remove messages until we have enough, otherwise exit out and inform the user why. - while(_maxTokens - tokensUsed <= _minTokens){ - if(messages.Count > 2){ - int tokens = _encoding.Encode(messages[1].Content).Count * 2; - tokensUsed -= tokens; - messages.RemoveAt(1); - } - else{ - return "Token count exceeded, please increase the number of tokens in the bot config and restart."; - } - } - using var http = _httpFactory.CreateClient(); - http.DefaultRequestHeaders.Authorization = new("Bearer", _apiKey); - var data = await http.PostAsJsonAsync(Uri, new Gpt3ApiRequest() - { - Model = _model, - Messages = messages, - MaxTokens = _maxTokens - tokensUsed, - Temperature = 1, - }); - var dataString = await data.Content.ReadAsStringAsync(); - try - { - var response = JsonConvert.DeserializeObject(dataString); - string message = response?.Choices[0]?.Message?.Content; - //Can't rely on the return to except, now that we need to add it to the messages list. - _ = message ?? throw new ArgumentNullException(nameof(message)); - messages.Add(new GPTMessage(){Role = "assistant", Content = message, Name = _ellieUsername}); - return message; - } - catch - { - Log.Warning("Unexpected GPT-3 response received: {ResponseString}", dataString); - return null; - } - } -} - diff --git a/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGptSession.cs b/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGptSession.cs new file mode 100644 index 0000000..4f7d35a --- /dev/null +++ b/src/EllieBot/Modules/Games/ChatterBot/_common/OfficialGptSession.cs @@ -0,0 +1,141 @@ +#nullable disable +using Newtonsoft.Json; +using OneOf.Types; +using System.Net.Http.Json; +using SharpToken; + +namespace EllieBot.Modules.Games.Common.ChatterBot; + +public class OfficialGptSession : IChatterBotSession +{ + private string Uri + => $"https://api.openai.com/v1/chat/completions"; + + private readonly string _apiKey; + private readonly string _model; + private readonly int _maxHistory; + private readonly int _maxTokens; + private readonly int _minTokens; + private readonly string _nadekoUsername; + private readonly GptEncoding _encoding; + private List messages = new(); + private readonly IHttpClientFactory _httpFactory; + + + public OfficialGptSession( + string apiKey, + ChatGptModel model, + int chatHistory, + int maxTokens, + int minTokens, + string personality, + string nadekoUsername, + IHttpClientFactory factory) + { + _apiKey = apiKey; + _httpFactory = factory; + + _model = model switch + { + ChatGptModel.Gpt35Turbo => "gpt-3.5-turbo", + ChatGptModel.Gpt4o => "gpt-4o", + _ => throw new ArgumentException("Unknown, unsupported or obsolete model", nameof(model)) + }; + + _maxHistory = chatHistory; + _maxTokens = maxTokens; + _minTokens = minTokens; + _nadekoUsername = nadekoUsername; + _encoding = GptEncoding.GetEncodingForModel(_model); + messages.Add(new() + { + Role = "system", + Content = personality, + Name = _nadekoUsername + }); + } + + public async Task>> Think(string input, string username) + { + messages.Add(new() + { + Role = "user", + Content = input, + Name = username + }); + while (messages.Count > _maxHistory + 2) + { + messages.RemoveAt(1); + } + + var tokensUsed = messages.Sum(message => _encoding.Encode(message.Content).Count); + + tokensUsed *= 2; + + //check if we have the minimum number of tokens available to use. Remove messages until we have enough, otherwise exit out and inform the user why. + while (_maxTokens - tokensUsed <= _minTokens) + { + if (messages.Count > 2) + { + var tokens = _encoding.Encode(messages[1].Content).Count * 2; + tokensUsed -= tokens; + messages.RemoveAt(1); + } + else + { + return new Error("Token count exceeded, please increase the number of tokens in the bot config and restart."); + } + } + + using var http = _httpFactory.CreateClient(); + http.DefaultRequestHeaders.Authorization = new("Bearer", _apiKey); + + var data = await http.PostAsJsonAsync(Uri, + new Gpt3ApiRequest() + { + Model = _model, + Messages = messages, + MaxTokens = _maxTokens - tokensUsed, + Temperature = 1, + }); + + var dataString = await data.Content.ReadAsStringAsync(); + try + { + var response = JsonConvert.DeserializeObject(dataString); + var res = response?.Choices?[0]; + var message = res?.Message?.Content; + + if (message is null) + { + return new Error("ChatGpt: Received no response."); + } + + messages.Add(new() + { + Role = "assistant", + Content = message, + Name = _nadekoUsername + }); + + return new ThinkResult() + { + Text = message, + TokensIn = response.Usage.PromptTokens, + TokensOut = response.Usage.CompletionTokens + }; + } + catch + { + Log.Warning("Unexpected response received from OpenAI: {ResponseString}", dataString); + return new Error("Unexpected response received"); + } + } +} + +public sealed class ThinkResult +{ + public string Text { get; set; } + public int TokensIn { get; set; } + public int TokensOut { get; set; } +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/GamesConfig.cs b/src/EllieBot/Modules/Games/GamesConfig.cs index 1502c39..e56cc70 100644 --- a/src/EllieBot/Modules/Games/GamesConfig.cs +++ b/src/EllieBot/Modules/Games/GamesConfig.cs @@ -8,7 +8,7 @@ namespace EllieBot.Modules.Games.Common; public sealed partial class GamesConfig : ICloneable { [Comment("DO NOT CHANGE")] - public int Version { get; set; } = 3; + public int Version { get; set; } = 4; [Comment("Hangman related settings (.hangman command)")] public HangmanConfig Hangman { get; set; } = new() @@ -105,8 +105,8 @@ public sealed partial class GamesConfig : ICloneable [Comment(@"Which chatbot API should bot use. 'cleverbot' - bot will use Cleverbot API. -'gpt3' - bot will use GPT-3 API")] - public ChatBotImplementation ChatBot { get; set; } = ChatBotImplementation.Gpt3; +'gpt' - bot will use GPT API")] + public ChatBotImplementation ChatBot { get; set; } = ChatBotImplementation.Gpt; public ChatGptConfig ChatGpt { get; set; } = new(); } @@ -114,10 +114,10 @@ public sealed partial class GamesConfig : ICloneable [Cloneable] public sealed partial class ChatGptConfig { - [Comment(@"Which GPT-3 Model should bot use. + [Comment(@"Which GPT Model should bot use. gpt35turbo - cheapest - gpt4 - 30x more expensive, higher quality - gp432k - same model as above, but with a 32k token limit")] + gpt4o - more expensive, higher quality +")] public ChatGptModel ModelName { get; set; } = ChatGptModel.Gpt35Turbo; [Comment(@"How should the chat bot behave, what's its personality? (Usage of this counts towards the max tokens)")] @@ -126,10 +126,10 @@ public sealed partial class ChatGptConfig [Comment(@"The maximum number of messages in a conversation that can be remembered. (This will increase the number of tokens used)")] public int ChatHistory { get; set; } = 5; - [Comment(@"The maximum number of tokens to use per GPT-3 API call")] + [Comment(@"The maximum number of tokens to use per GPT API call")] public int MaxTokens { get; set; } = 100; - [Comment(@"The minimum number of tokens to use per GPT-3 API call, such that chat history is removed to make room.")] + [Comment(@"The minimum number of tokens to use per GPT API call, such that chat history is removed to make room.")] public int MinTokens { get; set; } = 30; } @@ -163,12 +163,18 @@ public sealed partial class RaceAnimal public enum ChatBotImplementation { Cleverbot, - Gpt3 + Gpt = 1, + [Obsolete] + Gpt3 = 1, } public enum ChatGptModel { - Gpt35Turbo, + [Obsolete] Gpt4, - Gpt432k + [Obsolete] + Gpt432k, + + Gpt35Turbo, + Gpt4o, } \ No newline at end of file diff --git a/src/EllieBot/Modules/Games/GamesConfigService.cs b/src/EllieBot/Modules/Games/GamesConfigService.cs index 6446c23..06b75c3 100644 --- a/src/EllieBot/Modules/Games/GamesConfigService.cs +++ b/src/EllieBot/Modules/Games/GamesConfigService.cs @@ -73,15 +73,6 @@ public sealed class GamesConfigService : ConfigServiceBase }); } - if (data.Version < 2) - { - ModifyConfig(c => - { - c.Version = 2; - c.ChatBot = ChatBotImplementation.Cleverbot; - }); - } - if (data.Version < 3) { ModifyConfig(c => @@ -90,5 +81,19 @@ public sealed class GamesConfigService : ConfigServiceBase c.ChatGpt.ModelName = ChatGptModel.Gpt35Turbo; }); } + + if (data.Version < 4) + { + ModifyConfig(c => + { + c.Version = 4; +#pragma warning disable CS0612 // Type or member is obsolete + c.ChatGpt.ModelName = + c.ChatGpt.ModelName == ChatGptModel.Gpt4 || c.ChatGpt.ModelName == ChatGptModel.Gpt432k + ? ChatGptModel.Gpt4o + : c.ChatGpt.ModelName; +#pragma warning restore CS0612 // Type or member is obsolete + }); + } } } \ No newline at end of file From 00f8c70de0379b1e52a369bb58364a5324bc30a9 Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 16:49:50 +1200 Subject: [PATCH 16/25] Updated Marmalades module --- .../{Marmalade => Marmalades}/IMarmaladesRepositoryService.cs | 0 src/EllieBot/Modules/{Marmalade => Marmalades}/Marmalade.cs | 0 .../{Marmalade/MarmaladeItem.cs => Marmalades/MarmaladesItem.cs} | 0 .../{Marmalade => Marmalades}/MarmaladesRepositoryService.cs | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/EllieBot/Modules/{Marmalade => Marmalades}/IMarmaladesRepositoryService.cs (100%) rename src/EllieBot/Modules/{Marmalade => Marmalades}/Marmalade.cs (100%) rename src/EllieBot/Modules/{Marmalade/MarmaladeItem.cs => Marmalades/MarmaladesItem.cs} (100%) rename src/EllieBot/Modules/{Marmalade => Marmalades}/MarmaladesRepositoryService.cs (100%) diff --git a/src/EllieBot/Modules/Marmalade/IMarmaladesRepositoryService.cs b/src/EllieBot/Modules/Marmalades/IMarmaladesRepositoryService.cs similarity index 100% rename from src/EllieBot/Modules/Marmalade/IMarmaladesRepositoryService.cs rename to src/EllieBot/Modules/Marmalades/IMarmaladesRepositoryService.cs diff --git a/src/EllieBot/Modules/Marmalade/Marmalade.cs b/src/EllieBot/Modules/Marmalades/Marmalade.cs similarity index 100% rename from src/EllieBot/Modules/Marmalade/Marmalade.cs rename to src/EllieBot/Modules/Marmalades/Marmalade.cs diff --git a/src/EllieBot/Modules/Marmalade/MarmaladeItem.cs b/src/EllieBot/Modules/Marmalades/MarmaladesItem.cs similarity index 100% rename from src/EllieBot/Modules/Marmalade/MarmaladeItem.cs rename to src/EllieBot/Modules/Marmalades/MarmaladesItem.cs diff --git a/src/EllieBot/Modules/Marmalade/MarmaladesRepositoryService.cs b/src/EllieBot/Modules/Marmalades/MarmaladesRepositoryService.cs similarity index 100% rename from src/EllieBot/Modules/Marmalade/MarmaladesRepositoryService.cs rename to src/EllieBot/Modules/Marmalades/MarmaladesRepositoryService.cs From eb1ebc72dbeb7dcdc17edc236f44a6bdf923f304 Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 17:14:55 +1200 Subject: [PATCH 17/25] Updated Expressions module --- .../Modules/Expressions/EllieExpressionExtensions.cs | 2 +- src/EllieBot/Modules/Expressions/EllieExpressions.cs | 2 +- .../Modules/Expressions/EllieExpressionsService.cs | 12 ++++++------ src/EllieBot/Modules/Expressions/ExportedExpr.cs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/EllieBot/Modules/Expressions/EllieExpressionExtensions.cs b/src/EllieBot/Modules/Expressions/EllieExpressionExtensions.cs index 72606a7..0eeb68d 100644 --- a/src/EllieBot/Modules/Expressions/EllieExpressionExtensions.cs +++ b/src/EllieBot/Modules/Expressions/EllieExpressionExtensions.cs @@ -42,7 +42,7 @@ public static class EllieExpressionExtensions () => canMentionEveryone ? ctx.Content[substringIndex..].Trim() : ctx.Content[substringIndex..].Trim().SanitizeMentions(true)); - + var text = SmartText.CreateFrom(cr.Response); text = await repSvc.ReplaceAsync(text, repCtx); diff --git a/src/EllieBot/Modules/Expressions/EllieExpressions.cs b/src/EllieBot/Modules/Expressions/EllieExpressions.cs index 5def4f3..888901d 100644 --- a/src/EllieBot/Modules/Expressions/EllieExpressions.cs +++ b/src/EllieBot/Modules/Expressions/EllieExpressions.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Db.Models; namespace EllieBot.Modules.EllieExpressions; diff --git a/src/EllieBot/Modules/Expressions/EllieExpressionsService.cs b/src/EllieBot/Modules/Expressions/EllieExpressionsService.cs index 2f0b740..250c517 100644 --- a/src/EllieBot/Modules/Expressions/EllieExpressionsService.cs +++ b/src/EllieBot/Modules/Expressions/EllieExpressionsService.cs @@ -124,11 +124,11 @@ public sealed class EllieExpressionsService : IExecOnMessage, IReadyExecutor newguildExpressions = guildItems.GroupBy(k => k.GuildId!.Value) .ToDictionary(g => g.Key, g => g.Select(x => - { - x.Trigger = x.Trigger.Replace(MENTION_PH, - _client.CurrentUser.Mention); - return x; - }) + { + x.Trigger = x.Trigger.Replace(MENTION_PH, + _client.CurrentUser.Mention); + return x; + }) .ToArray()) .ToConcurrent(); @@ -259,7 +259,7 @@ public sealed class EllieExpressionsService : IExecOnMessage, IReadyExecutor "ACTUALEXPRESSIONS", expr.Trigger ); - + if (!result.IsAllowed) { var cache = _pc.GetCacheFor(guild.Id); diff --git a/src/EllieBot/Modules/Expressions/ExportedExpr.cs b/src/EllieBot/Modules/Expressions/ExportedExpr.cs index c45fbdc..581c884 100644 --- a/src/EllieBot/Modules/Expressions/ExportedExpr.cs +++ b/src/EllieBot/Modules/Expressions/ExportedExpr.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using EllieBot.Db.Models; namespace EllieBot.Modules.EllieExpressions; From b8fa164f8df99a06260fb5a217947bb021ffaa9e Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 18:23:14 +1200 Subject: [PATCH 18/25] Updated Administration module --- .../DangerousCommands/CleanupService.cs | 55 ++++++++++++++++++- .../Administration/Mute/MuteService.cs | 2 +- .../Administration/Prune/PruneCommands.cs | 36 ++++++++++-- .../Administration/Prune/PruneResult.cs | 9 +++ .../Administration/Prune/PruneService.cs | 23 ++++++-- .../Role/IReactionRoleService.cs | 2 +- .../Role/ReactionRoleCommands.cs | 6 +- .../Role/ReactionRolesService.cs | 23 ++++---- 8 files changed, 123 insertions(+), 33 deletions(-) create mode 100644 src/EllieBot/Modules/Administration/Prune/PruneResult.cs diff --git a/src/EllieBot/Modules/Administration/DangerousCommands/CleanupService.cs b/src/EllieBot/Modules/Administration/DangerousCommands/CleanupService.cs index 3555a61..b2dbf46 100644 --- a/src/EllieBot/Modules/Administration/DangerousCommands/CleanupService.cs +++ b/src/EllieBot/Modules/Administration/DangerousCommands/CleanupService.cs @@ -61,17 +61,66 @@ public sealed class CleanupService : ICleanupService, IReadyExecutor, IEService })); } + // delete guild configs await ctx.GetTable() .Where(x => !tempTable.Select(x => x.GuildId) .Contains(x.GuildId)) .DeleteAsync(); - - + + // delete guild xp await ctx.GetTable() .Where(x => !tempTable.Select(x => x.GuildId) .Contains(x.GuildId)) .DeleteAsync(); - + + // delete expressions + await ctx.GetTable() + .Where(x => x.GuildId != null && !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId.Value)) + .DeleteAsync(); + + // delete quotes + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + // delete planted currencies + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + // delete image only channels + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + // delete reaction roles + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + + // delete ignored users + await ctx.GetTable() + .Where(x => x.GuildId != null && !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId.Value)) + .DeleteAsync(); + + // delete perm overrides + await ctx.GetTable() + .Where(x => x.GuildId != null && !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId.Value)) + .DeleteAsync(); + + // delete repeaters + await ctx.GetTable() + .Where(x => !tempTable.Select(x => x.GuildId) + .Contains(x.GuildId)) + .DeleteAsync(); + return new() { GuildCount = guildIds.Keys.Count, diff --git a/src/EllieBot/Modules/Administration/Mute/MuteService.cs b/src/EllieBot/Modules/Administration/Mute/MuteService.cs index a3fbea3..df52c0c 100644 --- a/src/EllieBot/Modules/Administration/Mute/MuteService.cs +++ b/src/EllieBot/Modules/Administration/Mute/MuteService.cs @@ -293,7 +293,7 @@ public class MuteService : IEService { ArgumentNullException.ThrowIfNull(guild); - const string defaultMuteRoleName = "ellie-mute"; + const string defaultMuteRoleName = "nadeko-mute"; var muteRoleName = GuildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName); diff --git a/src/EllieBot/Modules/Administration/Prune/PruneCommands.cs b/src/EllieBot/Modules/Administration/Prune/PruneCommands.cs index 58b586e..2317bf0 100644 --- a/src/EllieBot/Modules/Administration/Prune/PruneCommands.cs +++ b/src/EllieBot/Modules/Administration/Prune/PruneCommands.cs @@ -45,23 +45,43 @@ public partial class Administration var progressMsg = await Response().Pending(strs.prune_progress(0, 100)).SendAsync(); var progress = GetProgressTracker(progressMsg); + PruneResult result; if (opts.Safe) - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, 100, x => x.Author.Id == user.Id && !x.IsPinned, progress, opts.After); else - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, 100, x => x.Author.Id == user.Id, progress, opts.After); ctx.Message.DeleteAfter(3); + + await SendResult(result); await progressMsg.DeleteAsync(); } + private async Task SendResult(PruneResult result) + { + switch (result) + { + case PruneResult.Success: + break; + case PruneResult.AlreadyRunning: + break; + case PruneResult.FeatureLimit: + await Response().Pending(strs.feature_limit_reached_owner).SendAsync(); + break; + + default: + throw new ArgumentOutOfRangeException(nameof(result), result, null); + } + } + // prune x [Cmd] [RequireContext(ContextType.Guild)] @@ -83,19 +103,21 @@ public partial class Administration var progressMsg = await Response().Pending(strs.prune_progress(0, count)).SendAsync(); var progress = GetProgressTracker(progressMsg); + PruneResult result; if (opts.Safe) - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, count, x => !x.IsPinned && x.Id != progressMsg.Id, progress, opts.After); else - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, count, x => x.Id != progressMsg.Id, progress, opts.After); + await SendResult(result); await progressMsg.DeleteAsync(); } @@ -155,9 +177,10 @@ public partial class Administration var progressMsg = await Response().Pending(strs.prune_progress(0, count)).SendAsync(); var progress = GetProgressTracker(progressMsg); + PruneResult result; if (opts.Safe) { - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, count, m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks && !m.IsPinned, progress, @@ -166,7 +189,7 @@ public partial class Administration } else { - await _service.PruneWhere((ITextChannel)ctx.Channel, + result = await _service.PruneWhere((ITextChannel)ctx.Channel, count, m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks, progress, @@ -174,6 +197,7 @@ public partial class Administration ); } + await SendResult(result); await progressMsg.DeleteAsync(); } diff --git a/src/EllieBot/Modules/Administration/Prune/PruneResult.cs b/src/EllieBot/Modules/Administration/Prune/PruneResult.cs new file mode 100644 index 0000000..b6ac515 --- /dev/null +++ b/src/EllieBot/Modules/Administration/Prune/PruneResult.cs @@ -0,0 +1,9 @@ +#nullable disable +namespace EllieBot.Modules.Administration.Services; + +public enum PruneResult +{ + Success, + AlreadyRunning, + FeatureLimit, +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Administration/Prune/PruneService.cs b/src/EllieBot/Modules/Administration/Prune/PruneService.cs index 006f9e8..753b56b 100644 --- a/src/EllieBot/Modules/Administration/Prune/PruneService.cs +++ b/src/EllieBot/Modules/Administration/Prune/PruneService.cs @@ -1,4 +1,6 @@ #nullable disable +using EllieBot.Modules.Patronage; + namespace EllieBot.Modules.Administration.Services; public class PruneService : IEService @@ -7,11 +9,15 @@ public class PruneService : IEService private readonly ConcurrentDictionary _pruningGuilds = new(); private readonly TimeSpan _twoWeeks = TimeSpan.FromDays(14); private readonly ILogCommandService _logService; + private readonly IPatronageService _ps; - public PruneService(ILogCommandService logService) - => _logService = logService; + public PruneService(ILogCommandService logService, IPatronageService ps) + { + _logService = logService; + _ps = ps; + } - public async Task PruneWhere( + public async Task PruneWhere( ITextChannel channel, int amount, Func predicate, @@ -26,8 +32,13 @@ public class PruneService : IEService using var cancelSource = new CancellationTokenSource(); if (!_pruningGuilds.TryAdd(channel.GuildId, cancelSource)) - return; + return PruneResult.AlreadyRunning; + if (!await _ps.LimitHitAsync(LimitedFeatureName.Prune, channel.Guild.OwnerId)) + { + return PruneResult.FeatureLimit; + } + try { var now = DateTime.UtcNow; @@ -47,7 +58,7 @@ public class PruneService : IEService .ToArray(); if (!msgs.Any()) - return; + return PruneResult.Success; lastMessage = msgs[^1]; @@ -88,6 +99,8 @@ public class PruneService : IEService { _pruningGuilds.TryRemove(channel.GuildId, out _); } + + return PruneResult.Success; } public async Task CancelAsync(ulong guildId) diff --git a/src/EllieBot/Modules/Administration/Role/IReactionRoleService.cs b/src/EllieBot/Modules/Administration/Role/IReactionRoleService.cs index 85f7945..771ceb0 100644 --- a/src/EllieBot/Modules/Administration/Role/IReactionRoleService.cs +++ b/src/EllieBot/Modules/Administration/Role/IReactionRoleService.cs @@ -18,7 +18,7 @@ public interface IReactionRoleService /// /// /// The result of the operation - Task> AddReactionRole( + Task> AddReactionRole( IGuild guild, IMessage msg, string emote, diff --git a/src/EllieBot/Modules/Administration/Role/ReactionRoleCommands.cs b/src/EllieBot/Modules/Administration/Role/ReactionRoleCommands.cs index 800512a..3a728ed 100644 --- a/src/EllieBot/Modules/Administration/Role/ReactionRoleCommands.cs +++ b/src/EllieBot/Modules/Administration/Role/ReactionRoleCommands.cs @@ -55,12 +55,10 @@ public partial class Administration await res.Match( _ => ctx.OkAsync(), - fl => + async fl => { _ = msg.RemoveReactionAsync(emote, ctx.Client.CurrentUser); - return !fl.IsPatronLimit - ? Response().Error(strs.limit_reached(fl.Quota)).SendAsync() - : Response().Pending(strs.feature_limit_reached_owner(fl.Quota, fl.Name)).SendAsync(); + await Response().Pending(strs.feature_limit_reached_owner).SendAsync(); }); } diff --git a/src/EllieBot/Modules/Administration/Role/ReactionRolesService.cs b/src/EllieBot/Modules/Administration/Role/ReactionRolesService.cs index f1216ef..cf36457 100644 --- a/src/EllieBot/Modules/Administration/Role/ReactionRolesService.cs +++ b/src/EllieBot/Modules/Administration/Role/ReactionRolesService.cs @@ -21,22 +21,16 @@ public sealed class ReactionRolesService : IReadyExecutor, IEService, IReactionR private readonly SemaphoreSlim _assignementLock = new(1, 1); private readonly IPatronageService _ps; - private static readonly FeatureLimitKey _reroFLKey = new() - { - Key = "rero:max_count", - PrettyName = "Reaction Role" - }; - public ReactionRolesService( DiscordSocketClient client, + IPatronageService ps, DbService db, - IBotCredentials creds, - IPatronageService ps) + IBotCredentials creds) { _db = db; - _ps = ps; _client = client; _creds = creds; + _ps = ps; _cache = new(); } @@ -242,7 +236,7 @@ public sealed class ReactionRolesService : IReadyExecutor, IEService, IReactionR /// /// /// The result of the operation - public async Task> AddReactionRole( + public async Task> AddReactionRole( IGuild guild, IMessage msg, string emote, @@ -261,9 +255,12 @@ public sealed class ReactionRolesService : IReadyExecutor, IEService, IReactionR .Where(x => x.GuildId == guild.Id) .CountAsync(); - var result = await _ps.TryGetFeatureLimitAsync(_reroFLKey, guild.OwnerId, 50); - if (result.Quota != -1 && activeReactionRoles >= result.Quota) - return result; + var limit = await _ps.GetUserLimit(LimitedFeatureName.ReactionRole, guild.OwnerId); + + if (!_creds.IsOwner(guild.OwnerId) && (activeReactionRoles >= limit.Quota && limit.Quota >= 0)) + { + return new Error(); + } await ctx.GetTable() .InsertOrUpdateAsync(() => new() From a976df554940963e119d67e534a04717b2c10f8e Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 18:25:07 +1200 Subject: [PATCH 19/25] Updated MuteService.cs --- src/EllieBot/Modules/Administration/Mute/MuteService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EllieBot/Modules/Administration/Mute/MuteService.cs b/src/EllieBot/Modules/Administration/Mute/MuteService.cs index df52c0c..a3fbea3 100644 --- a/src/EllieBot/Modules/Administration/Mute/MuteService.cs +++ b/src/EllieBot/Modules/Administration/Mute/MuteService.cs @@ -293,7 +293,7 @@ public class MuteService : IEService { ArgumentNullException.ThrowIfNull(guild); - const string defaultMuteRoleName = "nadeko-mute"; + const string defaultMuteRoleName = "ellie-mute"; var muteRoleName = GuildMuteRoles.GetOrAdd(guild.Id, defaultMuteRoleName); From fbff0282715ab34303ea901870eaa61db14ee3db Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 20:22:54 +1200 Subject: [PATCH 20/25] Updated Patronage module --- .../Patronage/Config/PatronageConfig.cs | 14 +- .../Patronage/CurrencyRewardService.cs | 47 +- .../Modules/Patronage/InsufficientTier.cs | 11 - .../Patronage/Patreon/PatreonClient.cs | 11 +- .../Patronage/Patreon/PatreonCredentials.cs | 2 +- .../Modules/Patronage/Patreon/PatreonData.cs | 2 +- .../Patronage/Patreon/PatreonMemberData.cs | 5 - .../Patreon/PatreonSubscriptionHandler.cs | 18 +- .../Modules/Patronage/PatronageCommands.cs | 58 +- .../Modules/Patronage/PatronageService.cs | 666 +++++------------- 10 files changed, 230 insertions(+), 604 deletions(-) delete mode 100644 src/EllieBot/Modules/Patronage/InsufficientTier.cs diff --git a/src/EllieBot/Modules/Patronage/Config/PatronageConfig.cs b/src/EllieBot/Modules/Patronage/Config/PatronageConfig.cs index 56f166f..254c3db 100644 --- a/src/EllieBot/Modules/Patronage/Config/PatronageConfig.cs +++ b/src/EllieBot/Modules/Patronage/Config/PatronageConfig.cs @@ -4,10 +4,11 @@ namespace EllieBot.Modules.Patronage; public class PatronageConfig : ConfigServiceBase { - public override string Name + public override string Name => "patron"; - private static readonly TypedKey _changeKey; + private static readonly TypedKey _changeKey + = new("config.patron.updated"); private const string FILE_PATH = "data/patron.yml"; @@ -31,5 +32,14 @@ public class PatronageConfig : ConfigServiceBase c.IsEnabled = false; } }); + + + ModifyConfig(c => + { + if (c.Version == 2) + { + c.Version = 3; + } + }); } } \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/CurrencyRewardService.cs b/src/EllieBot/Modules/Patronage/CurrencyRewardService.cs index 336fe9c..b61c646 100644 --- a/src/EllieBot/Modules/Patronage/CurrencyRewardService.cs +++ b/src/EllieBot/Modules/Patronage/CurrencyRewardService.cs @@ -1,6 +1,7 @@ #nullable disable using LinqToDB; using LinqToDB.EntityFrameworkCore; +using EllieBot.Common.ModuleBehaviors; using EllieBot.Modules.Gambling.Services; using EllieBot.Modules.Patronage; using EllieBot.Services.Currency; @@ -8,7 +9,7 @@ using EllieBot.Db.Models; namespace EllieBot.Modules.Utility; -public sealed class CurrencyRewardService : IEService, IDisposable +public sealed class CurrencyRewardService : IEService, IReadyExecutor { private readonly ICurrencyService _cs; private readonly IPatronageService _ps; @@ -32,16 +33,14 @@ public sealed class CurrencyRewardService : IEService, IDisposable _config = config; _client = client; + } + + public Task OnReadyAsync() + { _ps.OnNewPatronPayment += OnNewPayment; _ps.OnPatronRefunded += OnPatronRefund; _ps.OnPatronUpdated += OnPatronUpdate; - } - - public void Dispose() - { - _ps.OnNewPatronPayment -= OnNewPayment; - _ps.OnPatronRefunded -= OnPatronRefund; - _ps.OnPatronUpdated -= OnPatronUpdate; + return Task.CompletedTask; } private async Task OnPatronUpdate(Patron oldPatron, Patron newPatron) @@ -58,17 +57,17 @@ public sealed class CurrencyRewardService : IEService, IDisposable old = await ctx.GetTable() .Where(x => x.PlatformUserId == newPatron.UniquePlatformUserId) .FirstOrDefaultAsync(); - + if (old is null) { await OnNewPayment(newPatron); return; } - + // no action as the amount is the same or lower if (old.AmountRewardedThisMonth >= newAmount) return; - + var count = await ctx.GetTable() .Where(x => x.PlatformUserId == newPatron.UniquePlatformUserId) .UpdateAsync(_ => new() @@ -91,21 +90,21 @@ public sealed class CurrencyRewardService : IEService, IDisposable (int)(newAmount / conf.PatreonCurrencyPerCent), newAmount, out var percentBonus); - + var realOldAmount = GetRealCurrencyReward( (int)(oldAmount / conf.PatreonCurrencyPerCent), oldAmount, out _); - + var diff = realNewAmount - realOldAmount; if (diff <= 0) return; // no action if new is lower // if the user pledges 5$ or more, they will get X % more flowers where X is amount in dollars, // up to 100% - - await _cs.AddAsync(newPatron.UserId, diff, new TxData("patron", "update")); - + + await _cs.AddAsync(newPatron.UserId, diff, new TxData("patron","update")); + _ = SendMessageToUser(newPatron.UserId, $"You've received an additional **{diff}**{_config.Data.Currency.Sign} as a currency reward (+{percentBonus}%)!"); } @@ -140,12 +139,12 @@ public sealed class CurrencyRewardService : IEService, IDisposable await using var ctx = _db.GetDbContext(); await ctx.GetTable() .InsertOrUpdateAsync(() => new() - { - PlatformUserId = patron.UniquePlatformUserId, - UserId = patron.UserId, - AmountRewardedThisMonth = amount, - LastReward = patron.PaidAt, - }, + { + PlatformUserId = patron.UniquePlatformUserId, + UserId = patron.UserId, + AmountRewardedThisMonth = amount, + LastReward = patron.PaidAt, + }, old => new() { AmountRewardedThisMonth = amount, @@ -156,7 +155,7 @@ public sealed class CurrencyRewardService : IEService, IDisposable { PlatformUserId = patron.UniquePlatformUserId }); - + var realAmount = GetRealCurrencyReward(patron.Amount, amount, out var percentBonus); await _cs.AddAsync(patron.UserId, realAmount, new("patron", "new")); _ = SendMessageToUser(patron.UserId, @@ -174,7 +173,7 @@ public sealed class CurrencyRewardService : IEService, IDisposable var eb = _sender.CreateEmbed() .WithOkColor() .WithDescription(message); - + await _sender.Response(user).Embed(eb).SendAsync(); } catch diff --git a/src/EllieBot/Modules/Patronage/InsufficientTier.cs b/src/EllieBot/Modules/Patronage/InsufficientTier.cs deleted file mode 100644 index 26a0675..0000000 --- a/src/EllieBot/Modules/Patronage/InsufficientTier.cs +++ /dev/null @@ -1,11 +0,0 @@ -using EllieBot.Db.Models; - -namespace EllieBot.Modules.Patronage; - -public readonly struct InsufficientTier -{ - public FeatureType FeatureType { get; init; } - public string Feature { get; init; } - public PatronTier RequiredTier { get; init; } - public PatronTier UserTier { get; init; } -} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonClient.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonClient.cs index ad65448..2ac5820 100644 --- a/src/EllieBot/Modules/Patronage/Patreon/PatreonClient.cs +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonClient.cs @@ -11,11 +11,11 @@ public class PatreonClient : IDisposable private readonly string _clientId; private readonly string _clientSecret; private string refreshToken; - - + + private string accessToken = string.Empty; private readonly HttpClient _http; - + private DateTime refreshAt = DateTime.UtcNow; public PatreonClient(string clientId, string clientSecret, string refreshToken) @@ -101,7 +101,7 @@ public class PatreonClient : IDisposable return OneOf>, Error>.FromT0( GetMembersInternalAsync(campaignId)); } - + private async IAsyncEnumerable> GetMembersInternalAsync(string campaignId) { _http.DefaultRequestHeaders.Clear(); @@ -140,9 +140,8 @@ public class PatreonClient : IDisposable LastChargeDate = m.Attributes.LastChargeDate, LastChargeStatus = m.Attributes.LastChargeStatus }) - .Where(x => x.UserId == 140788173885276160) .ToArray(); - + yield return userData; } while (!string.IsNullOrWhiteSpace(page = data.Links?.Next)); diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonCredentials.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonCredentials.cs index 5eb6f1f..768a1f6 100644 --- a/src/EllieBot/Modules/Patronage/Patreon/PatreonCredentials.cs +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonCredentials.cs @@ -7,4 +7,4 @@ public readonly struct PatreonCredentials public string ClientSecret { get; init; } public string AccessToken { get; init; } public string RefreshToken { get; init; } -} +} \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonData.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonData.cs index f5d120e..6b33a80 100644 --- a/src/EllieBot/Modules/Patronage/Patreon/PatreonData.cs +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonData.cs @@ -1,4 +1,4 @@ -#nullable disable +#nullable disable using System.Text.Json.Serialization; namespace EllieBot.Modules.Patronage; diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonMemberData.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonMemberData.cs index 58656b9..4698b43 100644 --- a/src/EllieBot/Modules/Patronage/Patreon/PatreonMemberData.cs +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonMemberData.cs @@ -25,9 +25,4 @@ public sealed class PatreonMemberData : ISubscriberData "Declined" or "Pending" => SubscriptionChargeStatus.Unpaid, _ => SubscriptionChargeStatus.Other, }; -} - -public sealed class PatreonPledgeData -{ - } \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/Patreon/PatreonSubscriptionHandler.cs b/src/EllieBot/Modules/Patronage/Patreon/PatreonSubscriptionHandler.cs index 1fd170e..edc0f08 100644 --- a/src/EllieBot/Modules/Patronage/Patreon/PatreonSubscriptionHandler.cs +++ b/src/EllieBot/Modules/Patronage/Patreon/PatreonSubscriptionHandler.cs @@ -6,8 +6,8 @@ namespace EllieBot.Modules.Patronage; /// public sealed class PatreonSubscriptionHandler : ISubscriptionHandler, IEService { - private readonly IBotCredsProvider _credsProvider; - private readonly PatreonClient _patreonClient; + private readonly IBotCredsProvider _credsProvider; + private readonly PatreonClient _patreonClient; public PatreonSubscriptionHandler(IBotCredsProvider credsProvider) { @@ -15,26 +15,26 @@ public sealed class PatreonSubscriptionHandler : ISubscriptionHandler, IEService var botCreds = credsProvider.GetCreds(); _patreonClient = new PatreonClient(botCreds.Patreon.ClientId, botCreds.Patreon.ClientSecret, botCreds.Patreon.RefreshToken); } - + public async IAsyncEnumerable> GetPatronsAsync() { var botCreds = _credsProvider.GetCreds(); - + if (string.IsNullOrWhiteSpace(botCreds.Patreon.CampaignId) || string.IsNullOrWhiteSpace(botCreds.Patreon.ClientId) || string.IsNullOrWhiteSpace(botCreds.Patreon.ClientSecret) || string.IsNullOrWhiteSpace(botCreds.Patreon.RefreshToken)) yield break; - + var result = await _patreonClient.RefreshTokenAsync(false); if (!result.TryPickT0(out _, out var error)) { Log.Warning("Unable to refresh patreon token: {ErrorMessage}", error.Value); yield break; } - + var patreonCreds = _patreonClient.GetCredentials(); - + _credsProvider.ModifyCredsFile(c => { c.Patreon.AccessToken = patreonCreds.AccessToken; @@ -58,7 +58,7 @@ public sealed class PatreonSubscriptionHandler : ISubscriptionHandler, IEService Log.Warning(ex, "Unexpected error while refreshing patreon members: {ErroMessage}", ex.Message); - + yield break; } @@ -71,7 +71,7 @@ public sealed class PatreonSubscriptionHandler : ISubscriptionHandler, IEService && x.LastCharge is { } lc && lc.ToUniversalTime().ToDateOnly() >= firstOfThisMonth) .ToArray(); - + if (toReturn.Length > 0) yield return toReturn; } diff --git a/src/EllieBot/Modules/Patronage/PatronageCommands.cs b/src/EllieBot/Modules/Patronage/PatronageCommands.cs index 8d0a38a..fee2c33 100644 --- a/src/EllieBot/Modules/Patronage/PatronageCommands.cs +++ b/src/EllieBot/Modules/Patronage/PatronageCommands.cs @@ -71,17 +71,16 @@ public partial class Help return; } - var patron = await _service.GetPatronAsync(user.Id); - var quotaStats = await _service.GetUserQuotaStatistic(user.Id); + var maybePatron = await _service.GetPatronAsync(user.Id); + + var quotaStats = await _service.LimitStats(user.Id); var eb = _sender.CreateEmbed() .WithAuthor(user) .WithTitle(GetText(strs.patron_info)) .WithOkColor(); - if (quotaStats.Commands.Count == 0 - && quotaStats.Groups.Count == 0 - && quotaStats.Modules.Count == 0) + if (quotaStats.Count == 0 || maybePatron is not { } patron) { eb.WithDescription(GetText(strs.no_quota_found)); } @@ -97,26 +96,9 @@ public partial class Help eb.AddField(GetText(strs.quotas), "⁣", false); - if (quotaStats.Commands.Count > 0) - { - var text = GetQuotaList(quotaStats.Commands); - if (!string.IsNullOrWhiteSpace(text)) - eb.AddField(GetText(strs.commands), text, true); - } - - if (quotaStats.Groups.Count > 0) - { - var text = GetQuotaList(quotaStats.Groups); - if (!string.IsNullOrWhiteSpace(text)) - eb.AddField(GetText(strs.groups), text, true); - } - - if (quotaStats.Modules.Count > 0) - { - var text = GetQuotaList(quotaStats.Modules); - if (!string.IsNullOrWhiteSpace(text)) - eb.AddField(GetText(strs.modules), text, true); - } + var text = GetQuotaList(quotaStats); + if (!string.IsNullOrWhiteSpace(text)) + eb.AddField(GetText(strs.modules), text, true); } @@ -131,26 +113,28 @@ public partial class Help } } - private string GetQuotaList(IReadOnlyDictionary featureQuotaStats) + private string GetQuotaList( + IReadOnlyDictionary featureQuotaStats) { var text = string.Empty; - foreach (var (key, q) in featureQuotaStats) + foreach (var (key, (cur, quota)) in featureQuotaStats) { text += $"\n⁣\t`{key}`\n"; - if (q.Hourly != default) - text += $"⁣ ⁣ {GetEmoji(q.Hourly)} {q.Hourly.Cur}/{q.Hourly.Max} per hour\n"; - if (q.Daily != default) - text += $"⁣ ⁣ {GetEmoji(q.Daily)} {q.Daily.Cur}/{q.Daily.Max} per day\n"; - if (q.Monthly != default) - text += $"⁣ ⁣ {GetEmoji(q.Monthly)} {q.Monthly.Cur}/{q.Monthly.Max} per month\n"; + if (quota.QuotaPeriod == QuotaPer.PerHour) + text += $"⁣ ⁣ {cur}/{(quota.Quota == -1 ? "∞" : quota.Quota)} {QuotaPeriodToString(quota.QuotaPeriod)}\n"; } return text; } - private string GetEmoji((uint Cur, uint Max) limit) - => limit.Cur < limit.Max - ? "✅" - : "⚠️"; + public string QuotaPeriodToString(QuotaPer per) + => per switch + { + QuotaPer.PerHour => "per hour", + QuotaPer.PerDay => "per day", + QuotaPer.PerMonth => "per month", + QuotaPer.Total => "total", + _ => throw new ArgumentOutOfRangeException(nameof(per), per, null) + }; } } \ No newline at end of file diff --git a/src/EllieBot/Modules/Patronage/PatronageService.cs b/src/EllieBot/Modules/Patronage/PatronageService.cs index 3d5f62c..e6d7899 100644 --- a/src/EllieBot/Modules/Patronage/PatronageService.cs +++ b/src/EllieBot/Modules/Patronage/PatronageService.cs @@ -2,9 +2,8 @@ using LinqToDB.EntityFrameworkCore; using EllieBot.Common.ModuleBehaviors; using EllieBot.Db.Models; -using OneOf; -using OneOf.Types; -using CommandInfo = Discord.Commands.CommandInfo; +using StackExchange.Redis; +using System.Diagnostics; namespace EllieBot.Modules.Patronage; @@ -12,7 +11,6 @@ namespace EllieBot.Modules.Patronage; public sealed class PatronageService : IPatronageService, IReadyExecutor, - IExecPreCommand, IEService { public event Func OnNewPatronPayment = static delegate { return Task.CompletedTask; }; @@ -60,7 +58,7 @@ public sealed class PatronageService if (_client.ShardId != 0) return Task.CompletedTask; - return Task.WhenAll(ResetLoopAsync(), LoadSubscribersLoopAsync()); + return Task.WhenAll(LoadSubscribersLoopAsync()); } private async Task LoadSubscribersLoopAsync() @@ -85,71 +83,6 @@ public sealed class PatronageService } } - public async Task ResetLoopAsync() - { - await Task.Delay(1.Minutes()); - while (true) - { - try - { - if (!_pConf.Data.IsEnabled) - { - await Task.Delay(1.Minutes()); - continue; - } - - var now = DateTime.UtcNow; - var lastRun = DateTime.MinValue; - - var result = await _cache.GetAsync(_quotaKey); - if (result.TryGetValue(out var lastVal) && lastVal != default) - { - lastRun = DateTime.FromBinary(lastVal); - } - - var nowDate = now.ToDateOnly(); - var lastDate = lastRun.ToDateOnly(); - - await using var ctx = _db.GetDbContext(); - - if ((lastDate.Day == 1 || (lastDate.Month != nowDate.Month)) && nowDate.Day > 1) - { - // assumes bot won't be offline for a year - await ctx.GetTable() - .TruncateAsync(); - } - else if (nowDate.DayNumber != lastDate.DayNumber) - { - // day is different, means hour is different. - // reset both hourly and daily quota counts. - await ctx.GetTable() - .UpdateAsync((old) => new() - { - HourlyCount = 0, - DailyCount = 0, - }); - } - else if (now.Hour != lastRun.Hour) // if it's not, just reset hourly quotas - { - await ctx.GetTable() - .UpdateAsync((old) => new() - { - HourlyCount = 0 - }); - } - - // assumes that the code above runs in less than an hour - await _cache.AddAsync(_quotaKey, now.ToBinary()); - } - catch (Exception ex) - { - Log.Error(ex, "Error in quota reset loop. Message: {ErrorMessage}", ex.Message); - } - - await Task.Delay(TimeSpan.FromHours(1).Add(TimeSpan.FromMinutes(1))); - } - } - private async Task ProcesssPatronsAsync(IReadOnlyCollection subscribersEnum) { // process only users who have discord accounts connected @@ -203,7 +136,8 @@ public sealed class PatronageService // if his sub would end in teh future, extend it by one month. // if it's not, just add 1 month to the last charge date var count = await ctx.GetTable() - .Where(x => x.UniquePlatformUserId == subscriber.UniquePlatformUserId) + .Where(x => x.UniquePlatformUserId + == subscriber.UniquePlatformUserId) .UpdateAsync(old => new() { UserId = subscriber.UserId, @@ -215,14 +149,13 @@ public sealed class PatronageService : dateInOneMonth, }); - // this should never happen - if (count == 0) - { - // await tran.RollbackAsync(); - continue; - } - // await tran.CommitAsync(); + dbPatron.UserId = subscriber.UserId; + dbPatron.AmountCents = subscriber.Cents; + dbPatron.LastCharge = lastChargeUtc; + dbPatron.ValidThru = dbPatron.ValidThru >= todayDate + ? dbPatron.ValidThru.AddMonths(1) + : dateInOneMonth; await OnNewPatronPayment(PatronUserToPatron(dbPatron)); } @@ -284,313 +217,7 @@ public sealed class PatronageService } } - public async Task ExecPreCommandAsync( - ICommandContext ctx, - string moduleName, - CommandInfo command) - { - var ownerId = ctx.Guild?.OwnerId ?? 0; - - var result = await AttemptRunCommand( - ctx.User.Id, - ownerId: ownerId, - command.Aliases.First().ToLowerInvariant(), - command.Module.Parent == null ? string.Empty : command.Module.GetGroupName().ToLowerInvariant(), - moduleName.ToLowerInvariant() - ); - - return result.Match( - _ => false, - ins => - { - var eb = _sender.CreateEmbed() - .WithPendingColor() - .WithTitle("Insufficient Patron Tier") - .AddField("For", $"{ins.FeatureType}: `{ins.Feature}`", true) - .AddField("Required Tier", - $"[{ins.RequiredTier.ToFullName()}](https://patreon.com/join/elliebot)", - true); - - if (ctx.Guild is null || ctx.Guild?.OwnerId == ctx.User.Id) - eb.WithDescription("You don't have the sufficent Patron Tier to run this command.") - .WithFooter("You can use '.patron' and '.donate' commands for more info"); - else - eb.WithDescription( - "Neither you nor the server owner have the sufficent Patron Tier to run this command.") - .WithFooter("You can use '.patron' and '.donate' commands for more info"); - - _ = ctx.WarningAsync(); - - if (ctx.Guild?.OwnerId == ctx.User.Id) - _ = _sender.Response(ctx) - .Context(ctx) - .Embed(eb) - .SendAsync(); - else - _ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync(); - - return true; - }, - quota => - { - var eb = _sender.CreateEmbed() - .WithPendingColor() - .WithTitle("Quota Limit Reached"); - - if (quota.IsOwnQuota || ctx.User.Id == ownerId) - { - eb.WithDescription($"You've reached your quota of `{quota.Quota} {quota.QuotaPeriod.ToFullName()}`") - .WithFooter("You may want to check your quota by using the '.patron' command."); - } - else - { - eb.WithDescription( - $"This server reached the quota of {quota.Quota} `{quota.QuotaPeriod.ToFullName()}`") - .WithFooter("You may contact the server owner about this issue.\n" - + "Alternatively, you can become patron yourself by using the '.donate' command.\n" - + "If you're already a patron, it means you've reached your quota.\n" - + "You can use '.patron' command to check your quota status."); - } - - eb.AddField("For", $"{quota.FeatureType}: `{quota.Feature}`", true) - .AddField("Resets At", quota.ResetsAt.ToShortAndRelativeTimestampTag(), true); - - _ = ctx.WarningAsync(); - - // send the message in the server in case it's the owner - if (ctx.Guild?.OwnerId == ctx.User.Id) - _ = _sender.Response(ctx) - .Embed(eb) - .SendAsync(); - else - _ = _sender.Response(ctx).User(ctx.User).Embed(eb).SendAsync(); - - return true; - }); - } - - private async ValueTask> AttemptRunCommand( - ulong userId, - ulong ownerId, - string commandName, - string groupName, - string moduleName) - { - // try to run as a user - var res = await AttemptRunCommand(userId, commandName, groupName, moduleName, true); - - // if it fails, try to run as an owner - // but only if the command is ran in a server - // and if the owner is not the user - if (!res.IsT0 && ownerId != 0 && ownerId != userId) - res = await AttemptRunCommand(ownerId, commandName, groupName, moduleName, false); - - return res; - } - - /// - /// Returns either the current usage counter if limit wasn't reached, or QuotaLimit if it is. - /// - public async ValueTask> TryIncrementQuotaCounterAsync( - ulong userId, - bool isSelf, - FeatureType featureType, - string featureName, - uint? maybeHourly, - uint? maybeDaily, - uint? maybeMonthly) - { - await using var ctx = _db.GetDbContext(); - - var now = DateTime.UtcNow; - await using var tran = await ctx.Database.BeginTransactionAsync(); - - var userQuotaData = await ctx.GetTable() - .FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId - && x.Feature == featureName) - ?? new PatronQuota(); - - // if hourly exists, if daily exists, etc... - if (maybeHourly is uint hourly && userQuotaData.HourlyCount >= hourly) - { - return new QuotaLimit() - { - QuotaPeriod = QuotaPer.PerHour, - Quota = hourly, - // quite a neat trick. https://stackoverflow.com/a/5733560 - ResetsAt = now.Date.AddHours(now.Hour + 1), - Feature = featureName, - FeatureType = featureType, - IsOwnQuota = isSelf - }; - } - - if (maybeDaily is uint daily - && userQuotaData.DailyCount >= daily) - { - return new QuotaLimit() - { - QuotaPeriod = QuotaPer.PerDay, - Quota = daily, - ResetsAt = now.Date.AddDays(1), - Feature = featureName, - FeatureType = featureType, - IsOwnQuota = isSelf - }; - } - - if (maybeMonthly is uint monthly && userQuotaData.MonthlyCount >= monthly) - { - return new QuotaLimit() - { - QuotaPeriod = QuotaPer.PerMonth, - Quota = monthly, - ResetsAt = now.Date.SecondOfNextMonth(), - Feature = featureName, - FeatureType = featureType, - IsOwnQuota = isSelf - }; - } - - await ctx.GetTable() - .InsertOrUpdateAsync(() => new() - { - UserId = userId, - FeatureType = featureType, - Feature = featureName, - DailyCount = 1, - MonthlyCount = 1, - HourlyCount = 1, - }, - (old) => new() - { - HourlyCount = old.HourlyCount + 1, - DailyCount = old.DailyCount + 1, - MonthlyCount = old.MonthlyCount + 1, - }, - () => new() - { - UserId = userId, - FeatureType = featureType, - Feature = featureName, - }); - - await tran.CommitAsync(); - - return (userQuotaData.HourlyCount + 1, userQuotaData.DailyCount + 1, userQuotaData.MonthlyCount + 1); - } - - /// - /// Attempts to add 1 to user's quota for the command, group and module. - /// Input MUST BE lowercase - /// - /// Id of the user who is attempting to run the command - /// Name of the command the user is trying to run - /// Name of the command's group - /// Name of the command's top level module - /// Whether this is check is for the user himself. False if it's someone else's id (owner) - /// Either a succcess (user can run the command) or one of the error values. - private async ValueTask> AttemptRunCommand( - ulong userId, - string commandName, - string groupName, - string moduleName, - bool isSelf) - { - var confData = _pConf.Data; - - if (!confData.IsEnabled) - return default; - - if (_creds.GetCreds().IsOwner(userId)) - return default; - - // get user tier - var patron = await GetPatronAsync(userId); - FeatureType quotaForFeatureType; - - if (confData.Quotas.Commands.TryGetValue(commandName, out var quotaData)) - { - quotaForFeatureType = FeatureType.Command; - } - else if (confData.Quotas.Groups.TryGetValue(groupName, out quotaData)) - { - quotaForFeatureType = FeatureType.Group; - } - else if (confData.Quotas.Modules.TryGetValue(moduleName, out quotaData)) - { - quotaForFeatureType = FeatureType.Module; - } - else - { - return default; - } - - var featureName = quotaForFeatureType switch - { - FeatureType.Command => commandName, - FeatureType.Group => groupName, - FeatureType.Module => moduleName, - _ => throw new ArgumentOutOfRangeException(nameof(quotaForFeatureType)) - }; - - if (!TryGetTierDataOrLower(quotaData, patron.Tier, out var data)) - { - return new InsufficientTier() - { - Feature = featureName, - FeatureType = quotaForFeatureType, - RequiredTier = quotaData.Count == 0 - ? PatronTier.ComingSoon - : quotaData.Keys.First(), - UserTier = patron.Tier, - }; - } - - // no quota limits for this tier - if (data is null) - return default; - - var quotaCheckResult = await TryIncrementQuotaCounterAsync(userId, - isSelf, - quotaForFeatureType, - featureName, - data.TryGetValue(QuotaPer.PerHour, out var hourly) ? hourly : null, - data.TryGetValue(QuotaPer.PerDay, out var daily) ? daily : null, - data.TryGetValue(QuotaPer.PerMonth, out var monthly) ? monthly : null - ); - - return quotaCheckResult.Match>( - _ => new Success(), - x => x); - } - - private bool TryGetTierDataOrLower( - IReadOnlyDictionary data, - PatronTier tier, - out T? o) - { - // check for quotas on this tier - if (data.TryGetValue(tier, out o)) - return true; - - // if there are none, get the quota first tier below this one - // which has quotas specified - for (var i = _tiers.Length - 1; i >= 0; i--) - { - var lowerTier = _tiers[i]; - if (lowerTier < tier && data.TryGetValue(lowerTier, out o)) - return true; - } - - // if there are none, that means the feature is intended - // to be patron-only but the quotas haven't been specified yet - // so it will be marked as "Coming Soon" - o = default; - return false; - } - - public async Task GetPatronAsync(ulong userId) + public async Task GetPatronAsync(ulong userId) { await using var ctx = _db.GetDbContext(); @@ -616,128 +243,135 @@ public sealed class PatronageService return PatronUserToPatron(max); } - public async Task GetUserQuotaStatistic(ulong userId) + public async Task LimitHitAsync(LimitedFeatureName key, ulong userId, int amount = 1) { - var pConfData = _pConf.Data; + if (_creds.GetCreds().IsOwner(userId)) + return true; - if (!pConfData.IsEnabled) - return new(); + if (!_pConf.Data.IsEnabled) + return true; - var patron = await GetPatronAsync(userId); + var userLimit = await GetUserLimit(key, userId); - await using var ctx = _db.GetDbContext(); - var allPatronQuotas = await ctx.GetTable() - .Where(x => x.UserId == userId) - .ToListAsync(); + if (userLimit.Quota == 0) + return false; - var allQuotasDict = allPatronQuotas - .GroupBy(static x => x.FeatureType) - .ToDictionary(static x => x.Key, static x => x.ToDictionary(static y => y.Feature)); + if (userLimit.Quota == -1) + return true; - allQuotasDict.TryGetValue(FeatureType.Command, out var data); - var userCommandQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Commands); - - allQuotasDict.TryGetValue(FeatureType.Group, out data); - var userGroupQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Groups); - - allQuotasDict.TryGetValue(FeatureType.Module, out data); - var userModuleQuotaStats = GetFeatureQuotaStats(patron.Tier, data, pConfData.Quotas.Modules); - - return new UserQuotaStats() - { - Tier = patron.Tier, - Commands = userCommandQuotaStats, - Groups = userGroupQuotaStats, - Modules = userModuleQuotaStats, - }; + return await TryAddLimit(key, userLimit, userId, amount); } - private IReadOnlyDictionary GetFeatureQuotaStats( - PatronTier patronTier, - IReadOnlyDictionary? allQuotasDict, - Dictionary?>> commands) + public async Task LimitForceHit(LimitedFeatureName key, ulong userId, int amount) { - var userCommandQuotaStats = new Dictionary(); - foreach (var (key, quotaData) in commands) + if (_creds.GetCreds().IsOwner(userId)) + return true; + + if (!_pConf.Data.IsEnabled) + return true; + + var userLimit = await GetUserLimit(key, userId); + + var cacheKey = CreateKey(key, userId); + await _cache.GetOrAddAsync(cacheKey, () => Task.FromResult(0), GetExpiry(userLimit)); + + return await TryAddLimit(key, userLimit, userId, amount); + } + + private async Task TryAddLimit( + LimitedFeatureName key, + QuotaLimit userLimit, + ulong userId, + int amount) + { + var cacheKey = CreateKey(key, userId); + var cur = await _cache.GetOrAddAsync(cacheKey, () => Task.FromResult(0), GetExpiry(userLimit)); + + if (cur + amount < userLimit.Quota) { - if (TryGetTierDataOrLower(quotaData, patronTier, out var data)) + await _cache.AddAsync(cacheKey, cur + amount); + return true; + } + + return false; + } + + private TimeSpan? GetExpiry(QuotaLimit userLimit) + { + var now = DateTime.UtcNow; + switch (userLimit.QuotaPeriod) + { + case QuotaPer.PerHour: + return TimeSpan.FromMinutes(60 - now.Minute); + case QuotaPer.PerDay: + return TimeSpan.FromMinutes((24 * 60) - ((now.Hour * 60) + now.Minute)); + case QuotaPer.PerMonth: + var firstOfNextMonth = now.FirstOfNextMonth(); + return firstOfNextMonth - now; + default: + return null; + } + } + + private TypedKey CreateKey(LimitedFeatureName key, ulong userId) + => new($"limited_feature:{key}:{userId}"); + + private readonly QuotaLimit _emptyQuota = new QuotaLimit() + { + Quota = 0, + QuotaPeriod = QuotaPer.PerDay, + }; + + private readonly QuotaLimit _infiniteQuota = new QuotaLimit() + { + Quota = -1, + QuotaPeriod = QuotaPer.PerDay, + }; + + public async Task GetUserLimit(LimitedFeatureName name, ulong userId) + { + if (!_pConf.Data.IsEnabled) + return _infiniteQuota; + + var maybePatron = await GetPatronAsync(userId); + + if (maybePatron is not { } patron) + return _emptyQuota; + + if (patron.ValidThru < DateTime.UtcNow) + return _emptyQuota; + + foreach (var (key, value) in _pConf.Data.Limits) + { + if (patron.Amount >= key) { - // if data is null that means the quota for the user's tier is unlimited - // no point in returning it? - - if (data is null) - continue; - - var (daily, hourly, monthly) = default((uint, uint, uint)); - // try to get users stats for this feature - // if it fails just leave them at 0 - if (allQuotasDict?.TryGetValue(key, out var quota) ?? false) - (daily, hourly, monthly) = (quota.DailyCount, quota.HourlyCount, quota.MonthlyCount); - - userCommandQuotaStats[key] = new FeatureQuotaStats() + if (value.TryGetValue(name, out var quotaLimit)) { - Hourly = data.TryGetValue(QuotaPer.PerHour, out var hourD) - ? (hourly, hourD) - : default, - Daily = data.TryGetValue(QuotaPer.PerDay, out var maxD) - ? (daily, maxD) - : default, - Monthly = data.TryGetValue(QuotaPer.PerMonth, out var maxM) - ? (monthly, maxM) - : default, - }; + return quotaLimit; + } + + break; } } - return userCommandQuotaStats; + return _emptyQuota; } - public async Task TryGetFeatureLimitAsync(FeatureLimitKey key, ulong userId, int? defaultValue) + public async Task> LimitStats(ulong userId) { - var conf = _pConf.Data; - - // if patron system is disabled, the quota is just default - if (!conf.IsEnabled) - return new() - { - Name = key.PrettyName, - Quota = defaultValue, - IsPatronLimit = false - }; - - - if (!conf.Quotas.Features.TryGetValue(key.Key, out var data)) - return new() - { - Name = key.PrettyName, - Quota = defaultValue, - IsPatronLimit = false, - }; - - var patron = await GetPatronAsync(userId); - if (!TryGetTierDataOrLower(data, patron.Tier, out var limit)) - return new() - { - Name = key.PrettyName, - Quota = 0, - IsPatronLimit = true, - }; - - return new() + var dict = new Dictionary(); + foreach (var featureName in Enum.GetValues()) { - Name = key.PrettyName, - Quota = limit, - IsPatronLimit = true - }; + var cacheKey = CreateKey(featureName, userId); + var userLimit = await GetUserLimit(featureName, userId); + var cur = await _cache.GetOrAddAsync(cacheKey, () => Task.FromResult(0), GetExpiry(userLimit)); + + dict[featureName] = (cur, userLimit); + } + + return dict; } - // public async Task GiftPatronAsync(IUser user, int amount) - // { - // if (amount < 1) - // throw new ArgumentOutOfRangeException(nameof(amount)); - // - // - // } private Patron PatronUserToPatron(PatronUser user) => new Patron() @@ -767,6 +401,22 @@ public sealed class PatronageService }; } + public int PercentBonus(Patron? maybePatron) + => maybePatron is { } user && user.ValidThru > DateTime.UtcNow + ? PercentBonus(user.Amount) + : 0; + + public int PercentBonus(long amount) + => amount switch + { + >= 10_000 => 100, + >= 5000 => 50, + >= 2000 => 20, + >= 1000 => 10, + >= 500 => 5, + _ => 0 + }; + private async Task SendWelcomeMessage(Patron patron) { try @@ -776,28 +426,28 @@ public sealed class PatronageService return; var eb = _sender.CreateEmbed() - .WithOkColor() - .WithTitle("❤️ Thank you for supporting EllieBot! ❤️") - .WithDescription( - "Your donation has been processed and you will receive the rewards shortly.\n" - + "You can visit to see rewards for your tier. 🎉") - .AddField("Tier", Format.Bold(patron.Tier.ToString()), true) - .AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true) - .AddField("Expires", - patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(), - true) - .AddField("Instructions", - """ - *- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.* - *- You can check your benefits on * - *- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands* - *- **ALL** of the servers that you **own** will enjoy your Patron benefits.* - *- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)* - *- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Ellie's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.* - *- Permission guide can be found here if you're not familiar with it: * - """, - inline: false) - .WithFooter($"platform id: {patron.UniquePlatformUserId}"); + .WithOkColor() + .WithTitle("❤️ Thank you for supporting EllieBot! ❤️") + .WithDescription( + "Your donation has been processed and you will receive the rewards shortly.\n" + + "You can visit to see rewards for your tier. 🎉") + .AddField("Tier", Format.Bold(patron.Tier.ToString()), true) + .AddField("Pledge", $"**{patron.Amount / 100.0f:N1}$**", true) + .AddField("Expires", + patron.ValidThru.AddDays(1).ToShortAndRelativeTimestampTag(), + true) + .AddField("Instructions", + """ + *- Within the next **1-2 minutes** you will have all of the benefits of the Tier you've subscribed to.* + *- You can check your benefits on * + *- You can use the `.patron` command in this chat to check your current quota usage for the Patron-only commands* + *- **ALL** of the servers that you **own** will enjoy your Patron benefits.* + *- You can use any of the commands available in your tier on any server (assuming you have sufficient permissions to run those commands)* + *- Any user in any of your servers can use Patron-only commands, but they will spend **your quota**, which is why it's recommended to use Ellie's command cooldown system (.h .cmdcd) or permission system to limit the command usage for your server members.* + *- Permission guide can be found here if you're not familiar with it: * + """, + inline: false) + .WithFooter($"platform id: {patron.UniquePlatformUserId}"); await _sender.Response(user).Embed(eb).SendAsync(); } From a9576e5aa13c86ef1322619136b2d193dce57d42 Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 21:06:48 +1200 Subject: [PATCH 21/25] Updated CheckForUpdatesService.cs --- .../Modules/Administration/Self/CheckForUpdatesService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/EllieBot/Modules/Administration/Self/CheckForUpdatesService.cs b/src/EllieBot/Modules/Administration/Self/CheckForUpdatesService.cs index c037aeb..66cac5b 100644 --- a/src/EllieBot/Modules/Administration/Self/CheckForUpdatesService.cs +++ b/src/EllieBot/Modules/Administration/Self/CheckForUpdatesService.cs @@ -19,7 +19,7 @@ public sealed class CheckForUpdatesService : IEService, IReadyExecutor private readonly IMessageSenderService _sender; - private const string RELEASES_URL = "https://toastielab.dev/api/v1/repos/Emotions-stuff/EllieBot/releases"; + private const string RELEASES_URL = "https://toastielab.dev/api/v1/repos/Emotions-stuff/elliebot/releases"; public CheckForUpdatesService( BotConfigService bcs, @@ -72,7 +72,7 @@ public sealed class CheckForUpdatesService : IEService, IReadyExecutor UpdateLastKnownVersion(latestVersion); // pull changelog - var changelog = await http.GetStringAsync("https://toastielab.dev/Emotions-stuff/Ellie/raw/branch/v5/CHANGELOG.md"); + var changelog = await http.GetStringAsync("https://toastielab.dev/Emotions-stuff/elliebot/raw/branch/v5/CHANGELOG.md"); var thisVersionChangelog = GetVersionChangelog(latestVersion, changelog); @@ -95,7 +95,7 @@ public sealed class CheckForUpdatesService : IEService, IReadyExecutor .WithOkColor() .WithAuthor($"EllieBot v{latest} Released!") .WithTitle("Changelog") - .WithUrl("https://toastielab.dev/Emotions-stuff/Ellie/src/branch/v5/CHANGELOG.md") + .WithUrl("https://toastielab.dev/Emotions-stuff/elliebot/src/branch/v5/CHANGELOG.md") .WithDescription(thisVersionChangelog.TrimTo(4096)) .WithFooter( "You may disable these messages by typing '.conf bot checkforupdates false'"); From b7b8366fe2cdd1ee1c4f1463bb9d4f99a5a97038 Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 21:07:29 +1200 Subject: [PATCH 22/25] Updated Xp module --- src/EllieBot/Modules/Xp/Xp.cs | 1 + src/EllieBot/Modules/Xp/XpService.cs | 17 ++++++++++------- .../Modules/Xp/_common/db/XpShopOwnedItem.cs | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/EllieBot/Modules/Xp/Xp.cs b/src/EllieBot/Modules/Xp/Xp.cs index 2bf8fcb..a667be4 100644 --- a/src/EllieBot/Modules/Xp/Xp.cs +++ b/src/EllieBot/Modules/Xp/Xp.cs @@ -2,6 +2,7 @@ using EllieBot.Modules.Xp.Services; using EllieBot.Db.Models; using EllieBot.Modules.Patronage; +using EllieBot.Modules.Utility; namespace EllieBot.Modules.Xp; diff --git a/src/EllieBot/Modules/Xp/XpService.cs b/src/EllieBot/Modules/Xp/XpService.cs index 97d349a..6df1151 100644 --- a/src/EllieBot/Modules/Xp/XpService.cs +++ b/src/EllieBot/Modules/Xp/XpService.cs @@ -668,7 +668,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand /// private async Task ScanUserForVoiceXp(SocketGuildUser user, SocketVoiceChannel channel) { - if (UserParticipatingInVoiceChannel(user) && ShouldTrackXp(user, channel.Id)) + if (UserParticipatingInVoiceChannel(user) && ShouldTrackXp(user, channel)) await UserJoinedVoiceChannel(user); else await UserLeftVoiceChannel(user, channel); @@ -767,9 +767,12 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand } */ - private bool ShouldTrackXp(SocketGuildUser user, ulong channelId) + private bool ShouldTrackXp(SocketGuildUser user, IMessageChannel channel) { - if (_excludedChannels.TryGetValue(user.Guild.Id, out var chans) && chans.Contains(channelId)) + var channelId = channel.Id; + + if (_excludedChannels.TryGetValue(user.Guild.Id, out var chans) && (chans.Contains(channelId) + || (channel is SocketThreadChannel tc && chans.Contains(tc.ParentChannel.Id)))) return false; if (_excludedServers.Contains(user.Guild.Id)) @@ -788,7 +791,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand _ = Task.Run(async () => { - if (!ShouldTrackXp(user, arg.Channel.Id)) + if (!ShouldTrackXp(user, arg.Channel)) return; var xpConf = _xpConfig.Data; @@ -1286,9 +1289,9 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand Image? frame = null; if (item is null) { - if (patron.Tier == PatronTier.V) + if (patron?.Tier == PatronTier.V) frame = Image.Load(File.OpenRead("data/images/frame_silver.png")); - else if (patron.Tier >= PatronTier.X || _creds.IsOwner(userId)) + else if (patron?.Tier >= PatronTier.X || _creds.IsOwner(userId)) frame = Image.Load(File.OpenRead("data/images/frame_gold.png")); } else @@ -1465,7 +1468,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand { var patron = await _ps.GetPatronAsync(userId); - if ((int)patron.Tier < (int)req) + if (patron is null || (int)patron.Value.Tier < (int)req) return BuyResult.InsufficientPatronTier; } diff --git a/src/EllieBot/Modules/Xp/_common/db/XpShopOwnedItem.cs b/src/EllieBot/Modules/Xp/_common/db/XpShopOwnedItem.cs index 29b491e..955e17d 100644 --- a/src/EllieBot/Modules/Xp/_common/db/XpShopOwnedItem.cs +++ b/src/EllieBot/Modules/Xp/_common/db/XpShopOwnedItem.cs @@ -1,4 +1,4 @@ -#nullable disable warnings +#nullable disable warnings namespace EllieBot.Db.Models; public class XpShopOwnedItem : DbEntity From df56c76a89346aecf05bdeafd312b6f01c6bfc21 Mon Sep 17 00:00:00 2001 From: Toastie Date: Thu, 27 Jun 2024 21:08:15 +1200 Subject: [PATCH 23/25] Updated Help module --- src/EllieBot/Modules/Help/Help.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EllieBot/Modules/Help/Help.cs b/src/EllieBot/Modules/Help/Help.cs index 79367b9..4f9e916 100644 --- a/src/EllieBot/Modules/Help/Help.cs +++ b/src/EllieBot/Modules/Help/Help.cs @@ -524,7 +524,7 @@ public sealed partial class Help : EllieModule => smc.RespondConfirmAsync(_sender, """ - In case you don't want or cannot Donate to EllieBot project, but you - - EllieBot is a free and [open source](https://toastielab.dev/Emotions-stuff/Ellie) project which means you can run your own "selfhosted" instance on your computer. + - EllieBot is a free and [open source](https://toastielab.dev/Emotions-stuff/elliebot) project which means you can run your own "selfhosted" instance on your computer. *Keep in mind that running the bot on your computer means that the bot will be offline when you turn off your computer* From eab5344c61be538c4de358cd6f3ff7b25fa73bbb Mon Sep 17 00:00:00 2001 From: Toastie Date: Fri, 28 Jun 2024 15:16:12 +1200 Subject: [PATCH 24/25] Updated Services\Impl files --- src/EllieBot/Services/Impl/BotCredsProvider.cs | 6 ++++++ src/EllieBot/Services/Impl/RedisBotCache.cs | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/EllieBot/Services/Impl/BotCredsProvider.cs b/src/EllieBot/Services/Impl/BotCredsProvider.cs index 3d2638e..5d2b480 100644 --- a/src/EllieBot/Services/Impl/BotCredsProvider.cs +++ b/src/EllieBot/Services/Impl/BotCredsProvider.cs @@ -191,6 +191,12 @@ public sealed class BotCredsProvider : IBotCredsProvider creds.Version = 7; File.WriteAllText(CREDS_FILE_NAME, Yaml.Serializer.Serialize(creds)); } + + if (creds.Version <= 7) + { + creds.Version = 8; + File.WriteAllText(CREDS_FILE_NAME, Yaml.Serializer.Serialize(creds)); + } } } diff --git a/src/EllieBot/Services/Impl/RedisBotCache.cs b/src/EllieBot/Services/Impl/RedisBotCache.cs index fffc727..259b820 100644 --- a/src/EllieBot/Services/Impl/RedisBotCache.cs +++ b/src/EllieBot/Services/Impl/RedisBotCache.cs @@ -3,6 +3,7 @@ using OneOf.Types; using StackExchange.Redis; using System.Text.Json; using System.Text.Json.Serialization; +using YamlDotNet.Core.Tokens; namespace EllieBot.Common; @@ -47,6 +48,7 @@ public sealed class RedisBotCache : IBotCache var success = await db.StringSetAsync(key.Key, val, expiry: expiry, + keepTtl: true, when: overwrite ? When.Always : When.NotExists); return success; From 657805d51cdf6125d73295387c57ed79ca7dab1b Mon Sep 17 00:00:00 2001 From: Toastie Date: Fri, 28 Jun 2024 15:19:37 +1200 Subject: [PATCH 25/25] Updated changelog, version upped to 5.1.0 --- CHANGELOG.md | 34 +++++++++ src/EllieBot/EllieBot.csproj | 136 +++++++++++++++++------------------ 2 files changed, 102 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75f3a41..f47a812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,40 @@ Mostly based on [keepachangelog](https://keepachangelog.com/en/1.0.0/) except date format. a-c-f-r-o +## [5.1.0] - 28.06.2024 + +### Added + +- Added `'prompt` command, Ellie Ai Assistant + - You can send natural language questions, queries or execute commands. For example "@Ellie how's the weather in paris" and it will return `'we Paris` and run it for you. + - In case the bot can't execute a command using your query, It will fall back to your chatter bot, in case you have it enabled in data/games.yml. (Cleverbot or chatgpt) + - (It's far from perfect so please don't ask the bot to do dangerous things like banning or pruning) + - Requires Patreon subscription, after which you'll be able to run it on global @Ellie bot. If you're selfhosting, you also will need to acquire the api key from (coming soon(ish)...) +- Added support for `gpt-4o` in `data/games.yml` +- Added EllieAiToken to `creds.yml` + + +### Changed + +- Remind will now show a timestamp tag for durations +- Only `Gpt35Turbo` and `Gpt4o` are valid inputs in games.yml now +- `data/patron.yml` changed. It now has limits. The entire feature limit system has been reworked. Your previous settings will be reset +- A lot of updates to bot strings (thanks Ene) +- Improved cleanup command to delete a lot more data once cleanup is ran, not only guild configs (please don't use this command unless you have your database bakced up and you know 100% what you're doing) + +### Fixed + +- Fixed xp bg buy button not working, and possibly some other buttons too +- Fixed shopbuy %user% placeholders and updated help text +- All 'feed overloads should now work" +- `'xpexclude` should will now work with forums too. If you exclude a forum you won't be able to gain xp in any of the threads. +- Fixed remind not showing correct time (thx cata) + +### Removed + +- Removed PoE related commands +- dev: Removed patron quota data from the database, it will now be stored in redis + ## [5.0.8] - 19.06.2024 ### Added diff --git a/src/EllieBot/EllieBot.csproj b/src/EllieBot/EllieBot.csproj index 2c605d4..01dd661 100644 --- a/src/EllieBot/EllieBot.csproj +++ b/src/EllieBot/EllieBot.csproj @@ -4,7 +4,7 @@ enable true en - 5.0.8 + 5.1.0 $(MSBuildProjectDirectory) @@ -22,88 +22,88 @@ - - - all - True - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + all + True + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - - - + + + - - + + - - - - - - - + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + + - + - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - + - - - + + + - + - - + + - - + + - + - +