├── .gitignore ├── LICENSE ├── NinjaBotCore.sln ├── README.md ├── appveyor.yml ├── media ├── guildstats.PNG ├── logsc.png ├── rpi.PNG ├── set-guild.PNG ├── set-guildc.png ├── watch-dis.PNG └── watch-en.PNG ├── src ├── Attributes │ ├── DoUserCheckAttribute.cs │ └── RequireOwnerAttribute.cs ├── Common │ ├── IApiRequestorThrottle.cs │ ├── IWclApiRequestor.cs │ └── IWowApi.cs ├── Database │ ├── AchCategory.cs │ ├── AuctionItemMapping.cs │ ├── AwaySystem.cs │ ├── Blacklist.cs │ ├── C8Ball.cs │ ├── ChannelOutput.cs │ ├── CharStats.cs │ ├── CurrentRaidTier.cs │ ├── DiscordServer.cs │ ├── FindWowCheeve.cs │ ├── Giphy.cs │ ├── LogMonitoring.cs │ ├── NinjaBotEntities.cs │ ├── NinjaBotEntitiesFactory.cs │ ├── Note.cs │ ├── PrefixList.cs │ ├── QuestionAnswer.cs │ ├── Request.cs │ ├── RlStat.cs │ ├── RlUserStat.cs │ ├── ServerGreeting.cs │ ├── ServerSetting.cs │ ├── TriviaCategory.cs │ ├── TriviaQuestion.cs │ ├── TriviaQuestionChoice.cs │ ├── Warnings.cs │ ├── WclPosted.cs │ ├── WordList.cs │ ├── WowAuctionPrice.cs │ ├── WowAuctions.cs │ ├── WowClassicGuild.cs │ ├── WowGuildAssociation.cs │ ├── WowMChar.cs │ ├── WowResources.cs │ └── WowVanillaGuild.cs ├── Models │ ├── Google │ │ └── GeocodeResponse.cs │ ├── Steam │ │ └── SteamModel.cs │ ├── Wow │ │ ├── ApiResponse.cs │ │ ├── AuctionList.cs │ │ ├── AuctionsModel.cs │ │ ├── Character.cs │ │ ├── FightTables.cs │ │ ├── FoundChar.cs │ │ ├── GuildMembers.cs │ │ ├── ItemComparison.cs │ │ ├── ItemInfo.cs │ │ ├── LogsReports.cs │ │ ├── NinjaObjects.cs │ │ ├── ProgressGuildRank.cs │ │ ├── RaiderIOModels.cs │ │ ├── WarcraftlogsRankings.cs │ │ ├── WowConnnectedRealm.cs │ │ ├── WowItems.cs │ │ ├── WowRealmResponseGuild.cs │ │ ├── WowRealmSearch.cs │ │ ├── WowRealms.cs │ │ ├── WowSingleRealmInfo.cs │ │ └── WowStats.cs │ └── YouTube │ │ └── YouTube.cs ├── Modules │ ├── Admin │ │ └── UserInteractions.cs │ ├── Audio │ │ └── Audio.cs │ ├── AwaySystem │ │ └── AwayData.cs │ ├── Interactions │ │ ├── Admin │ │ │ └── Admin.cs │ │ ├── Misc │ │ │ ├── AwayCommands.cs │ │ │ └── FunCommands.cs │ │ ├── Wow │ │ │ ├── WowAdminInteract.cs │ │ │ ├── WowClassicInteract.cs │ │ │ ├── WowInteract.cs │ │ │ └── WowVanillaInteract.cs │ │ └── YouTube │ │ │ └── YouTubeCommands.cs │ ├── Steam │ │ └── SteamApi.cs │ ├── Wow │ │ ├── ApiRequestorThrottle.cs │ │ ├── RaiderIOApi.cs │ │ ├── RoseCommands.cs │ │ ├── WarcraftLogs.cs │ │ ├── WclApiRequestor.cs │ │ ├── WowApi.cs │ │ ├── WowProgress.cs │ │ └── WowUtilities.cs │ └── YouTube │ │ └── YouTubeApi.cs ├── NinjaBot.cs ├── NinjaBotCore.csproj ├── Program.cs └── Services │ ├── AudioService.cs │ ├── ChannelCheck.cs │ ├── CommandHandler.cs │ ├── InteractionHandler.cs │ ├── LoggingService.cs │ ├── NinjaExtensions.cs │ └── StartupService.cs └── test └── NinjaBotCore.Tests ├── NinjaBotCore.Tests.csproj └── WowUtilitiesTests.cs /.gitignore: -------------------------------------------------------------------------------- 1 | #Ignore json files 2 | *.json 3 | 4 | #Ignore build folders 5 | /bin/ 6 | bin/ 7 | obj/ 8 | /obj/ 9 | Migrations/ 10 | /Migrations/ 11 | 12 | #Ignore db/log files 13 | *.db* 14 | *.db3 15 | *.log 16 | 17 | #Ignore scripts/txt files 18 | *.ps1 19 | *.txt 20 | 21 | #Ignore vscode folders 22 | /.vscode/ 23 | /.vs/ 24 | 25 | config.json.save 26 | .DS_Store 27 | ninjabot.db-journal 28 | 29 | 30 | #Ignore misc files 31 | *.dll 32 | *.exe 33 | *.mp3 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mike Roberts 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NinjaBotCore.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NinjaBotCore", "src\NinjaBotCore.csproj", "{89385036-B0FC-400A-92EB-78E40343052D}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{31932E90-75BA-497C-8275-88D7DED0D86F}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NinjaBotCore.Tests", "test\NinjaBotCore.Tests\NinjaBotCore.Tests.csproj", "{B6C6DFF6-EC1A-4160-8244-1D0010E1194A}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {89385036-B0FC-400A-92EB-78E40343052D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {89385036-B0FC-400A-92EB-78E40343052D}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {89385036-B0FC-400A-92EB-78E40343052D}.Debug|x64.ActiveCfg = Debug|Any CPU 28 | {89385036-B0FC-400A-92EB-78E40343052D}.Debug|x64.Build.0 = Debug|Any CPU 29 | {89385036-B0FC-400A-92EB-78E40343052D}.Debug|x86.ActiveCfg = Debug|Any CPU 30 | {89385036-B0FC-400A-92EB-78E40343052D}.Debug|x86.Build.0 = Debug|Any CPU 31 | {89385036-B0FC-400A-92EB-78E40343052D}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {89385036-B0FC-400A-92EB-78E40343052D}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {89385036-B0FC-400A-92EB-78E40343052D}.Release|x64.ActiveCfg = Release|Any CPU 34 | {89385036-B0FC-400A-92EB-78E40343052D}.Release|x64.Build.0 = Release|Any CPU 35 | {89385036-B0FC-400A-92EB-78E40343052D}.Release|x86.ActiveCfg = Release|Any CPU 36 | {89385036-B0FC-400A-92EB-78E40343052D}.Release|x86.Build.0 = Release|Any CPU 37 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Debug|x64.ActiveCfg = Debug|Any CPU 40 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Debug|x64.Build.0 = Debug|Any CPU 41 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Debug|x86.ActiveCfg = Debug|Any CPU 42 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Debug|x86.Build.0 = Debug|Any CPU 43 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Release|x64.ActiveCfg = Release|Any CPU 46 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Release|x64.Build.0 = Release|Any CPU 47 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Release|x86.ActiveCfg = Release|Any CPU 48 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A}.Release|x86.Build.0 = Release|Any CPU 49 | EndGlobalSection 50 | GlobalSection(NestedProjects) = preSolution 51 | {B6C6DFF6-EC1A-4160-8244-1D0010E1194A} = {31932E90-75BA-497C-8275-88D7DED0D86F} 52 | EndGlobalSection 53 | EndGlobal 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![NinjaBot](https://static1.squarespace.com/static/5644323de4b07810c0b6db7b/5939edfbf7e0abe61afd8b9c/5940bca7e58c6299ddc2119a/1497420130867/botdiscord.png?format=300w)](https://gngr.ninja/bot) 2 | 3 | # NinjaBot 4 | [![Build status](https://ci.appveyor.com/api/projects/status/9r20viaa3r2i9ksf?svg=true)](https://ci.appveyor.com/project/gngrninja/ninjabotcore) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 5 | 6 | NinjaBot is a Discord bot written in C#. 7 | 8 | Its primary focus was to help out guilds in World of Warcraft. 9 | I will be shifting to more administrative / Discord tasks for the time being as I am no longer actively playing World of Warcraft. 10 | 11 | This project has been an awesome way for me to learn C#, feel free to toss in a pull request if there's a better way to do something! 12 | 13 | **10.2.x updates coming soon** 14 | 15 | ## Getting Started 16 | The first thing you'll need to do is [invite the bot to your server](https://discord.com/api/oauth2/authorize?client_id=238495040446398467&permissions=377960909888&scope=bot%20applications.commands). 17 | It will need permissions to read and post messages at the very minimum. 18 | If you wish to use NinjaBot to assist with admin tasks (kicking/banning users, message management, etc), [please use this link](https://discord.com/api/oauth2/authorize?client_id=238495040446398467&permissions=1494652415174&scope=bot%20applications.commands). 19 | 20 | ### Slash commands 21 | This bot is now using [slash commands](https://discord.com/blog/slash-commands-permissions-discord-apps-bots), be sure to use the updated invites above to invite it to your discord server. 22 | If it is already on your server, you may need to ensure users can use the commands: 23 | ``` 24 | Go to Server Settings → Integrations, and then 'Manage' (next to NinjaBot). 25 | ``` 26 | 27 | There are a limited number of classic WoW commands now available. You can associate your guild, and watch/get logs from Warcraft logs. 28 | Currently there is no way to get classic armory or guild information via the API, and I'll be watching to see when/if things get added! 29 | 30 | More information on the bot and getting started [here](https://www.gngrninja.com/bot). 31 | 32 | ### Associating your guild (Retail WoW) 33 | Associating a WoW guild with your Discord server allows you to use the Warcraft Logs watching command, as well as some autocomplete features for guild member names when using various WoW commands. 34 | 35 | To associate your guild with NinjaBot, use the following command: 36 | ``` 37 | /setguild realmName, guildName, region 38 | ``` 39 | Here are some examples of using the command: 40 | ### US (also the default if no region is specified) 41 | ``` 42 | /setguild Blackwater Raiders, Raiders of the Lost Ark, us 43 | ``` 44 | ### EU 45 | ``` 46 | /setguild Silvermoon, Rome in a Day, eu 47 | ``` 48 | ### RU 49 | ``` 50 | /setguild Ревущий фьорд, Порейдим месяц, ru 51 | ``` 52 | 53 | ### Associating your guild (Classic WoW) 54 | 55 | To associate your classic WoW guild with NinjaBot, use the following command: 56 | ``` 57 | /setclassicguild "guild name" "realm" "region" 58 | ``` 59 | 60 | Valid regions: 61 | US, EU, KR, TW, and CN 62 | 63 | NinjaBot will associate what you enter as the guild attached to your server. That data will then be used to watch / retrieve logs from Warcraft Logs. 64 | 65 | Example: 66 | ### US (also the default if no region is specified) 67 | ``` 68 | /setclassicguild "Disorder" "Rattlegore" 69 | ``` 70 | ## WoW Commands 71 | 72 | ### [Warcraft Logs](https://www.warcraftlogs.com) Auto Log Poster (Retail and Classic) 73 | 74 | To use the auto log poster, use this command in the channel you want them automatically posted to: 75 | ``` 76 | /watchlogs 77 | ``` 78 | 79 | You can use the same exact command to disable the auto log posting, and then use it again to enable it (in the channel you want them posted to). 80 | 81 | ### [Warcraft Logs](https://www.warcraftlogs.com) Last Three Logs 82 | 83 | To get the last three of your guild's logs, use: 84 | 85 | ``` 86 | /logs 87 | ``` 88 | 89 | ### [Warcraft Logs](https://www.warcraftlogs.com) Last Three Logs (Classic WoW) 90 | 91 | To get the last three of your guild's logs, use: 92 | 93 | ``` 94 | /logsclassic 95 | ``` 96 | 97 | ### World of Warcraft Commands 98 | 99 | ### [Raider.IO](https://www.raider.io) Player Information Lookup 100 | 101 | Command 102 | Help: 103 | 104 | ``` 105 | /rio 106 | ``` 107 | 108 | Try to find character (first in guild, then best guess) 109 | ``` 110 | /rio characterName 111 | ``` 112 | 113 | Long form version to try to find someone not in the same region 114 | ``` 115 | /rio characterName realmName region(us or eu) 116 | ``` 117 | 118 | ### [Raider.IO](https://www.raider.io) Guild Information 119 | 120 | ``` 121 | /ginfo 122 | ``` 123 | 124 | ## Server Enhancement Commands 125 | 126 | NinjaBot can greet people joining the server, and notify the server when someone leaves. The messages the bot uses are customizable. 127 | 128 | ### Greetings: 129 | 130 | In the channel you'd like to have the greetings in (this will either enable or disable, as a toggle): 131 | ``` 132 | /toggle-greetings 133 | ``` 134 | 135 | If greetings are enabled, and you'd like to set a different channel to handle leaving/parting messages, use (in the channel you want it to be): 136 | 137 | ``` 138 | /set-parting-channel 139 | ``` 140 | 141 | When setting greetings, you can use emojis the bot has access to. For example, you can use :joy:, and it will translate to 😂. 142 | 143 | If you'd like to link to a specific channel, you'd use: 144 | ``` 145 | Please check out this channel for information: <#channel-id-here> 146 | ``` 147 | (to get the ID, just right click a text channel and click "**Copy Channel ID**") 148 | 149 | To change the greeting message, use: 150 | 151 | ``` 152 | /set-join-message 153 | ``` 154 | 155 | To change the leaving/parting message, use: 156 | ``` 157 | /set-part-message 158 | ``` 159 | 160 | ### Server wide note 161 | 162 | Server members with kick permissions and above can set a server wide note via: 163 | 164 | ``` 165 | /set-note 166 | ``` 167 | 168 | Anyone in the server can retrieve the note via: 169 | 170 | ``` 171 | /get-note 172 | ``` 173 | 174 | (note: updating the website in the mere future!) 175 | Visit the [NinjaBot website](https://www.gngrninja.com/ninjabot-command-reference/2017/6/13/admin-commands) for more information. 176 | 177 | ## Help! 178 | 179 | If you're having trouble using any of the WoW commands, the first thing to try is re-associating your WoW guild with your Discord server. 180 | If that doesn't help, check out the following resources below: 181 | 182 | [Discord Chat](https://discord.gg/MgvJuaV) 183 | 184 | [NinjaBot Website](https://www.gngrninja.com/bot) 185 | 186 | Feel free to open an issue here for any bugs or problems you come across! 187 | 188 | Enjoy. -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | #Build configuration 2 | os: Visual Studio 2022 3 | before_build: 4 | - dotnet --info 5 | - dotnet restore 6 | # build platform, i.e. x86, x64, Any CPU. This setting is optional. 7 | platform: Any CPU 8 | # build Configuration, i.e. Debug, Release, etc. 9 | configuration: Debug 10 | -------------------------------------------------------------------------------- /media/guildstats.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gngrninja/NinjaBotCore/f869759589c48da910572f193d7b05c107f3728f/media/guildstats.PNG -------------------------------------------------------------------------------- /media/logsc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gngrninja/NinjaBotCore/f869759589c48da910572f193d7b05c107f3728f/media/logsc.png -------------------------------------------------------------------------------- /media/rpi.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gngrninja/NinjaBotCore/f869759589c48da910572f193d7b05c107f3728f/media/rpi.PNG -------------------------------------------------------------------------------- /media/set-guild.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gngrninja/NinjaBotCore/f869759589c48da910572f193d7b05c107f3728f/media/set-guild.PNG -------------------------------------------------------------------------------- /media/set-guildc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gngrninja/NinjaBotCore/f869759589c48da910572f193d7b05c107f3728f/media/set-guildc.png -------------------------------------------------------------------------------- /media/watch-dis.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gngrninja/NinjaBotCore/f869759589c48da910572f193d7b05c107f3728f/media/watch-dis.PNG -------------------------------------------------------------------------------- /media/watch-en.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gngrninja/NinjaBotCore/f869759589c48da910572f193d7b05c107f3728f/media/watch-en.PNG -------------------------------------------------------------------------------- /src/Attributes/DoUserCheckAttribute.cs: -------------------------------------------------------------------------------- 1 | using Discord; 2 | using Discord.Interactions; 3 | using Discord.WebSocket; 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | namespace NinjaBotCore.Attributes 8 | { 9 | internal class DoUserCheck : PreconditionAttribute 10 | { 11 | public override Task CheckRequirementsAsync(IInteractionContext context, ICommandInfo commandInfo, IServiceProvider services) 12 | { 13 | // Check if the component matches the target properly. 14 | if (context.Interaction is not SocketMessageComponent componentContext) 15 | return Task.FromResult(PreconditionResult.FromError("Context unrecognized as component context.")); 16 | 17 | else 18 | { 19 | // The approach here entirely depends on how you construct your custom ID. In this case, the format is: 20 | // unique-name:*,* 21 | 22 | // here the name and wildcards are split by ':' 23 | var param = componentContext.Data.CustomId.Split(':'); 24 | 25 | // here we determine that we should always check for the first ',' present. 26 | // This will deal with additional wildcards by always selecting the first wildcard present. 27 | if (param.Length > 1 && ulong.TryParse(param[1].Split(',')[0], out ulong id)) 28 | return (context.User.Id == id) 29 | // If the user ID 30 | ? Task.FromResult(PreconditionResult.FromSuccess()) 31 | : Task.FromResult(PreconditionResult.FromError("User ID does not match component ID!")); 32 | 33 | else 34 | return Task.FromResult(PreconditionResult.FromError("Parse cannot be done if no userID exists.")); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Attributes/RequireOwnerAttribute.cs: -------------------------------------------------------------------------------- 1 | using Discord; 2 | using Discord.Interactions; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace NinjaBotCore.Attributes 10 | { 11 | public class RequireOwnerAttribute : PreconditionAttribute 12 | { 13 | public override async Task CheckRequirementsAsync(IInteractionContext context, ICommandInfo commandInfo, IServiceProvider services) 14 | { 15 | switch (context.Client.TokenType) 16 | { 17 | case TokenType.Bot: 18 | var application = await context.Client.GetApplicationInfoAsync().ConfigureAwait(false); 19 | if (context.User.Id != application.Owner.Id) 20 | return PreconditionResult.FromError(ErrorMessage ?? "Command can only be run by the owner of the bot."); 21 | return PreconditionResult.FromSuccess(); 22 | default: 23 | return PreconditionResult.FromError($"{nameof(RequireOwnerAttribute)} is not supported by this {nameof(TokenType)}."); 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Common/IApiRequestorThrottle.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Threading.Tasks; 3 | 4 | namespace NinjaBotCore.Common 5 | { 6 | public interface IApiRequestorThrottle 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Common/IWclApiRequestor.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Threading.Tasks; 3 | 4 | namespace NinjaBotCore.Common 5 | { 6 | public interface IWclApiRequestor 7 | { 8 | Task Get(string relativeUrl); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Common/IWowApi.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | namespace NinjaBotCore.Common 3 | { 4 | public interface IWowApi 5 | { 6 | void GetWowData(); 7 | string GetAPIRequest(string url, string locale); 8 | string GetAPIRequest(string url, string locale, string region = "us"); 9 | public Task GetWowToken(string username, string password); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Database/AchCategory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class AchCategory 8 | { 9 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] 10 | public AchCategory() 11 | { 12 | this.FindWowCheeves = new HashSet(); 13 | } 14 | 15 | [Key] 16 | public long CatId { get; set; } 17 | public string CatName { get; set; } 18 | 19 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 20 | public virtual ICollection FindWowCheeves { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Database/AuctionItemMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class AuctionItemMapping 8 | { 9 | [Key] 10 | public long MapId { get; set; } 11 | public Nullable ItemId { get; set; } 12 | public string Name { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Database/AwaySystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class AwaySystem 8 | { 9 | [Key] 10 | public long AwayId { get; set; } 11 | public string UserName { get; set; } 12 | public string Message { get; set; } 13 | public Nullable Status { get; set; } 14 | public Nullable TimeAway { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Database/Blacklist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class Blacklist 8 | { 9 | [Key] 10 | public long BlacklistId { get; set; } 11 | public Nullable DiscordUserId { get; set; } 12 | public string DiscordUserName { get; set; } 13 | public string Reason { get; set; } 14 | public Nullable WhenBlacklisted { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Database/C8Ball.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class C8Ball 8 | { 9 | [Key] 10 | public long AnswerId { get; set; } 11 | public string Answer { get; set; } 12 | public string Color { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Database/ChannelOutput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class ChannelOutput 8 | { 9 | [Key] 10 | public long Id { get; set; } 11 | public string ServerName { get; set; } 12 | public Nullable ServerId { get; set; } 13 | public string ChannelName { get; set; } 14 | public Nullable ChannelId { get; set; } 15 | public string SetByName { get; set; } 16 | public Nullable SetById { get; set; } 17 | public Nullable SetTime { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Database/CharStats.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class CharStats 7 | { 8 | [Key] 9 | public long CharStatId { get; set; } 10 | public string CharName { get; set; } 11 | public string GuildName { get; set; } 12 | public string RealmName { get; set; } 13 | public DateTime LastModified { get; set; } 14 | public string ElixerConsumed { get; set; } 15 | public long Quantity { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Database/CurrentRaidTier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public class CurrentRaidTier 7 | { 8 | [Key] 9 | public int Id { get; set; } 10 | public int WclZoneId { get; set; } 11 | public string RaidName { get; set; } 12 | public int? Partition { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Database/DiscordServer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class DiscordServer 8 | { 9 | [Key] 10 | public long ServerId { get; set; } 11 | public string ServerName { get; set; } 12 | public Nullable OwnerId { get; set; } 13 | public string OwnerName { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Database/FindWowCheeve.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public class FindWowCheeve 8 | { 9 | [Key] 10 | public long AchId { get; set; } 11 | public virtual AchCategory AchCategory { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Database/Giphy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class Giphy 8 | { 9 | [Key] 10 | public long Id { get; set; } 11 | public string ServerName { get; set; } 12 | public Nullable ServerId { get; set; } 13 | public Nullable GiphyEnabled { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Database/LogMonitoring.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class LogMonitoring 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public long ServerId { get; set; } 11 | public long ChannelId { get; set; } 12 | public string ChannelName { get; set; } 13 | public string ServerName { get; set; } 14 | public bool MonitorLogs { get; set; } 15 | public bool WatchLog { get; set; } 16 | public string RetailReportId { get; set; } 17 | public string ClassicReportId { get; set; } 18 | public string VanillaReportId { get; set; } 19 | public string ReportId { get; set; } 20 | public DateTime? LatestLog { get; set; } 21 | public DateTime? LatestLogClassic { get; set; } 22 | public DateTime? LatestLogVanilla { get; set; } 23 | public DateTime? LatestLogRetail { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Database/NinjaBotEntities.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaBotCore.Database 2 | { 3 | using System; 4 | using Microsoft.Data.Sqlite; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | public partial class NinjaBotEntities : DbContext 8 | { 9 | public NinjaBotEntities() { 10 | 11 | } 12 | public NinjaBotEntities(DbContextOptions options) : base(options) 13 | { 14 | } 15 | public virtual DbSet RlStats { get; set; } 16 | public virtual DbSet RlUserStats { get; set; } 17 | public virtual DbSet TriviaQuestion { get; set; } 18 | public virtual DbSet TriviaQuestionChoices { get; set; } 19 | public virtual DbSet Notes { get; set; } 20 | public virtual DbSet QuestionAnswers { get; set; } 21 | public virtual DbSet ChannelOutputs { get; set; } 22 | public virtual DbSet WowGuildAssociations { get; set; } 23 | public virtual DbSet Giphy { get; set; } 24 | public virtual DbSet ServerSettings { get; set; } 25 | public virtual DbSet TriviaCategories { get; set; } 26 | public virtual DbSet AwaySystem { get; set; } 27 | public virtual DbSet C8Ball { get; set; } 28 | public virtual DbSet WowAuctions { get; set; } 29 | public virtual DbSet AuctionItemMappings { get; set; } 30 | public virtual DbSet WowAuctionPrices { get; set; } 31 | public virtual DbSet Blacklist { get; set; } 32 | public virtual DbSet ServerGreetings { get; set; } 33 | public virtual DbSet AchCategories { get; set; } 34 | public virtual DbSet FindWowCheeves { get; set; } 35 | public virtual DbSet DiscordServers { get; set; } 36 | public virtual DbSet Requests { get; set; } 37 | public virtual DbSet WowResources { get; set; } 38 | public virtual DbSet LogMonitoring { get; set; } 39 | public virtual DbSet Warnings { get; set; } 40 | public virtual DbSet PrefixList { get; set; } 41 | public virtual DbSet CharStats { get; set; } 42 | public virtual DbSet CurrentRaidTier { get; set; } 43 | public virtual DbSet WowMChar { get; set; } 44 | public virtual DbSet WordList { get; set; } 45 | public virtual DbSet WowClassicGuild { get; set; } 46 | public virtual DbSet WowVanillaGuild { get; set; } 47 | public virtual DbSet WclPosted { get; set; } 48 | 49 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 50 | { 51 | var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = "ninjabot.db" }; 52 | var connectionString = connectionStringBuilder.ToString(); 53 | var connection = new SqliteConnection(connectionString); 54 | if (!optionsBuilder.IsConfigured) 55 | { 56 | optionsBuilder.UseSqlite(connection); 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/Database/NinjaBotEntitiesFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Design; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public class NinjaBotEntitiesFactory : IDesignTimeDbContextFactory 7 | { 8 | public NinjaBotEntities CreateDbContext(string[] args) 9 | { 10 | var optionsBuilder = new DbContextOptionsBuilder(); 11 | optionsBuilder.UseSqlite("Data Source=ninjabot.db"); 12 | 13 | return new NinjaBotEntities(optionsBuilder.Options); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Database/Note.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class Note 8 | { 9 | [Key] 10 | public long Id { get; set; } 11 | public string Note1 { get; set; } 12 | public string ServerName { get; set; } 13 | public Nullable ServerId { get; set; } 14 | public string SetBy { get; set; } 15 | public Nullable SetById { get; set; } 16 | public Nullable TimeSet { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Database/PrefixList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class PrefixList 8 | { 9 | [Key] 10 | public long ServerId { get; set; } 11 | public string ServerName { get; set; } 12 | public char Prefix { get; set; } 13 | public long SetById { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Database/QuestionAnswer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class QuestionAnswer 8 | { 9 | [Key] 10 | public long Id { get; set; } 11 | public string DiscordUserName { get; set; } 12 | public Nullable QuestionId { get; set; } 13 | public Nullable ChoiceId { get; set; } 14 | public Nullable IsRight { get; set; } 15 | public Nullable AnswerTime { get; set; } 16 | public string test { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Database/Request.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class Request 8 | { 9 | [Key] 10 | public long Id { get; set; } 11 | public long UserId { get; set; } 12 | public string UserName { get; set; } 13 | public long ChannelId { get; set; } 14 | public string ChannelName { get; set; } 15 | public string Command { get; set; } 16 | public string Parameters { get; set; } 17 | public string ServerName { get; set; } 18 | public long ServerID { get; set; } 19 | public Nullable RequestTime { get; set; } 20 | public Nullable Success { get; set; } 21 | public string FailureReason { get; set; } 22 | } 23 | } -------------------------------------------------------------------------------- /src/Database/RlStat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public class RlStat 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public Nullable SteamID { get; set; } 11 | public Nullable DiscordUserID { get; set; } 12 | public string DiscordUserName { get; set; } 13 | public string RlPlayerName { get; set; } 14 | public string Platform { get; set; } 15 | 16 | } 17 | } -------------------------------------------------------------------------------- /src/Database/RlUserStat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class RlUserStat 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public Nullable SteamID { get; set; } 11 | public string RankedSolo { get; set; } 12 | public string Ranked2v2 { get; set; } 13 | public string RankedDuel { get; set; } 14 | public string Ranked3v3 { get; set; } 15 | public string Unranked { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Database/ServerGreeting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class ServerGreeting 7 | { 8 | [Key] 9 | public long DiscordGuildId { get; set; } 10 | public Nullable GreetUsers { get; set; } 11 | public string Greeting { get; set; } 12 | public Nullable SetById { get; set; } 13 | public string SetByName { get; set; } 14 | public Nullable TimeSet { get; set; } 15 | public string PartingMessage { get; set; } 16 | public Nullable GreetingChannelId { get; set; } 17 | public Nullable PartingChannelId { get; set; } 18 | public string GreetingChannelName { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Database/ServerSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class ServerSetting 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public string ServerName { get; set; } 11 | public Nullable ServerId { get; set; } 12 | public Nullable Announcements { get; set; } 13 | public Nullable OutputChannel { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Database/TriviaCategory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class TriviaCategory 8 | { 9 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] 10 | public TriviaCategory() 11 | { 12 | this.TriviaQuestions = new HashSet(); 13 | } 14 | 15 | public string Name { get; set; } 16 | [Key] 17 | public long CategoryId { get; set; } 18 | 19 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 20 | public virtual ICollection TriviaQuestions { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Database/TriviaQuestion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class TriviaQuestion 8 | { 9 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] 10 | public TriviaQuestion() 11 | { 12 | this.TriviaQuestionChoices = new HashSet(); 13 | } 14 | [Key] 15 | public long QuestionId { get; set; } 16 | public string Question { get; set; } 17 | public Nullable IsActive { get; set; } 18 | public Nullable Category { get; set; } 19 | 20 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 21 | public virtual ICollection TriviaQuestionChoices { get; set; } 22 | public virtual TriviaCategory TriviaCategory { get; set; } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Database/TriviaQuestionChoice.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class TriviaQuestionChoice 7 | { 8 | [Key] 9 | public long ChoiceId { get; set; } 10 | public Nullable QuestionId { get; set; } 11 | public Nullable IsRightChoice { get; set; } 12 | public string Choice { get; set; } 13 | 14 | public virtual TriviaQuestion TriviaQuestion { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Database/Warnings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class Warnings 8 | { 9 | [Key] 10 | public long Warnid { get; set; } 11 | public long ServerId { get; set; } 12 | public string ServerName { get; set; } 13 | public long UserWarnedId { get; set; } 14 | public string UserWarnedName { get; set; } 15 | public long IssuerId { get; set; } 16 | public string IssuerName { get; set; } 17 | public Nullable TimeIssued { get; set; } 18 | public int NumWarnings { get; set;} 19 | } 20 | } -------------------------------------------------------------------------------- /src/Database/WclPosted.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class WclPosted 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public long ServerId { get; set; } 11 | public long ChannelId { get; set; } 12 | public string ChannelName { get; set; } 13 | public string ServerName { get; set; } 14 | public string ReportId { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Database/WordList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NinjaBotCore.Database 6 | { 7 | public partial class WordList 8 | { 9 | [Key] 10 | public long Id {get; set;} 11 | public long ServerId { get; set; } 12 | public string ServerName { get; set; } 13 | public string Word { get; set; } 14 | public long SetById { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Database/WowAuctionPrice.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class WowAuctionPrice 7 | { 8 | [Key] 9 | public long AuctionPriceId { get; set; } 10 | public Nullable AuctionItemId { get; set; } 11 | public string AuctionRealm { get; set; } 12 | public Nullable MinPrice { get; set; } 13 | public Nullable AvgPrice { get; set; } 14 | public Nullable MaxPrice { get; set; } 15 | public Nullable Seen { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Database/WowAuctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class WowAuctions 7 | { 8 | [Key] 9 | public long AuctionId { get; set; } 10 | public string RealmName { get; set; } 11 | public string RealmSlug { get; set; } 12 | public Nullable WowAuctionId { get; set; } 13 | public Nullable AuctionItemId { get; set; } 14 | public string AuctionOwner { get; set; } 15 | public string AuctionOwnerRealm { get; set; } 16 | public Nullable AuctionBid { get; set; } 17 | public Nullable AuctionBuyout { get; set; } 18 | public Nullable AuctionQuantity { get; set; } 19 | public string AuctionTimeLeft { get; set; } 20 | public Nullable AuctionRand { get; set; } 21 | public Nullable AuctionSeed { get; set; } 22 | public Nullable AuctionContext { get; set; } 23 | public Nullable DateModified { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Database/WowClassicGuild.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class WowClassicGuild 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public Nullable ServerId { get; set; } 11 | public string ServerName { get; set; } 12 | public string WowGuild { get; set; } 13 | public string WowRealm { get; set; } 14 | public string WowRegion { get; set; } 15 | public string SetBy { get; set; } 16 | public Nullable SetById { get; set; } 17 | public Nullable TimeSet { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Database/WowGuildAssociation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class WowGuildAssociations 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public Nullable ServerId { get; set; } 11 | public string ServerName { get; set; } 12 | public string WowGuild { get; set; } 13 | public string WowRealm { get; set; } 14 | public string WowRegion { get; set; } 15 | public string LocalRealmSlug { get; set; } 16 | public string Locale { get; set; } 17 | public string SetBy { get; set; } 18 | public Nullable SetById { get; set; } 19 | public Nullable TimeSet { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /src/Database/WowMChar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class WowMChar 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public long ServerId { get; set; } 11 | public long DiscordUserId { get; set; } 12 | public string CharName { get; set; } 13 | public string ClassName { get; set;} 14 | public long ItemLevel { get; set; } 15 | public long Traits { get; set; } 16 | public string MainSpec { get; set; } 17 | public string OffSpec { get; set; } 18 | public bool IsMain { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Database/WowResources.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class WowResources 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public Nullable ServerId { get; set; } 11 | public string ClassName { get; set; } 12 | public string Specialization { get; set; } 13 | public string Resource { get; set; } 14 | public string ResourceDescription { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/Database/WowVanillaGuild.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | 4 | namespace NinjaBotCore.Database 5 | { 6 | public partial class WowVanillaGuild 7 | { 8 | [Key] 9 | public long Id { get; set; } 10 | public Nullable ServerId { get; set; } 11 | public string ServerName { get; set; } 12 | public string WowGuild { get; set; } 13 | public string WowRealm { get; set; } 14 | public string WowRegion { get; set; } 15 | public string SetBy { get; set; } 16 | public Nullable SetById { get; set; } 17 | public Nullable TimeSet { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Models/Google/GeocodeResponse.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaBotCore.Models.Google 2 | { 3 | public class GeocodeResponse 4 | { 5 | public Result[] results { get; set; } 6 | public string status { get; set; } 7 | } 8 | 9 | public class Result 10 | { 11 | public Address_Components[] address_components { get; set; } 12 | public string formatted_address { get; set; } 13 | public Geometry geometry { get; set; } 14 | public string place_id { get; set; } 15 | public string[] types { get; set; } 16 | } 17 | 18 | public class Geometry 19 | { 20 | public Location location { get; set; } 21 | public string location_type { get; set; } 22 | public Viewport viewport { get; set; } 23 | } 24 | 25 | public class Location 26 | { 27 | public float lat { get; set; } 28 | public float lng { get; set; } 29 | } 30 | 31 | public class Viewport 32 | { 33 | public Northeast northeast { get; set; } 34 | public Southwest southwest { get; set; } 35 | } 36 | 37 | public class Northeast 38 | { 39 | public float lat { get; set; } 40 | public float lng { get; set; } 41 | } 42 | 43 | public class Southwest 44 | { 45 | public float lat { get; set; } 46 | public float lng { get; set; } 47 | } 48 | 49 | public class Address_Components 50 | { 51 | public string long_name { get; set; } 52 | public string short_name { get; set; } 53 | public string[] types { get; set; } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Models/Steam/SteamModel.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaBotCore.Models.Steam 2 | { 3 | public class SteamModel 4 | { 5 | public class UserInfo 6 | { 7 | public Response response { get; set; } 8 | } 9 | 10 | public class Response 11 | { 12 | public Player[] players { get; set; } 13 | } 14 | 15 | public class Player 16 | { 17 | public string steamid { get; set; } 18 | public int communityvisibilitystate { get; set; } 19 | public int profilestate { get; set; } 20 | public string personaname { get; set; } 21 | public int lastlogoff { get; set; } 22 | public string profileurl { get; set; } 23 | public string avatar { get; set; } 24 | public string avatarmedium { get; set; } 25 | public string avatarfull { get; set; } 26 | public int personastate { get; set; } 27 | public string realname { get; set; } 28 | public string primaryclanid { get; set; } 29 | public int timecreated { get; set; } 30 | public int personastateflags { get; set; } 31 | } 32 | 33 | public class VanityResponse 34 | { 35 | public VanitySteam response { get; set; } 36 | } 37 | 38 | public class VanitySteam 39 | { 40 | public string steamid { get; set; } 41 | public int success { get; set; } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Models/Wow/ApiResponse.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace NinjaBotCore.Models.Wow 4 | { 5 | public class ApiResponse 6 | { 7 | [JsonProperty("access_token")] 8 | public string AccessToken { get; set; } 9 | 10 | [JsonProperty("token_type")] 11 | public string TokenType { get; set; } 12 | 13 | [JsonProperty("expires_in")] 14 | public long ExpiresIn { get; set; } 15 | 16 | [JsonProperty("scope")] 17 | public string Scope { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Models/Wow/AuctionList.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaBotCore.Models.Wow 2 | { 3 | public class AuctionList 4 | { 5 | public string Name { get; set; } 6 | public int ItemID { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Models/Wow/AuctionsModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NinjaBotCore.Models.Wow 8 | { 9 | public class AuctionsModel 10 | { 11 | public class AuctionFile 12 | { 13 | public File[] files { get; set; } 14 | } 15 | 16 | public class File 17 | { 18 | public string url { get; set; } 19 | public long lastModified { get; set; } 20 | } 21 | 22 | public class Auctions 23 | { 24 | public Realm[] realms { get; set; } 25 | public Auction[] auctions { get; set; } 26 | } 27 | 28 | public class Realm 29 | { 30 | public string name { get; set; } 31 | public string slug { get; set; } 32 | } 33 | 34 | public class Auction 35 | { 36 | public DateTime fileDate { get; set; } 37 | public int auc { get; set; } 38 | public int item { get; set; } 39 | public string owner { get; set; } 40 | public string ownerRealm { get; set; } 41 | public long bid { get; set; } 42 | public long buyout { get; set; } 43 | public int quantity { get; set; } 44 | public string timeLeft { get; set; } 45 | public int rand { get; set; } 46 | public long seed { get; set; } 47 | public int context { get; set; } 48 | public Bonuslist[] bonusLists { get; set; } 49 | public Modifier[] modifiers { get; set; } 50 | public int petSpeciesId { get; set; } 51 | public int petBreedId { get; set; } 52 | public int petLevel { get; set; } 53 | public int petQualityId { get; set; } 54 | } 55 | 56 | public class Bonuslist 57 | { 58 | public int bonusListId { get; set; } 59 | } 60 | 61 | public class Modifier 62 | { 63 | public int type { get; set; } 64 | public int value { get; set; } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Models/Wow/FightTables.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NinjaBotCore.Models.Wow 8 | { 9 | public class ReportTable 10 | { 11 | public Entry[] entries { get; set; } 12 | public int totalTime { get; set; } 13 | } 14 | 15 | public class Entry 16 | { 17 | public string name { get; set; } 18 | public int id { get; set; } 19 | public int guid { get; set; } 20 | public string type { get; set; } 21 | public int itemLevel { get; set; } 22 | public string icon { get; set; } 23 | public int total { get; set; } 24 | public int activeTime { get; set; } 25 | public int activeTimeReduced { get; set; } 26 | public Ability[] abilities { get; set; } 27 | public object[] damageAbilities { get; set; } 28 | public Target[] targets { get; set; } 29 | public Talent[] talents { get; set; } 30 | public Gear[] gear { get; set; } 31 | public int blocked { get; set; } 32 | public int totalReduced { get; set; } 33 | public Pet[] pets { get; set; } 34 | } 35 | 36 | public class Ability 37 | { 38 | public string name { get; set; } 39 | public int total { get; set; } 40 | public int type { get; set; } 41 | public int totalReduced { get; set; } 42 | public string petName { get; set; } 43 | } 44 | 45 | public class Target 46 | { 47 | public string name { get; set; } 48 | public int total { get; set; } 49 | public string type { get; set; } 50 | public int totalReduced { get; set; } 51 | } 52 | 53 | public class Talent 54 | { 55 | public string name { get; set; } 56 | public int guid { get; set; } 57 | public int type { get; set; } 58 | } 59 | 60 | public class Gear 61 | { 62 | public int id { get; set; } 63 | public int slot { get; set; } 64 | public int itemLevel { get; set; } 65 | public int[] bonusIDs { get; set; } 66 | public string name { get; set; } 67 | public int permanentEnchant { get; set; } 68 | public string permanentEnchantName { get; set; } 69 | public Gem[] gems { get; set; } 70 | public int onUseEnchant { get; set; } 71 | } 72 | 73 | public class Gem 74 | { 75 | public int id { get; set; } 76 | public int itemLevel { get; set; } 77 | } 78 | 79 | public class Pet 80 | { 81 | public string name { get; set; } 82 | public int id { get; set; } 83 | public int guid { get; set; } 84 | public string type { get; set; } 85 | public int icon { get; set; } 86 | public int total { get; set; } 87 | public int totalReduced { get; set; } 88 | public int activeTime { get; set; } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Models/Wow/FoundChar.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaBotCore.Models.Wow 2 | { 3 | public class FoundChar 4 | { 5 | public string charName { get; set; } 6 | public string realmName { get; set; } 7 | public string level { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/Models/Wow/GuildMembers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Newtonsoft.Json; 7 | 8 | namespace NinjaBotCore.Models.Wow 9 | { 10 | public class GuildMembers 11 | { 12 | public Member[] members { get; set; } 13 | public Emblem emblem { get; set; } 14 | public WowGuild guild { get; set; } 15 | } 16 | 17 | public class WowRealmResponseGuild 18 | { 19 | public int id { get; set; } 20 | public string slug { get; set; } 21 | } 22 | 23 | public class Faction 24 | { 25 | public string type { get; set; } 26 | public string name { get; set; } 27 | } 28 | 29 | public class WowGuild 30 | { 31 | public string name { get; set; } 32 | public int id { get; set; } 33 | public WowRealmResponseGuild realm { get; set; } 34 | public Faction faction { get; set; } 35 | } 36 | 37 | public class Emblem 38 | { 39 | public int icon { get; set; } 40 | public string iconColor { get; set; } 41 | public int iconColorId { get; set; } 42 | public int border { get; set; } 43 | public string borderColor { get; set; } 44 | public int borderColorId { get; set; } 45 | public string backgroundColor { get; set; } 46 | public int backgroundColorId { get; set; } 47 | } 48 | 49 | public class Member 50 | { 51 | public Character character { get; set; } 52 | public int rank { get; set; } 53 | } 54 | 55 | public class Spec 56 | { 57 | public string name { get; set; } 58 | public string role { get; set; } 59 | public string backgroundImage { get; set; } 60 | public string icon { get; set; } 61 | public string description { get; set; } 62 | public int order { get; set; } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Models/Wow/ItemComparison.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaBotCore.Models.Wow 2 | { 3 | public class ItemComparison 4 | { 5 | public string itemName { get; set; } 6 | public int itemLevel { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Models/Wow/ItemInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NinjaBotCore.Models.Wow 8 | { 9 | public class ItemInfo 10 | { 11 | public int id { get; set; } 12 | public int disenchantingSkillRank { get; set; } 13 | public string description { get; set; } 14 | public string name { get; set; } 15 | public string icon { get; set; } 16 | public int stackable { get; set; } 17 | public int itemBind { get; set; } 18 | public Bonusstat[] bonusStats { get; set; } 19 | public object[] itemSpells { get; set; } 20 | public int buyPrice { get; set; } 21 | public int itemClass { get; set; } 22 | public int itemSubClass { get; set; } 23 | public int containerSlots { get; set; } 24 | public Weapon weaponInfo { get; set; } 25 | public int inventoryType { get; set; } 26 | public bool equippable { get; set; } 27 | public int itemLevel { get; set; } 28 | public int maxCount { get; set; } 29 | public int maxDurability { get; set; } 30 | public int minFactionId { get; set; } 31 | public int minReputation { get; set; } 32 | public int quality { get; set; } 33 | public int sellPrice { get; set; } 34 | public int requiredSkill { get; set; } 35 | public int requiredLevel { get; set; } 36 | public int requiredSkillRank { get; set; } 37 | public Itemsource itemSource { get; set; } 38 | public int baseArmor { get; set; } 39 | public bool hasSockets { get; set; } 40 | public bool isAuctionable { get; set; } 41 | public int armor { get; set; } 42 | public int displayInfoId { get; set; } 43 | public string nameDescription { get; set; } 44 | public string nameDescriptionColor { get; set; } 45 | public bool upgradable { get; set; } 46 | public bool heroicTooltip { get; set; } 47 | public string context { get; set; } 48 | public object[] bonusLists { get; set; } 49 | public string[] availableContexts { get; set; } 50 | public Bonussummary bonusSummary { get; set; } 51 | public int artifactId { get; set; } 52 | } 53 | 54 | public class Weapon 55 | { 56 | public Dmg damage { get; set; } 57 | public float weaponSpeed { get; set; } 58 | public float dps { get; set; } 59 | } 60 | 61 | public class Dmg 62 | { 63 | public int min { get; set; } 64 | public int max { get; set; } 65 | public float exactMin { get; set; } 66 | public float exactMax { get; set; } 67 | } 68 | 69 | public class Itemsource 70 | { 71 | public int sourceId { get; set; } 72 | public string sourceType { get; set; } 73 | } 74 | 75 | public class Bonussummary 76 | { 77 | public object[] defaultBonusLists { get; set; } 78 | public object[] chanceBonusLists { get; set; } 79 | public object[] bonusChances { get; set; } 80 | } 81 | 82 | public class Bonusstat 83 | { 84 | public int stat { get; set; } 85 | public int amount { get; set; } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Models/Wow/LogsReports.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Newtonsoft.Json; 7 | using NinjaBotCore.Modules.Wow; 8 | 9 | namespace NinjaBotCore.Models.Wow 10 | { 11 | [JsonObject] 12 | public class Reports 13 | { 14 | public string id { get; set; } 15 | public string title { get; set; } 16 | public string owner { get; set; } 17 | public long start { get; set; } 18 | public long end { get; set; } 19 | public int zone { get; set; } 20 | public string zoneName 21 | { 22 | get 23 | { 24 | string theZone = WarcraftLogs.Zones.Where(r => r.id == this.zone).Select(r => r.name).FirstOrDefault(); 25 | return theZone; 26 | } 27 | } 28 | public string reportURL 29 | { 30 | get 31 | { 32 | string url = string.Empty; 33 | url = $"https://www.warcraftlogs.com/reports/{id}"; 34 | return url; 35 | } 36 | } 37 | } 38 | [JsonObject] 39 | public class Zones 40 | { 41 | public int id { get; set; } 42 | public string name { get; set; } 43 | public bool frozen { get; set; } 44 | public Encounter[] encounters { get; set; } 45 | public Bracket brackets { get; set; } 46 | } 47 | [JsonObject] 48 | public class Encounter 49 | { 50 | public int id { get; set; } 51 | public string name { get; set; } 52 | } 53 | [JsonObject] 54 | public class Bracket 55 | { 56 | public int min { get; set; } 57 | public float max { get; set; } 58 | public float bucket { get; set; } 59 | public string type { get; set; } 60 | public int sub_bucket { get; set; } 61 | } 62 | [JsonObject] 63 | public class Fights 64 | { 65 | public Fight[] fights { get; set; } 66 | public string lang { get; set; } 67 | public Friendly[] friendlies { get; set; } 68 | public Enemy[] enemies { get; set; } 69 | public Friendlypet[] friendlyPets { get; set; } 70 | public object[] enemyPets { get; set; } 71 | public Phase[] phases { get; set; } 72 | public string title { get; set; } 73 | public string owner { get; set; } 74 | public long start { get; set; } 75 | public long end { get; set; } 76 | public int zone { get; set; } 77 | } 78 | [JsonObject] 79 | public class Fight 80 | { 81 | public int id { get; set; } 82 | public int start_time { get; set; } 83 | public int end_time { get; set; } 84 | public int boss { get; set; } 85 | public int size { get; set; } 86 | public int difficulty { get; set; } 87 | public bool kill { get; set; } 88 | public int partial { get; set; } 89 | public int bossPercentage { get; set; } 90 | public string name { get; set; } 91 | } 92 | [JsonObject] 93 | public class Friendly 94 | { 95 | public string name { get; set; } 96 | public int id { get; set; } 97 | public int guid { get; set; } 98 | public string type { get; set; } 99 | public Fight1[] fights { get; set; } 100 | } 101 | [JsonObject] 102 | public class Fight1 103 | { 104 | public int id { get; set; } 105 | public int instances { get; set; } 106 | } 107 | [JsonObject] 108 | public class Enemy 109 | { 110 | public string name { get; set; } 111 | public int id { get; set; } 112 | public int guid { get; set; } 113 | public string type { get; set; } 114 | public Fight2[] fights { get; set; } 115 | } 116 | [JsonObject] 117 | public class Fight2 118 | { 119 | public int id { get; set; } 120 | public int instances { get; set; } 121 | } 122 | [JsonObject] 123 | public class Friendlypet 124 | { 125 | public string name { get; set; } 126 | public int id { get; set; } 127 | public int guid { get; set; } 128 | public string type { get; set; } 129 | public int petOwner { get; set; } 130 | public Fight3[] fights { get; set; } 131 | } 132 | [JsonObject] 133 | public class Fight3 134 | { 135 | public int id { get; set; } 136 | public int instances { get; set; } 137 | } 138 | [JsonObject] 139 | public class Phase 140 | { 141 | public int boss { get; set; } 142 | public string[] phases { get; set; } 143 | } 144 | [JsonObject] 145 | public class CharParses 146 | { 147 | public int difficulty { get; set; } 148 | public int size { get; set; } 149 | public int kill { get; set; } 150 | public string name { get; set; } 151 | public LogSpec[] specs { get; set; } 152 | public bool variable { get; set; } 153 | public int partition { get; set; } 154 | } 155 | [JsonObject] 156 | public class LogSpec 157 | { 158 | public string _class { get; set; } 159 | public string spec { get; set; } 160 | public bool combined { get; set; } 161 | public Datum[] data { get; set; } 162 | public int best_persecondamount { get; set; } 163 | public int best_duration { get; set; } 164 | public int best_historical_percent { get; set; } 165 | public float best_allstar_points { get; set; } 166 | public int best_combined_allstar_points { get; set; } 167 | public int possible_allstar_points { get; set; } 168 | public Best_Talents[] best_talents { get; set; } 169 | public Best_Gear[] best_gear { get; set; } 170 | public int historical_total { get; set; } 171 | public float historical_median { get; set; } 172 | public float historical_avg { get; set; } 173 | } 174 | [JsonObject] 175 | public class Datum 176 | { 177 | public int character_id { get; set; } 178 | public string character_name { get; set; } 179 | public int persecondamount { get; set; } 180 | public int ilvl { get; set; } 181 | public int duration { get; set; } 182 | public long start_time { get; set; } 183 | public string report_code { get; set; } 184 | public int report_fight { get; set; } 185 | public int ranking_id { get; set; } 186 | public string guildName { get; set; } 187 | public int total { get; set; } 188 | public string rank { get; set; } 189 | public float percent { get; set; } 190 | public int exploit { get; set; } 191 | public bool banned { get; set; } 192 | public int historical_count { get; set; } 193 | public int historical_percent { get; set; } 194 | public LogTalent[] talents { get; set; } 195 | public Gear[] gear { get; set; } 196 | } 197 | [JsonObject] 198 | public class LogTalent 199 | { 200 | public string name { get; set; } 201 | public int id { get; set; } 202 | } 203 | [JsonObject] 204 | public class LogGear 205 | { 206 | public string name { get; set; } 207 | public string quality { get; set; } 208 | public int id { get; set; } 209 | } 210 | [JsonObject] 211 | public class Best_Talents 212 | { 213 | public string name { get; set; } 214 | public int id { get; set; } 215 | } 216 | [JsonObject] 217 | public class Best_Gear 218 | { 219 | public string name { get; set; } 220 | public string quality { get; set; } 221 | public int id { get; set; } 222 | } 223 | [JsonObject] 224 | public class LogCharRankings 225 | { 226 | public int encounter { get; set; } 227 | public string encounterName 228 | { 229 | get 230 | { 231 | string encounterName = string.Empty; 232 | foreach (Zones zone in WarcraftLogs.Zones) 233 | { 234 | foreach (Encounter encounter in zone.encounters) 235 | { 236 | if (encounter.id == this.encounter) 237 | { 238 | encounterName = encounter.name; 239 | } 240 | } 241 | } 242 | 243 | return encounterName; 244 | } 245 | } 246 | [JsonProperty(PropertyName = "class")] 247 | public int classID { get; set; } 248 | public string className 249 | { 250 | get 251 | { 252 | string name = string.Empty; 253 | List charClasses = WarcraftLogs.CharClasses; 254 | 255 | name = charClasses.Where(c => c.id == this.classID).Select(c => c.name).FirstOrDefault(); 256 | 257 | return name; 258 | } 259 | } 260 | public int spec { get; set; } 261 | public string specName 262 | { 263 | get 264 | { 265 | string name = string.Empty; 266 | List charClasses = WarcraftLogs.CharClasses; 267 | 268 | foreach (CharClasses classItem in charClasses) 269 | { 270 | if (classItem.id == this.classID) 271 | { 272 | name = classItem.specs.Where(c => c.id == this.spec).Select(c => c.name).FirstOrDefault(); 273 | } 274 | } 275 | 276 | return name; 277 | } 278 | } 279 | public string guildName { get; set; } 280 | public int rank { get; set; } 281 | public int outOf { get; set; } 282 | public int rankPercentage 283 | { 284 | get 285 | { 286 | int rankPercentage = (int)Math.Round((double)(100 * this.rank) / this.outOf); 287 | return rankPercentage; 288 | } 289 | } 290 | public int duration { get; set; } 291 | public long startTime { get; set; } 292 | public string reportID { get; set; } 293 | public string reportURL 294 | { 295 | get 296 | { 297 | string url = string.Empty; 298 | url = $"https://www.warcraftlogs.com/reports/{this.reportID}"; 299 | return url; 300 | } 301 | } 302 | public int fightID { get; set; } 303 | public int difficulty { get; set; } 304 | public string difficultyName 305 | { 306 | get 307 | { 308 | string name = string.Empty; 309 | 310 | switch (this.difficulty) 311 | { 312 | case 1: 313 | { 314 | name = "LFR"; 315 | break; 316 | } 317 | case 2: 318 | { 319 | name = "Flex"; 320 | break; 321 | } 322 | case 3: 323 | { 324 | name = "Normal"; 325 | break; 326 | } 327 | case 4: 328 | { 329 | name = "Heroic"; 330 | break; 331 | } 332 | case 5: 333 | { 334 | name = "Mythic"; 335 | break; 336 | } 337 | } 338 | 339 | return name; 340 | } 341 | } 342 | public int size { get; set; } 343 | public int itemLevel { get; set; } 344 | public int total { get; set; } 345 | public bool estimated { get; set; } 346 | } 347 | 348 | public class CharClasses 349 | { 350 | public int id { get; set; } 351 | public string name { get; set; } 352 | public ClassSpec[] specs { get; set; } 353 | } 354 | 355 | public class ClassSpec 356 | { 357 | public int id { get; set; } 358 | public string name { get; set; } 359 | } 360 | } -------------------------------------------------------------------------------- /src/Models/Wow/NinjaObjects.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NinjaBotCore.Models.Wow 8 | { 9 | public class NinjaObjects 10 | { 11 | public class GuildObject 12 | { 13 | public string guildName { get; set; } 14 | public string realmName { get; set; } 15 | public string regionName { get; set; } 16 | public string locale { get; set; } 17 | public string realmSlug { get; set; } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Models/Wow/ProgressGuildRank.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NinjaBotCore.Models.Wow 8 | { 9 | class ProgressGuildRanks 10 | { 11 | public class GuildRank 12 | { 13 | public int score { get; set; } 14 | public int world_rank { get; set; } 15 | public int area_rank { get; set; } 16 | public int realm_rank { get; set; } 17 | } 18 | 19 | public class Ranking 20 | { 21 | public int score { get; set; } 22 | public int world_rank { get; set; } 23 | public int area_rank { get; set; } 24 | public int realm_rank { get; set; } 25 | public string name { get; set; } 26 | public string url { get; set; } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Models/Wow/WarcraftlogsRankings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Newtonsoft.Json; 7 | 8 | namespace NinjaBotCore.Models.Wow 9 | { 10 | public class WarcraftlogRankings 11 | { 12 | public class RankingObject 13 | { 14 | public int page { get; set; } 15 | public bool hasMorePages { get; set; } 16 | public int count { get; set; } 17 | public Ranking[] rankings { get; set; } 18 | } 19 | 20 | public class Ranking 21 | { 22 | public string name { get; set; } 23 | [JsonProperty(PropertyName = "class")] 24 | public int _class { get; set; } 25 | public int spec { get; set; } 26 | public decimal total { get; set; } 27 | public int duration { get; set; } 28 | public long startTime { get; set; } 29 | public int fightID { get; set; } 30 | public string reportID { get; set; } 31 | public string guildName { get; set; } 32 | public string serverName { get; set; } 33 | public string regionName { get; set; } 34 | public int itemLevel { get; set; } 35 | public int exploit { get; set; } 36 | public Talent[] talents { get; set; } 37 | public Gear[] gear { get; set; } 38 | public int rankid { get; set; } 39 | public int size { get; set; } 40 | } 41 | 42 | public class Talent 43 | { 44 | public string name { get; set; } 45 | public int? id { get; set; } 46 | } 47 | 48 | public class Gear 49 | { 50 | public string name { get; set; } 51 | public string quality { get; set; } 52 | public int? id { get; set; } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Models/Wow/WowConnnectedRealm.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaBotCore.Models.Wow 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Converters; 8 | 9 | public class WowConnectedRealm 10 | { 11 | [JsonProperty("_links")] 12 | public Links Links { get; set; } 13 | 14 | [JsonProperty("id")] 15 | public long Id { get; set; } 16 | 17 | [JsonProperty("has_queue")] 18 | public bool HasQueue { get; set; } 19 | 20 | [JsonProperty("status")] 21 | public Population Status { get; set; } 22 | 23 | [JsonProperty("population")] 24 | public Population Population { get; set; } 25 | 26 | [JsonProperty("realms")] 27 | public Realm[] Realms { get; set; } 28 | 29 | [JsonProperty("mythic_leaderboards")] 30 | public Auctions MythicLeaderboards { get; set; } 31 | 32 | [JsonProperty("auctions")] 33 | public Auctions Auctions { get; set; } 34 | } 35 | 36 | public partial class Auctions 37 | { 38 | [JsonProperty("href")] 39 | public Uri Href { get; set; } 40 | } 41 | 42 | public class Links 43 | { 44 | [JsonProperty("self")] 45 | public Auctions Self { get; set; } 46 | } 47 | 48 | public partial class Population 49 | { 50 | [JsonProperty("type")] 51 | public string Type { get; set; } 52 | 53 | [JsonProperty("name")] 54 | public string Name { get; set; } 55 | } 56 | 57 | public partial class Realm 58 | { 59 | [JsonProperty("id")] 60 | public long Id { get; set; } 61 | 62 | [JsonProperty("region")] 63 | public Region Region { get; set; } 64 | 65 | [JsonProperty("connected_realm")] 66 | public Auctions ConnectedRealm { get; set; } 67 | 68 | [JsonProperty("name")] 69 | public string Name { get; set; } 70 | 71 | [JsonProperty("category")] 72 | public string Category { get; set; } 73 | 74 | [JsonProperty("locale")] 75 | public string Locale { get; set; } 76 | 77 | [JsonProperty("timezone")] 78 | public string Timezone { get; set; } 79 | 80 | [JsonProperty("type")] 81 | public Population Type { get; set; } 82 | 83 | [JsonProperty("is_tournament")] 84 | public bool IsTournament { get; set; } 85 | 86 | [JsonProperty("slug")] 87 | public string Slug { get; set; } 88 | } 89 | 90 | public class Region 91 | { 92 | [JsonProperty("key")] 93 | public Auctions AuctionsKey { get; set; } 94 | 95 | [JsonProperty("name")] 96 | public string Name { get; set; } 97 | 98 | [JsonProperty("id")] 99 | public long Id { get; set; } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Models/Wow/WowRealmResponseGuild.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gngrninja/NinjaBotCore/f869759589c48da910572f193d7b05c107f3728f/src/Models/Wow/WowRealmResponseGuild.cs -------------------------------------------------------------------------------- /src/Models/Wow/WowRealmSearch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NinjaBotCore.Models.Wow 8 | { 9 | public class WowRealmSearch 10 | { 11 | public class Category 12 | { 13 | public string it_IT { get; set; } 14 | public string ru_RU { get; set; } 15 | public string en_GB { get; set; } 16 | public string zh_TW { get; set; } 17 | public string ko_KR { get; set; } 18 | public string en_US { get; set; } 19 | public string es_MX { get; set; } 20 | public string pt_BR { get; set; } 21 | public string es_ES { get; set; } 22 | public string zh_CN { get; set; } 23 | public string fr_FR { get; set; } 24 | public string de_DE { get; set; } 25 | } 26 | 27 | public class Data 28 | { 29 | public bool is_tournament { get; set; } 30 | public string timezone { get; set; } 31 | public Name name { get; set; } 32 | public int id { get; set; } 33 | public Region region { get; set; } 34 | public Category category { get; set; } 35 | public string locale { get; set; } 36 | public Type type { get; set; } 37 | public string slug { get; set; } 38 | } 39 | 40 | public class Key 41 | { 42 | public string href { get; set; } 43 | } 44 | 45 | public class Name 46 | { 47 | public string it_IT { get; set; } 48 | public string ru_RU { get; set; } 49 | public string en_GB { get; set; } 50 | public string zh_TW { get; set; } 51 | public string ko_KR { get; set; } 52 | public string en_US { get; set; } 53 | public string es_MX { get; set; } 54 | public string pt_BR { get; set; } 55 | public string es_ES { get; set; } 56 | public string zh_CN { get; set; } 57 | public string fr_FR { get; set; } 58 | public string de_DE { get; set; } 59 | } 60 | 61 | public class Region 62 | { 63 | public Name name { get; set; } 64 | public int id { get; set; } 65 | } 66 | 67 | public class Result 68 | { 69 | public Key key { get; set; } 70 | public Data data { get; set; } 71 | } 72 | 73 | public class Root 74 | { 75 | public int page { get; set; } 76 | public int pageSize { get; set; } 77 | public int maxPageSize { get; set; } 78 | public int pageCount { get; set; } 79 | public List results { get; set; } 80 | } 81 | 82 | public class Type 83 | { 84 | public Name name { get; set; } 85 | public string type { get; set; } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Models/Wow/WowRealms.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NinjaBotCore.Models.Wow 8 | { 9 | public class WowRealm 10 | { 11 | public Realm[] realms { get; set; } 12 | 13 | public class Realm 14 | { 15 | public string type { get; set; } 16 | public string population { get; set; } 17 | public bool queue { get; set; } 18 | public bool status { get; set; } 19 | public int id { get; set; } 20 | public string name { get; set; } 21 | public string slug { get; set; } 22 | public string battlegroup { get; set; } 23 | public string locale { get; set; } 24 | public string timezone { get; set; } 25 | public string[] connected_realms { get; set; } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Models/Wow/WowSingleRealmInfo.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaBotCore.Models.Wow 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using Newtonsoft.Json; 7 | using Newtonsoft.Json.Converters; 8 | 9 | public partial class WowSingleRealmInfo 10 | { 11 | [JsonProperty("_links")] 12 | public Links Links { get; set; } 13 | 14 | [JsonProperty("id")] 15 | public long Id { get; set; } 16 | 17 | [JsonProperty("region")] 18 | public RealmRegion Region { get; set; } 19 | 20 | [JsonProperty("connected_realm")] 21 | public ConnectedRealm ConnectedRealm { get; set; } 22 | 23 | [JsonProperty("name")] 24 | public string Name { get; set; } 25 | 26 | [JsonProperty("category")] 27 | public string Category { get; set; } 28 | 29 | [JsonProperty("locale")] 30 | public string Locale { get; set; } 31 | 32 | [JsonProperty("timezone")] 33 | public string Timezone { get; set; } 34 | 35 | [JsonProperty("type")] 36 | public TypeClass Type { get; set; } 37 | 38 | [JsonProperty("is_tournament")] 39 | public bool IsTournament { get; set; } 40 | 41 | [JsonProperty("slug")] 42 | public string Slug { get; set; } 43 | } 44 | 45 | public partial class ConnectedRealm 46 | { 47 | [JsonProperty("href")] 48 | public Uri Href { get; set; } 49 | } 50 | 51 | public class SelfLinks 52 | { 53 | [JsonProperty("self")] 54 | public ConnectedRealm Self { get; set; } 55 | } 56 | 57 | public class RealmRegion 58 | { 59 | [JsonProperty("key")] 60 | public ConnectedRealm RegionKey { get; set; } 61 | 62 | [JsonProperty("name")] 63 | public string RegionName { get; set; } 64 | 65 | [JsonProperty("id")] 66 | public long RegionId { get; set; } 67 | } 68 | 69 | public partial class TypeClass 70 | { 71 | [JsonProperty("type")] 72 | public string Type { get; set; } 73 | 74 | [JsonProperty("name")] 75 | public string Name { get; set; } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Models/Wow/WowStats.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NinjaBotCore.Models.Wow; 3 | using Newtonsoft.Json; 4 | 5 | namespace NinjaBotCore.Models.Wow 6 | { 7 | public partial class WowStats 8 | { 9 | [JsonProperty("lastModified")] 10 | public long LastModified { get; set; } 11 | 12 | [JsonProperty("name")] 13 | public string Name { get; set; } 14 | 15 | [JsonProperty("realm")] 16 | public string Realm { get; set; } 17 | 18 | [JsonProperty("battlegroup")] 19 | public string Battlegroup { get; set; } 20 | 21 | [JsonProperty("class")] 22 | public long Class { get; set; } 23 | 24 | [JsonProperty("race")] 25 | public long Race { get; set; } 26 | 27 | [JsonProperty("gender")] 28 | public long Gender { get; set; } 29 | 30 | [JsonProperty("level")] 31 | public long Level { get; set; } 32 | 33 | [JsonProperty("achievementPoints")] 34 | public long AchievementPoints { get; set; } 35 | 36 | [JsonProperty("thumbnail")] 37 | public string Thumbnail { get; set; } 38 | 39 | [JsonProperty("calcClass")] 40 | public string CalcClass { get; set; } 41 | 42 | [JsonProperty("faction")] 43 | public long Faction { get; set; } 44 | 45 | [JsonProperty("statistics")] 46 | public Statistics Statistics { get; set; } 47 | 48 | [JsonProperty("totalHonorableKills")] 49 | public long TotalHonorableKills { get; set; } 50 | } 51 | 52 | public partial class Statistics 53 | { 54 | [JsonProperty("id")] 55 | public long Id { get; set; } 56 | 57 | [JsonProperty("name")] 58 | public string Name { get; set; } 59 | 60 | [JsonProperty("subCategories")] 61 | public SubCategory[] SubCategories { get; set; } 62 | } 63 | 64 | public partial class SubCategory 65 | { 66 | [JsonProperty("id")] 67 | public long Id { get; set; } 68 | 69 | [JsonProperty("name")] 70 | public string Name { get; set; } 71 | 72 | [JsonProperty("statistics")] 73 | public Statistic[] Statistics { get; set; } 74 | 75 | [JsonProperty("subCategories", NullValueHandling = NullValueHandling.Ignore)] 76 | public SubCategory[] SubCategories { get; set; } 77 | } 78 | 79 | public partial class Statistic 80 | { 81 | [JsonProperty("id")] 82 | public long Id { get; set; } 83 | 84 | [JsonProperty("name")] 85 | public string Name { get; set; } 86 | 87 | [JsonProperty("quantity")] 88 | public long Quantity { get; set; } 89 | 90 | [JsonProperty("lastUpdated")] 91 | public long LastUpdated { get; set; } 92 | 93 | [JsonProperty("money")] 94 | public bool Money { get; set; } 95 | 96 | [JsonProperty("highest", NullValueHandling = NullValueHandling.Ignore)] 97 | public string Highest { get; set; } 98 | } 99 | } -------------------------------------------------------------------------------- /src/Models/YouTube/YouTube.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace NinjaBotCore.Models.YouTube 3 | { 4 | public class YouTubeModel 5 | { 6 | public class Video 7 | { 8 | public string kind { get; set; } 9 | public string etag { get; set; } 10 | public string nextPageToken { get; set; } 11 | public string regionCode { get; set; } 12 | public Pageinfo pageInfo { get; set; } 13 | public Item[] items { get; set; } 14 | } 15 | 16 | public class Pageinfo 17 | { 18 | public int totalResults { get; set; } 19 | public int resultsPerPage { get; set; } 20 | } 21 | 22 | public class Item 23 | { 24 | public string kind { get; set; } 25 | public string etag { get; set; } 26 | public Id id { get; set; } 27 | public Snippet snippet { get; set; } 28 | } 29 | 30 | public class Id 31 | { 32 | public string kind { get; set; } 33 | public string videoId { get; set; } 34 | } 35 | 36 | public class Snippet 37 | { 38 | public DateTime publishedAt { get; set; } 39 | public string channelId { get; set; } 40 | public string title { get; set; } 41 | public string description { get; set; } 42 | public Thumbnails thumbnails { get; set; } 43 | public string channelTitle { get; set; } 44 | public string liveBroadcastContent { get; set; } 45 | } 46 | 47 | public class Thumbnails 48 | { 49 | public Default _default { get; set; } 50 | public Medium medium { get; set; } 51 | public High high { get; set; } 52 | } 53 | 54 | public class Default 55 | { 56 | public string url { get; set; } 57 | public int width { get; set; } 58 | public int height { get; set; } 59 | } 60 | 61 | public class Medium 62 | { 63 | public string url { get; set; } 64 | public int width { get; set; } 65 | public int height { get; set; } 66 | } 67 | 68 | public class High 69 | { 70 | public string url { get; set; } 71 | public int width { get; set; } 72 | public int height { get; set; } 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/Modules/Audio/Audio.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Discord.Commands; 3 | using NinjaBotCore.Services; 4 | using Discord.Audio; 5 | using Discord; 6 | 7 | namespace NinjaBotCore.Modules.Audio 8 | { 9 | public class AudioModule : ModuleBase 10 | { 11 | // Scroll down further for the AudioService. 12 | // Like, way down 13 | private readonly AudioService _service; 14 | 15 | // Remember to add an instance of the AudioService 16 | // to your IServiceCollection when you initialize your bot 17 | public AudioModule(AudioService service) 18 | { 19 | _service = service; 20 | } 21 | 22 | // You *MUST* mark these commands with 'RunMode.Async' 23 | // otherwise the bot will not respond until the Task times out. 24 | [RequireOwner] 25 | [Command("join", RunMode = RunMode.Async)] 26 | public async Task JoinCmd() 27 | { 28 | await _service.JoinAudio(Context.Guild, (Context.User as IVoiceState).VoiceChannel); 29 | } 30 | 31 | // Remember to add preconditions to your commands, 32 | // this is merely the minimal amount necessary. 33 | // Adding more commands of your own is also encouraged. 34 | [RequireOwner] 35 | [Command("leave", RunMode = RunMode.Async)] 36 | public async Task LeaveCmd() 37 | { 38 | await _service.LeaveAudio(Context.Guild); 39 | } 40 | 41 | [RequireOwner] 42 | [Command("njaplay", RunMode = RunMode.Async)] 43 | public async Task PlayCmd([Remainder] string song) 44 | { 45 | await _service.SendAudioAsync(Context.Guild, Context.Channel, song); 46 | } 47 | 48 | [RequireOwner] 49 | [Command("snekpete")] 50 | public async Task PlayHi() 51 | { 52 | await _service.JoinAudio(Context.Guild, (Context.User as IVoiceState).VoiceChannel); 53 | await _service.SendAudioAsync(Context.Guild, Context.Channel, "hi.mp3"); 54 | await _service.LeaveAudio(Context.Guild); 55 | } 56 | 57 | [RequireOwner] 58 | [Command("oom")] 59 | public async Task PlayShunt() 60 | { 61 | await _service.JoinAudio(Context.Guild, (Context.User as IVoiceState).VoiceChannel); 62 | await _service.SendAudioAsync(Context.Guild, Context.Channel, "mana.mp3"); 63 | await _service.LeaveAudio(Context.Guild); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/Modules/AwaySystem/AwayData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using NinjaBotCore.Database; 7 | using NinjaBotCore.Services; 8 | 9 | namespace NinjaBotCore.Modules.Away 10 | { 11 | public class AwayData 12 | { 13 | public void setAwayUser(AwaySystem awayInfo) 14 | { 15 | 16 | var awayUser = new AwaySystem(); 17 | 18 | using (var db = new NinjaBotEntities()) 19 | { 20 | awayUser = db.AwaySystem.Where(a => a.UserName == awayInfo.UserName).FirstOrDefault(); 21 | if (awayUser == null) 22 | { 23 | db.AwaySystem.Add(awayInfo); 24 | } 25 | else 26 | { 27 | awayUser.Status = awayInfo.Status; 28 | awayUser.Message = awayInfo.Message; 29 | awayUser.TimeAway = awayInfo.TimeAway; 30 | } 31 | db.SaveChanges(); 32 | } 33 | } 34 | 35 | public AwaySystem getAwayUser(string discordUserName) 36 | { 37 | var awayUser = new AwaySystem(); 38 | using (var db = new NinjaBotEntities()) 39 | { 40 | awayUser = db.AwaySystem.Where(a => a.UserName == discordUserName).FirstOrDefault(); 41 | } 42 | return awayUser; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Modules/Interactions/Misc/AwayCommands.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Discord; 7 | using Discord.WebSocket; 8 | using NinjaBotCore.Database; 9 | using NinjaBotCore.Services; 10 | using Microsoft.Extensions.Logging; 11 | using NinjaBotCore.Modules.Away; 12 | using Discord.Interactions; 13 | 14 | namespace NinjaBotCore.Modules.Interactions.Away 15 | { 16 | public class AwayCommands : InteractionModuleBase 17 | { 18 | private static bool _isLinked = false; 19 | private static ChannelCheck _cc = null; 20 | private static DiscordShardedClient _client; 21 | private readonly ILogger _logger; 22 | //Work on way to do this when bot starts 23 | public AwayCommands(DiscordShardedClient client, ILogger logger) 24 | { 25 | _logger = logger; 26 | if (!_isLinked) 27 | { 28 | client.MessageReceived += AwayMentionFinder; 29 | _logger.LogInformation($"Hooked into message received for away commands."); 30 | } 31 | _isLinked = true; 32 | if (_cc == null) 33 | { 34 | _cc = new ChannelCheck(); 35 | } 36 | if (_client == null) 37 | { 38 | _client = client; 39 | } 40 | } 41 | 42 | [SlashCommand("away", "set yourself as away, replying to @mentions of you")] 43 | public async Task SetAway(string input) 44 | { 45 | try 46 | { 47 | StringBuilder sb = new StringBuilder(); 48 | var message = input; 49 | var user = Context.User; 50 | string userName = string.Empty; 51 | string userMentionName = string.Empty; 52 | if (user != null) 53 | { 54 | userName = user.Username; 55 | userMentionName = user.Mention; 56 | } 57 | var data = new AwayData(); 58 | var away = new AwaySystem(); 59 | var attempt = data.getAwayUser(userName); 60 | 61 | if (string.IsNullOrEmpty(message.ToString())) 62 | { 63 | message = "No message set!"; 64 | } 65 | if (attempt != null) 66 | { 67 | away.UserName = attempt.UserName; 68 | away.Status = attempt.Status; 69 | if ((bool)away.Status) 70 | { 71 | sb.AppendLine($"You're already away, **{userMentionName}**!"); 72 | } 73 | else 74 | { 75 | sb.AppendLine($"Marking you as away, **{userMentionName}**, with the message: *{message.ToString()}*"); 76 | away.Status = true; 77 | away.Message = message; 78 | away.UserName = userName; 79 | away.TimeAway = DateTime.Now; 80 | 81 | var awayData = new AwayData(); 82 | awayData.setAwayUser(away); 83 | } 84 | } 85 | else 86 | { 87 | sb.AppendLine($"Marking you as away, **{userMentionName}**, with the message: *{message.ToString()}*"); 88 | away.Status = true; 89 | away.Message = message; 90 | away.UserName = userName; 91 | away.TimeAway = DateTime.Now; 92 | 93 | var awayData = new AwayData(); 94 | awayData.setAwayUser(away); 95 | } 96 | await RespondAsync(sb.ToString(), ephemeral: true); 97 | } 98 | catch (Exception ex) 99 | { 100 | StringBuilder sb = new StringBuilder(); 101 | sb.AppendLine("Something went wrong setting you away :("); 102 | _logger.LogError($"Away command error {ex.Message}"); 103 | await RespondAsync(sb.ToString(), ephemeral: true); 104 | } 105 | } 106 | 107 | [SlashCommand("back", "set yourself as back from being away")] 108 | public async Task SetBack(bool forced = false, IGuildUser forceUser = null) 109 | { 110 | try 111 | { 112 | IGuildUser user = null; 113 | StringBuilder sb = new StringBuilder(); 114 | var data = new AwayData(); 115 | if (forced) 116 | { 117 | user = forceUser; 118 | } 119 | else 120 | { 121 | user = Context.User as IGuildUser; 122 | } 123 | 124 | string userName = string.Empty; 125 | string userMentionName = string.Empty; 126 | if (user != null) 127 | { 128 | userName = user.Username; 129 | userMentionName = user.Mention; 130 | } 131 | var attempt = data.getAwayUser(userName); 132 | var away = new AwaySystem(); 133 | 134 | if (attempt != null) 135 | { 136 | away.UserName = attempt.UserName; 137 | away.Status = attempt.Status; 138 | if (!(bool)away.Status) 139 | { 140 | sb.AppendLine($"You're not even away yet, **{userMentionName}**"); 141 | } 142 | else 143 | { 144 | away.Status = false; 145 | away.Message = string.Empty; 146 | var awayData = new AwayData(); 147 | awayData.setAwayUser(away); 148 | string awayDuration = string.Empty; 149 | if (attempt.TimeAway.HasValue) 150 | { 151 | var awayTime = DateTime.Now - attempt.TimeAway; 152 | if (awayTime.HasValue) 153 | { 154 | awayDuration = $"**{awayTime.Value.Days}** days, **{awayTime.Value.Hours}** hours, **{awayTime.Value.Minutes}** minutes, and **{awayTime.Value.Seconds}** seconds"; 155 | } 156 | } 157 | if (forced) 158 | { 159 | sb.AppendLine($"You're now set as back **{userMentionName}** (forced by: **{Context.User.Username}**)!"); 160 | } 161 | else 162 | { 163 | sb.AppendLine($"You're now set as back, **{userMentionName}**!"); 164 | } 165 | sb.AppendLine($"You were away for: [{awayDuration}]"); 166 | } 167 | await RespondAsync(sb.ToString(), ephemeral: true); 168 | } 169 | } 170 | catch (Exception ex) 171 | { 172 | StringBuilder sb = new StringBuilder(); 173 | sb.AppendLine("Something went wrong marking you as back :("); 174 | _logger.LogError($"Back command error {ex.Message}"); 175 | await RespondAsync(sb.ToString()); 176 | } 177 | } 178 | 179 | [SlashCommand("set-back-forced", "force a user as being back from away")] 180 | [RequireUserPermission(GuildPermission.KickMembers)] 181 | public async Task SetBack(IGuildUser user) 182 | { 183 | await SetBack(forced: true, forceUser: user); 184 | } 185 | 186 | private async Task AwayMentionFinder(SocketMessage messageDetails) 187 | { 188 | await Task.Run(async () => 189 | { 190 | var message = messageDetails as SocketUserMessage; 191 | if (!messageDetails.Author.IsBot) 192 | { 193 | var userMentioned = messageDetails.MentionedUsers.ToList(); 194 | if (userMentioned != null) 195 | { 196 | foreach (var user in userMentioned) 197 | { 198 | var awayData = new AwayData(); 199 | var awayUser = awayData.getAwayUser(user.Username); 200 | if (awayUser != null) 201 | { 202 | string awayDuration = string.Empty; 203 | if (awayUser.TimeAway.HasValue) 204 | { 205 | var awayTime = DateTime.Now - awayUser.TimeAway; 206 | if (awayTime.HasValue) 207 | { 208 | awayDuration = $"**{awayTime.Value.Days}** days, **{awayTime.Value.Hours}** hours, **{awayTime.Value.Minutes}** minutes, and **{awayTime.Value.Seconds}** seconds"; 209 | } 210 | } 211 | _logger.LogInformation($"Mentioned user {user.Username} -> {awayUser.UserName} -> {awayUser.Status}"); 212 | if ((bool)awayUser.Status) 213 | { 214 | if (user.Username == (awayUser.UserName)) 215 | { 216 | SocketGuild guild = (message.Channel as SocketGuildChannel)?.Guild; 217 | EmbedBuilder embed = new EmbedBuilder(); 218 | embed.WithColor(new Color(0, 71, 171)); 219 | 220 | if (!string.IsNullOrWhiteSpace(guild.IconUrl)) 221 | { 222 | embed.ThumbnailUrl = user.GetAvatarUrl(); 223 | } 224 | 225 | embed.Title = $":clock: {awayUser.UserName} is away! :clock:"; 226 | embed.Description = $"Since: **{awayUser.TimeAway}\n**Duration: {awayDuration}\nMessage: {awayUser.Message}"; 227 | await messageDetails.Channel.SendMessageAsync("", false, embed.Build()); 228 | } 229 | } 230 | } 231 | } 232 | } 233 | } 234 | }); 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /src/Modules/Interactions/Misc/FunCommands.cs: -------------------------------------------------------------------------------- 1 | using NinjaBotCore.Database; 2 | using Discord; 3 | using Discord.WebSocket; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using Microsoft.Extensions.Configuration; 10 | using NinjaBotCore.Services; 11 | using Discord.Interactions; 12 | 13 | namespace NinjaBotCore.Modules.Interactions.Fun 14 | { 15 | public class FunCommands : InteractionModuleBase 16 | { 17 | private static ChannelCheck _cc = null; 18 | 19 | private DiscordShardedClient _client; 20 | private readonly IConfigurationRoot _config; 21 | private string _prefix; 22 | 23 | public FunCommands(DiscordShardedClient client, ChannelCheck cc, IConfigurationRoot config) 24 | { 25 | try 26 | { 27 | _cc = cc; 28 | _client = client; 29 | _config = config; 30 | _prefix = _config["prefix"]; 31 | } 32 | catch (Exception ex) 33 | { 34 | Console.WriteLine($"Something went wrong creating the fun class: {ex.Message}"); 35 | } 36 | } 37 | 38 | [SlashCommand("setstatus", "set status of the bot")] 39 | [RequireOwner] 40 | public async Task SetStatus(string args = null) 41 | { 42 | await _client.SetGameAsync(args); 43 | } 44 | 45 | [SlashCommand("donate", "donate!")] 46 | public async Task Donate() 47 | { 48 | var embed = new EmbedBuilder(); 49 | StringBuilder sb = new StringBuilder(); 50 | 51 | sb.AppendLine($"Would you like to help keep NinjaBot going?"); 52 | sb.AppendLine(); 53 | sb.AppendLine($"Every little bit counts!"); 54 | sb.AppendLine(); 55 | sb.AppendLine($"[Donate To Support NinjaBot!]({_config["DonateUrl"]}/5) :thumbsup:"); 56 | 57 | embed.ThumbnailUrl = "https://static1.squarespace.com/static/5644323de4b07810c0b6db7b/t/5931c57f46c3c47b464d717a/1496434047310/FdxsNNRt.jpg"; 58 | embed.WithColor(new Color(0, 255, 0)); 59 | embed.Title = $"{Context.User.Username}, help keep NinjaBot going!"; 60 | embed.Description = sb.ToString(); 61 | 62 | await RespondAsync(embed: embed.Build(), ephemeral: true); 63 | } 64 | 65 | 66 | [SlashCommand("8ball", "Ask Ninja 8-ball a question!")] 67 | public async Task AskQuestion(string args) 68 | { 69 | var embed = new EmbedBuilder(); 70 | Random r = new Random(); 71 | var answers = new List(); 72 | using (var db = new NinjaBotEntities()) 73 | { 74 | answers = db.C8Ball.ToList(); 75 | if (answers == null) 76 | { 77 | answers.Add(new C8Ball 78 | { 79 | AnswerId = 0, 80 | Answer = "No! (cant access DB)", 81 | Color = "Red" 82 | }); 83 | } 84 | } 85 | var answer = answers[r.Next(answers.Count())]; 86 | string answerText = string.Empty; 87 | if (answer != null) 88 | { 89 | answerText = answer.Answer; 90 | switch (answer.Color.ToLower()) 91 | { 92 | case "yellow": 93 | { 94 | embed.WithColor(new Color(255, 255, 0)); 95 | break; 96 | } 97 | case "red": 98 | { 99 | embed.WithColor(new Color(255, 0, 0)); 100 | break; 101 | } 102 | case "green": 103 | { 104 | embed.WithColor(new Color(0, 128, 0)); 105 | break; 106 | } 107 | } 108 | StringBuilder sb = new StringBuilder(); 109 | sb.AppendLine("** **"); 110 | sb.AppendLine($"**{answerText}**"); 111 | sb.AppendLine("** **\n"); 112 | embed.Description = sb.ToString(); 113 | } 114 | embed.ThumbnailUrl = Context.User.GetAvatarUrl(); 115 | embed.Title = $":crystal_ball: Ninja 8-Ball: (**{args}**) :crystal_ball:"; 116 | await RespondAsync(embed: embed.Build()); 117 | } 118 | 119 | [SlashCommand("ping", "get ping time")] 120 | private async Task GetPing() 121 | { 122 | string pingTime = string.Empty; 123 | pingTime = $"Ping time for bot is **{_client.Latency}**ms"; 124 | await RespondAsync(pingTime); 125 | } 126 | 127 | [SlashCommand("help", "get ninjabot help")] 128 | public async Task Help() 129 | { 130 | var embed = new EmbedBuilder(); 131 | StringBuilder sb = new StringBuilder(); 132 | 133 | embed.Title = $"NinjaBot Help!"; 134 | embed.ThumbnailUrl = Context.User.GetAvatarUrl(); 135 | embed.WithColor(new Color(0, 0, 255)); 136 | 137 | var helpTxt = await System.IO.File.ReadAllLinesAsync("help.txt"); 138 | 139 | foreach (var line in helpTxt) 140 | { 141 | sb.AppendLine(line).Replace('!',Char.Parse(_prefix)); 142 | } 143 | 144 | embed.Description = sb.ToString(); 145 | await RespondAsync(embed: embed.Build(), ephemeral: true); 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /src/Modules/Interactions/Wow/WowAdminInteract.cs: -------------------------------------------------------------------------------- 1 | using Discord; 2 | using Discord.Interactions; 3 | using NinjaBotCore.Attributes; 4 | using System; 5 | using System.Threading.Tasks; 6 | using NinjaBotCore.Services; 7 | using System.Linq; 8 | using System.Text; 9 | using Discord.Net; 10 | using Discord.WebSocket; 11 | using System.Text.RegularExpressions; 12 | using Microsoft.Extensions.Configuration; 13 | using Microsoft.Extensions.Logging; 14 | using Microsoft.Extensions.DependencyInjection; 15 | using NinjaBotCore.Common; 16 | using System.Threading; 17 | using NinjaBotCore.Modules.Wow; 18 | using NinjaBotCore.Models.Wow; 19 | using NinjaBotCore.Database; 20 | using System.Collections.Generic; 21 | 22 | namespace NinjaBotCore.Modules.Interactions.Wow 23 | { 24 | // Interaction modules must be public and inherit from an IInteractionModuleBase 25 | public class WowAdminInteract : InteractionModuleBase 26 | { 27 | private ChannelCheck _cc; 28 | private WarcraftLogs _logsApi; 29 | private WowApi _wowApi; 30 | private DiscordShardedClient _client; 31 | private RaiderIOApi _rioApi; 32 | private readonly IConfigurationRoot _config; 33 | private string _prefix; 34 | private readonly ILogger _logger; 35 | private WowUtilities _wowUtils; 36 | 37 | public WowAdminInteract(IServiceProvider services) 38 | { 39 | _logger = services.GetRequiredService>(); 40 | _wowUtils = services.GetRequiredService(); 41 | _cc = services.GetRequiredService(); 42 | _logsApi = services.GetRequiredService(); 43 | _wowApi = services.GetRequiredService(); 44 | _rioApi = services.GetRequiredService(); 45 | _client = services.GetRequiredService(); 46 | _config = services.GetRequiredService(); 47 | } 48 | 49 | [SlashCommand("populatelogs", "populate logs")] 50 | [Discord.Interactions.RequireOwner] 51 | public async Task PopulateLogs() 52 | { 53 | { 54 | List guildList = null; 55 | List logWatchList = null; 56 | try 57 | { 58 | using (var db = new NinjaBotEntities()) 59 | { 60 | guildList = db.WowGuildAssociations.ToList(); 61 | logWatchList = db.LogMonitoring.ToList(); 62 | } 63 | } 64 | catch (Exception ex) 65 | { 66 | _logger.LogError($"Error getting guild/logwatch list -> [{ex.Message}]"); 67 | } 68 | if (guildList != null) 69 | { 70 | foreach (var guild in guildList) 71 | { 72 | try 73 | { 74 | var watchGuild = logWatchList.Where(w => w.ServerId == guild.ServerId).FirstOrDefault(); 75 | if (watchGuild != null) 76 | { 77 | if (watchGuild.MonitorLogs) 78 | { 79 | //System._logger.LogInformation($"YES! Watch logs on {guild.ServerName}!"); 80 | var logs = await _logsApi.GetReportsFromGuild(guildName: guild.WowGuild, realm: guild.WowRealm.Replace("'", ""), region: guild.WowRegion); 81 | if (logs != null) 82 | { 83 | var latestLog = logs[logs.Count - 1]; 84 | DateTime startTime = _wowApi.UnixTimeStampToDateTime(latestLog.start); 85 | { 86 | using (var db = new NinjaBotEntities()) 87 | { 88 | var latestForGuild = db.LogMonitoring.Where(l => l.ServerId == guild.ServerId).FirstOrDefault(); 89 | latestForGuild.LatestLogRetail = startTime; 90 | latestForGuild.RetailReportId = latestLog.id; 91 | await db.SaveChangesAsync(); 92 | } 93 | //System._logger.LogInformation($"Updated [{watchGuild.ServerName}] -> [{latestLog.id}] [{latestLog.owner}]!"); 94 | } 95 | } 96 | } 97 | } 98 | } 99 | catch (Exception ex) 100 | { 101 | _logger.LogError($"Error checking for logs! -> [{ex.Message}]"); 102 | } 103 | } 104 | } 105 | } 106 | } 107 | 108 | [SlashCommand("removeachievement", "remove achivement")] 109 | [Discord.Interactions.RequireOwner] 110 | public async Task RemoveAchieve(long id) 111 | { 112 | using (var db = new NinjaBotEntities()) 113 | { 114 | var foundCheeve = db.FindWowCheeves.Where(c => c.AchId == id).FirstOrDefault(); 115 | if (foundCheeve != null) 116 | { 117 | db.Remove(foundCheeve); 118 | await db.SaveChangesAsync(); 119 | await RespondAsync($"Removed achievement id {id} from the database!"); 120 | } 121 | else 122 | { 123 | await RespondAsync($"Sorry, unable to find achievement ID {id} in the database!"); 124 | } 125 | } 126 | } 127 | 128 | [SlashCommand("addachievement", "add achivement")] 129 | [Discord.Interactions.RequireOwner] 130 | public async Task AddAchieve(long id, int cat) 131 | { 132 | using (var db = new NinjaBotEntities()) 133 | { 134 | var foundCheeve = db.FindWowCheeves.Where(c => c.AchId == id); 135 | if (foundCheeve != null) 136 | { 137 | var category = db.AchCategories.Where(c => c.CatId == cat).FirstOrDefault(); 138 | if (category != null) 139 | { 140 | try 141 | { 142 | db.FindWowCheeves.Add(new FindWowCheeve 143 | { 144 | AchId = id, 145 | AchCategory = category 146 | }); 147 | await db.SaveChangesAsync(); 148 | await RespondAsync($"Added achievement ID {id} with category {category.CatName} to the database!"); 149 | } 150 | catch (Exception ex) 151 | { 152 | _logger.LogError($"{ex.Message}"); 153 | } 154 | } 155 | else 156 | { 157 | await RespondAsync($"Unable to find category with ID {cat} in the database!"); 158 | } 159 | 160 | } 161 | else 162 | { 163 | await RespondAsync($"Sorry, achievement {id} already exists in the database!"); 164 | } 165 | } 166 | } 167 | 168 | [SlashCommand("listachievements", "list achivements")] 169 | [Discord.Interactions.RequireOwner] 170 | public async Task ListCheeves() 171 | { 172 | StringBuilder sb = new StringBuilder(); 173 | List cheeves = new List(); 174 | using (var db = new NinjaBotEntities()) 175 | { 176 | cheeves = db.FindWowCheeves.ToList(); 177 | } 178 | if (cheeves.Count > 0) 179 | { 180 | foreach (var cheeve in cheeves) 181 | { 182 | sb.AppendLine($"{cheeve.AchId}"); 183 | } 184 | } 185 | await RespondAsync(sb.ToString()); 186 | } 187 | 188 | [SlashCommand("tu", "start wcl timer")] 189 | [Discord.Interactions.RequireOwner] 190 | public async Task StartTimer() 191 | { 192 | await _logsApi.StartTimer(); 193 | } 194 | 195 | [SlashCommand("td", "stop wcl timer")] 196 | [Discord.Interactions.RequireOwner] 197 | public async Task StopTimer() 198 | { 199 | await _logsApi.StopTimer(); 200 | } 201 | 202 | [SlashCommand("get-latest-zone", "get latest zone")] 203 | [Discord.Interactions.RequireOwner] 204 | public async Task GetLatestZone() 205 | { 206 | var zone = WarcraftLogs.Zones[WarcraftLogs.Zones.Count - 1]; 207 | var encounters = zone.encounters.Select(s => s.name).ToList(); 208 | 209 | var embed = new EmbedBuilder(); 210 | var sb = new StringBuilder(); 211 | 212 | foreach (var encounter in encounters) 213 | { 214 | sb.AppendLine($"*{encounter}*"); 215 | } 216 | 217 | embed.Title = $"{zone.name}"; 218 | 219 | embed.AddField(new EmbedFieldBuilder 220 | { 221 | Name = "ID", 222 | Value = $"*{zone.id.ToString()}*", 223 | 224 | }); 225 | 226 | embed.AddField(new EmbedFieldBuilder 227 | { 228 | Name = "Encounters", 229 | Value = sb.ToString() 230 | 231 | }); 232 | 233 | await RespondAsync(embed: embed.Build()); 234 | } 235 | 236 | [SlashCommand("set-zone", "set zone")] 237 | [Discord.Interactions.RequireOwner] 238 | public async Task SetLatestZone(string args = null) 239 | { 240 | Zones zone = null; 241 | int currentId = 0; 242 | string name = string.Empty; 243 | 244 | if (args == null) 245 | { 246 | zone = WarcraftLogs.Zones[WarcraftLogs.Zones.Count - 1]; 247 | currentId = zone.id; 248 | name = zone.name; 249 | } 250 | else 251 | { 252 | currentId = int.Parse(args); 253 | zone = WarcraftLogs.Zones.Where(z => z.id == currentId).FirstOrDefault(); 254 | name = zone.name; 255 | } 256 | 257 | var embed = new EmbedBuilder(); 258 | embed.Title = "Raid tier setter for NinjaBot"; 259 | try 260 | { 261 | await _wowUtils.SetLatestRaid(zone); 262 | embed.Description = $"Raid tier set to [{zone.id}] -> [{zone.name}]"; 263 | } 264 | catch (Exception ex) 265 | { 266 | _logger.LogError($"Error setting db to new raid -> [{ex.Message}]"); 267 | embed.Description = $"Error setting raid tier!"; 268 | } 269 | await RespondAsync(embed: embed.Build()); 270 | } 271 | 272 | [SlashCommand("set-partition", "set partition")] 273 | [Discord.Interactions.RequireOwner] 274 | public async Task SetPartition(string args = null) 275 | { 276 | var embed = new EmbedBuilder(); 277 | embed.Title = "Parition setter for NinjaBot"; 278 | int? partition = int.Parse(args.Trim()); 279 | try 280 | { 281 | if (partition != null) 282 | { 283 | using (var db = new NinjaBotEntities()) 284 | { 285 | var curTier = db.CurrentRaidTier.FirstOrDefault(); 286 | curTier.Partition = partition; 287 | await db.SaveChangesAsync(); 288 | } 289 | } 290 | embed.Description = $"Parition set to {partition}"; 291 | } 292 | catch (Exception ex) 293 | { 294 | _logger.LogError($"Error setting partition -> [{ex.Message}]"); 295 | embed.Description = "Error setting parition!"; 296 | } 297 | await RespondAsync(embed: embed.Build()); 298 | WarcraftLogs.CurrentRaidTier.Partition = partition; 299 | } 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /src/Modules/Interactions/Wow/WowClassicInteract.cs: -------------------------------------------------------------------------------- 1 | using Discord; 2 | using Discord.Interactions; 3 | using NinjaBotCore.Attributes; 4 | using System; 5 | using System.Threading.Tasks; 6 | using NinjaBotCore.Services; 7 | using System.Linq; 8 | using System.Text; 9 | using Discord.Net; 10 | using Discord.WebSocket; 11 | using System.Text.RegularExpressions; 12 | using Microsoft.Extensions.Configuration; 13 | using Microsoft.Extensions.Logging; 14 | using Microsoft.Extensions.DependencyInjection; 15 | using NinjaBotCore.Common; 16 | using System.Threading; 17 | using NinjaBotCore.Modules.Wow; 18 | using NinjaBotCore.Models.Wow; 19 | using NinjaBotCore.Database; 20 | using System.Collections.Generic; 21 | 22 | namespace NinjaBotCore.Modules.Interactions.Wow 23 | { 24 | public class WowClassicInteract : InteractionModuleBase 25 | { 26 | private readonly ILogger _logger; 27 | private readonly List _wclRegions = new List{"US", "EU", "KR", "TW", "CN"}; 28 | private readonly ChannelCheck _cc; 29 | private WarcraftLogs _wclLogsApi; 30 | 31 | public WowClassicInteract(IServiceProvider services) 32 | { 33 | _logger = services.GetRequiredService>(); 34 | _cc = services.GetRequiredService(); 35 | _wclLogsApi = services.GetRequiredService(); 36 | } 37 | 38 | [SlashCommand("getclassicguild", "get classic guild info")] 39 | public async Task GetClassicGuild() 40 | { 41 | var sb = new StringBuilder(); 42 | var embed = new EmbedBuilder(); 43 | WowClassicGuild wowClassicGuild = null; 44 | 45 | embed.Title = $"[{Context.Guild.Name}] WoW Classic Guild Association"; 46 | embed.ThumbnailUrl = Context.Guild.IconUrl; 47 | using (var db = new NinjaBotEntities()) 48 | { 49 | wowClassicGuild = db.WowClassicGuild.Where(g => g.ServerId == (long)Context.Guild.Id).FirstOrDefault(); 50 | } 51 | if (wowClassicGuild != null) 52 | { 53 | sb.AppendLine($"**Guild Name:** {wowClassicGuild.WowGuild}"); 54 | sb.AppendLine($"**Realm:** {wowClassicGuild.WowRealm}"); 55 | sb.AppendLine($"**Region:** {wowClassicGuild.WowRegion}"); 56 | } 57 | else 58 | { 59 | sb.AppendLine($"There is no guild associated to this server!"); 60 | } 61 | embed.WithColor(0, 255, 155); 62 | embed.Description = sb.ToString(); 63 | await RespondAsync(embed: embed.Build(), ephemeral: true); 64 | } 65 | 66 | [SlashCommand("setclassicguild", "set classic guild")] 67 | [RequireUserPermission(GuildPermission.KickMembers)] 68 | public async Task SetClassicGuild(string guildName, string realm, string region = "US") 69 | { 70 | var embed = new EmbedBuilder(); 71 | var wowClassicGuild = new WowClassicGuild(); 72 | var sb = new StringBuilder(); 73 | 74 | embed.ThumbnailUrl = Context.Guild.IconUrl; 75 | 76 | if (!_wclRegions.Contains(region.ToUpper())) 77 | { 78 | embed.Title = "Error setting guild!"; 79 | embed.WithColor(255, 0 , 0); 80 | sb.AppendLine("Please specify a valid region."); 81 | sb.AppendLine(); 82 | sb.AppendLine("**Possible regions:**"); 83 | foreach (var reg in _wclRegions) 84 | { 85 | sb.AppendLine(reg); 86 | } 87 | embed.Description = sb.ToString(); 88 | await RespondAsync(embed: embed.Build(), ephemeral: true); 89 | return; 90 | } 91 | 92 | wowClassicGuild.ServerId = (long)Context.Guild.Id; 93 | wowClassicGuild.SetById = (long)Context.User.Id; 94 | wowClassicGuild.WowGuild = guildName; 95 | wowClassicGuild.WowRealm = realm; 96 | wowClassicGuild.WowRegion = region; 97 | wowClassicGuild.SetBy = Context.User.Username; 98 | wowClassicGuild.TimeSet = DateTime.Now; 99 | wowClassicGuild.ServerName = Context.Guild.Name; 100 | 101 | try 102 | { 103 | using (var db = new NinjaBotEntities()) 104 | { 105 | var currentGuild = db.WowClassicGuild.Where(g => g.ServerId == (long)Context.Guild.Id).FirstOrDefault(); 106 | if (currentGuild != null) 107 | { 108 | db.Remove(currentGuild); 109 | } 110 | db.WowClassicGuild.Add(wowClassicGuild); 111 | await db.SaveChangesAsync(); 112 | } 113 | embed.Title = $"[{Context.Guild.Name}] WoW Classic Guild Association"; 114 | sb.AppendLine($"**Guild Name:** {wowClassicGuild.WowGuild}"); 115 | sb.AppendLine($"**Realm:** {wowClassicGuild.WowRealm}"); 116 | sb.AppendLine($"**Region:** {wowClassicGuild.WowRegion}"); 117 | embed.Description = sb.ToString(); 118 | embed.WithFooter(new EmbedFooterBuilder 119 | { 120 | Text = $"Change made by [{Context.User.Username}]", 121 | IconUrl = Context.User.GetAvatarUrl() 122 | }); 123 | embed.WithColor(0, 255, 155); 124 | await RespondAsync(embed: embed.Build(), ephemeral: true); 125 | } 126 | catch (Exception ex) 127 | { 128 | _logger.LogError($"Error setting classic guild for {Context.Guild.Name} -> [{ex.Message}]"); 129 | } 130 | 131 | } 132 | 133 | [SlashCommand("logsclassic", "get classic logs")] 134 | public async Task GetLogsClassic() 135 | { 136 | var embed = new EmbedBuilder(); 137 | var sb = new StringBuilder(); 138 | int maxReturn = 2; 139 | WowClassicGuild wowClassicGuild = null; 140 | using (var db = new NinjaBotEntities()) 141 | { 142 | wowClassicGuild = db.WowClassicGuild.Where(g => g.ServerId == (long)Context.Guild.Id).FirstOrDefault(); 143 | } 144 | if (wowClassicGuild != null) 145 | { 146 | var guildLogs = await _wclLogsApi.GetReportsFromGuildClassic(wowClassicGuild.WowGuild, wowClassicGuild.WowRealm, wowClassicGuild.WowRegion); 147 | if (guildLogs.Count > 0) 148 | { 149 | sb.AppendLine(); 150 | for (int i = 0; i <= (guildLogs.Count) && i <= maxReturn ; i++) 151 | { 152 | sb.AppendLine($"[__**{guildLogs[i].title}** **/** **{guildLogs[i].zoneName}**__]({guildLogs[i].reportURL})"); 153 | sb.AppendLine($"\t:timer: Start time: **{_wclLogsApi.UnixTimeStampToDateTime(guildLogs[i].start).ToLocalTime()}**"); 154 | sb.AppendLine($"\t:stopwatch: End time: **{_wclLogsApi.UnixTimeStampToDateTime(guildLogs[i].end).ToLocalTime()}**"); 155 | sb.AppendLine($"\t:pencil2: Created by [**{guildLogs[i].owner}**]"); 156 | sb.AppendLine(); 157 | } 158 | _logger.LogInformation($"Sending logs to {Context.Channel.Name}, requested by {Context.User.Username}"); 159 | embed.Title = $":1234: __Logs for **{wowClassicGuild.WowGuild}** on **{wowClassicGuild.WowRealm}**__:1234: "; 160 | embed.Description = sb.ToString(); 161 | embed.WithColor(0, 255, 100); 162 | await RespondAsync(embed: embed.Build(), ephemeral: true); 163 | } 164 | } 165 | } 166 | 167 | [SlashCommand("listclassicfights", "list classic fights")] 168 | [Discord.Interactions.RequireOwner] 169 | public async Task GetClassicZones(string args = null) 170 | { 171 | var zones = await _wclLogsApi.GetClassicZones(); 172 | Zones latest = null; 173 | if (args == null) 174 | { 175 | latest = zones[zones.Count - 2]; 176 | } 177 | else 178 | { 179 | if (args.ToLower() == "bwl") 180 | { 181 | args = "Blackwing Lair"; 182 | } 183 | if (args.ToLower() == "mc") 184 | { 185 | args = "Molten Core"; 186 | } 187 | latest = zones.Where(z => z.name.ToLower() == args.ToLower()).FirstOrDefault(); 188 | } 189 | var sb = new StringBuilder(); 190 | if (latest != null) 191 | { 192 | sb.AppendLine($"fights for [{latest.name}]"); 193 | foreach (var fight in latest.encounters) 194 | { 195 | sb.AppendLine($"id [{fight.id}] name [{fight.name}]"); 196 | } 197 | } 198 | await RespondAsync(sb.ToString()); 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/Modules/Interactions/Wow/WowVanillaInteract.cs: -------------------------------------------------------------------------------- 1 | using Discord; 2 | using Discord.Interactions; 3 | using NinjaBotCore.Attributes; 4 | using System; 5 | using System.Threading.Tasks; 6 | using NinjaBotCore.Services; 7 | using System.Linq; 8 | using System.Text; 9 | using Discord.Net; 10 | using Discord.WebSocket; 11 | using System.Text.RegularExpressions; 12 | using Microsoft.Extensions.Configuration; 13 | using Microsoft.Extensions.Logging; 14 | using Microsoft.Extensions.DependencyInjection; 15 | using NinjaBotCore.Common; 16 | using System.Threading; 17 | using NinjaBotCore.Modules.Wow; 18 | using NinjaBotCore.Models.Wow; 19 | using NinjaBotCore.Database; 20 | using System.Collections.Generic; 21 | 22 | namespace NinjaBotCore.Modules.Interactions.Wow 23 | { 24 | public class WowVanillaInteract : InteractionModuleBase 25 | { 26 | private readonly ILogger _logger; 27 | private readonly List _wclRegions = new List{"US", "EU", "KR", "TW", "CN"}; 28 | private readonly ChannelCheck _cc; 29 | private WarcraftLogs _wclLogsApi; 30 | 31 | public WowVanillaInteract(IServiceProvider services) 32 | { 33 | _logger = services.GetRequiredService>(); 34 | _cc = services.GetRequiredService(); 35 | _wclLogsApi = services.GetRequiredService(); 36 | } 37 | 38 | [SlashCommand("getvanillaguild", "get vanilla guild info")] 39 | public async Task GetvanillaGuild() 40 | { 41 | var sb = new StringBuilder(); 42 | var embed = new EmbedBuilder(); 43 | WowVanillaGuild wowvanillaGuild = null; 44 | 45 | embed.Title = $"[{Context.Guild.Name}] WoW Vanilla Guild Association"; 46 | embed.ThumbnailUrl = Context.Guild.IconUrl; 47 | using (var db = new NinjaBotEntities()) 48 | { 49 | wowvanillaGuild = db.WowVanillaGuild.Where(g => g.ServerId == (long)Context.Guild.Id).FirstOrDefault(); 50 | } 51 | if (wowvanillaGuild != null) 52 | { 53 | sb.AppendLine($"**Guild Name:** {wowvanillaGuild.WowGuild}"); 54 | sb.AppendLine($"**Realm:** {wowvanillaGuild.WowRealm}"); 55 | sb.AppendLine($"**Region:** {wowvanillaGuild.WowRegion}"); 56 | } 57 | else 58 | { 59 | sb.AppendLine($"There is no guild associated to this server!"); 60 | } 61 | embed.WithColor(0, 255, 155); 62 | embed.Description = sb.ToString(); 63 | await RespondAsync(embed: embed.Build(), ephemeral: true); 64 | } 65 | 66 | [SlashCommand("setvanillaguild", "set vanilla guild")] 67 | [RequireUserPermission(GuildPermission.KickMembers)] 68 | public async Task SetvanillaGuild(string guildName, string realm, string region = "US") 69 | { 70 | var embed = new EmbedBuilder(); 71 | var wowvanillaGuild = new WowVanillaGuild(); 72 | var sb = new StringBuilder(); 73 | 74 | embed.ThumbnailUrl = Context.Guild.IconUrl; 75 | 76 | if (!_wclRegions.Contains(region.ToUpper())) 77 | { 78 | embed.Title = "Error setting guild!"; 79 | embed.WithColor(255, 0 , 0); 80 | sb.AppendLine("Please specify a valid region."); 81 | sb.AppendLine(); 82 | sb.AppendLine("**Possible regions:**"); 83 | foreach (var reg in _wclRegions) 84 | { 85 | sb.AppendLine(reg); 86 | } 87 | embed.Description = sb.ToString(); 88 | await RespondAsync(embed: embed.Build(), ephemeral: true); 89 | return; 90 | } 91 | 92 | wowvanillaGuild.ServerId = (long)Context.Guild.Id; 93 | wowvanillaGuild.SetById = (long)Context.User.Id; 94 | wowvanillaGuild.WowGuild = guildName; 95 | wowvanillaGuild.WowRealm = realm; 96 | wowvanillaGuild.WowRegion = region; 97 | wowvanillaGuild.SetBy = Context.User.Username; 98 | wowvanillaGuild.TimeSet = DateTime.Now; 99 | wowvanillaGuild.ServerName = Context.Guild.Name; 100 | 101 | try 102 | { 103 | using (var db = new NinjaBotEntities()) 104 | { 105 | var currentGuild = db.WowVanillaGuild.Where(g => g.ServerId == (long)Context.Guild.Id).FirstOrDefault(); 106 | if (currentGuild != null) 107 | { 108 | db.Remove(currentGuild); 109 | } 110 | db.WowVanillaGuild.Add(wowvanillaGuild); 111 | await db.SaveChangesAsync(); 112 | } 113 | embed.Title = $"[{Context.Guild.Name}] WoW Vanilla Guild Association"; 114 | sb.AppendLine($"**Guild Name:** {wowvanillaGuild.WowGuild}"); 115 | sb.AppendLine($"**Realm:** {wowvanillaGuild.WowRealm}"); 116 | sb.AppendLine($"**Region:** {wowvanillaGuild.WowRegion}"); 117 | embed.Description = sb.ToString(); 118 | embed.WithFooter(new EmbedFooterBuilder 119 | { 120 | Text = $"Change made by [{Context.User.Username}]", 121 | IconUrl = Context.User.GetAvatarUrl() 122 | }); 123 | embed.WithColor(0, 255, 155); 124 | await RespondAsync(embed: embed.Build(), ephemeral: true); 125 | } 126 | catch (Exception ex) 127 | { 128 | _logger.LogError($"Error setting vanilla guild for {Context.Guild.Name} -> [{ex.Message}]"); 129 | } 130 | 131 | } 132 | 133 | [SlashCommand("logsvanilla", "get vanilla logs")] 134 | public async Task GetLogsvanilla() 135 | { 136 | var embed = new EmbedBuilder(); 137 | var sb = new StringBuilder(); 138 | int maxReturn = 2; 139 | WowVanillaGuild wowvanillaGuild = null; 140 | using (var db = new NinjaBotEntities()) 141 | { 142 | wowvanillaGuild = db.WowVanillaGuild.Where(g => g.ServerId == (long)Context.Guild.Id).FirstOrDefault(); 143 | } 144 | if (wowvanillaGuild != null) 145 | { 146 | var guildLogs = await _wclLogsApi.GetReportsFromGuildVanilla(wowvanillaGuild.WowGuild, wowvanillaGuild.WowRealm, wowvanillaGuild.WowRegion); 147 | if (guildLogs.Count > 0) 148 | { 149 | sb.AppendLine(); 150 | for (int i = 0; i <= (guildLogs.Count) && i <= maxReturn ; i++) 151 | { 152 | sb.AppendLine($"[__**{guildLogs[i].title}** **/** **{guildLogs[i].zoneName}**__]({guildLogs[i].reportURL})"); 153 | sb.AppendLine($"\t:timer: Start time: **{_wclLogsApi.UnixTimeStampToDateTime(guildLogs[i].start).ToLocalTime()}**"); 154 | sb.AppendLine($"\t:stopwatch: End time: **{_wclLogsApi.UnixTimeStampToDateTime(guildLogs[i].end).ToLocalTime()}**"); 155 | sb.AppendLine($"\t:pencil2: Created by [**{guildLogs[i].owner}**]"); 156 | sb.AppendLine(); 157 | } 158 | _logger.LogInformation($"Sending logs to {Context.Channel.Name}, requested by {Context.User.Username}"); 159 | embed.Title = $":1234: __Logs for **{wowvanillaGuild.WowGuild}** on **{wowvanillaGuild.WowRealm}**__:1234: "; 160 | embed.Description = sb.ToString(); 161 | embed.WithColor(0, 255, 100); 162 | await RespondAsync(embed: embed.Build(), ephemeral: true); 163 | } 164 | } 165 | } 166 | 167 | [SlashCommand("listvanillafights", "list vanilla fights")] 168 | [Discord.Interactions.RequireOwner] 169 | public async Task GetvanillaZones(string args = null) 170 | { 171 | var zones = await _wclLogsApi.GetVanillaZones(); 172 | Zones latest = null; 173 | if (args == null) 174 | { 175 | latest = zones[zones.Count - 2]; 176 | } 177 | else 178 | { 179 | if (args.ToLower() == "bwl") 180 | { 181 | args = "Blackwing Lair"; 182 | } 183 | if (args.ToLower() == "mc") 184 | { 185 | args = "Molten Core"; 186 | } 187 | latest = zones.Where(z => z.name.ToLower() == args.ToLower()).FirstOrDefault(); 188 | } 189 | var sb = new StringBuilder(); 190 | if (latest != null) 191 | { 192 | sb.AppendLine($"fights for [{latest.name}]"); 193 | foreach (var fight in latest.encounters) 194 | { 195 | sb.AppendLine($"id [{fight.id}] name [{fight.name}]"); 196 | } 197 | } 198 | await RespondAsync(sb.ToString()); 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/Modules/Interactions/YouTube/YouTubeCommands.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Discord.Interactions; 7 | using Discord; 8 | using Discord.Net; 9 | using Discord.WebSocket; 10 | using NinjaBotCore.Models.YouTube; 11 | using Google.Apis.YouTube; 12 | using Google.Apis.YouTube.v3; 13 | using Google.Apis.YouTube.v3.Data; 14 | using NinjaBotCore.Services; 15 | using NinjaBotCore.Modules.YouTube; 16 | 17 | namespace NinjaBotCore.Modules.Interactions.YouTube 18 | { 19 | public class YouTubeCommands : InteractionModuleBase 20 | { 21 | private static ChannelCheck _cc = null; 22 | private static YouTubeApi _youTubeApi = null; 23 | 24 | public YouTubeCommands(ChannelCheck cc, YouTubeApi youTubeApi) 25 | { 26 | if (_cc == null) 27 | { 28 | _cc = cc; 29 | } 30 | if (_youTubeApi == null) 31 | { 32 | _youTubeApi = youTubeApi; 33 | } 34 | } 35 | //Command that links just one video normally so it has play button 36 | [SlashCommand("ysearch", "search youtube")] 37 | public async Task SearchYouTube(string args = "") 38 | { 39 | string searchFor = string.Empty; 40 | var embed = new EmbedBuilder(); 41 | var embedThumb = Context.User.GetAvatarUrl(); 42 | StringBuilder sb = new StringBuilder(); 43 | List results = null; 44 | 45 | embed.ThumbnailUrl = embedThumb; 46 | 47 | if (string.IsNullOrEmpty(args)) 48 | { 49 | 50 | embed.Title = $"No search term provided!"; 51 | embed.WithColor(new Discord.Color(255, 0, 0)); 52 | sb.AppendLine("Please provide a term to search for!"); 53 | embed.Description = sb.ToString(); 54 | await RespondAsync(embed: embed.Build()); 55 | return; 56 | } 57 | else 58 | { 59 | searchFor = args; 60 | embed.WithColor(new Color(0, 255, 0)); 61 | results = await _youTubeApi.SearchChannelsAsync(searchFor); 62 | } 63 | 64 | if (results != null) 65 | { 66 | string videoUrlPrefix = $"https://www.youtube.com/watch?v="; 67 | embed.Title = $"YouTube Search For (**{searchFor}**)"; 68 | var thumbFromVideo = results.Where(r => r.Id.Kind == "youtube#video").Take(1).FirstOrDefault(); 69 | if (thumbFromVideo != null) 70 | { 71 | embed.ThumbnailUrl = thumbFromVideo.Snippet.Thumbnails.Default__.Url; 72 | } 73 | foreach (var result in results.Where(r => r.Id.Kind == "youtube#video").Take(3)) 74 | { 75 | string fullVideoUrl = string.Empty; 76 | string videoId = string.Empty; 77 | string description = string.Empty; 78 | if (string.IsNullOrEmpty(result.Snippet.Description)) 79 | { 80 | description = "No description available."; 81 | } 82 | else 83 | { 84 | description = result.Snippet.Description; 85 | } 86 | if (result.Id.VideoId != null) 87 | { 88 | fullVideoUrl = $"{videoUrlPrefix}{result.Id.VideoId.ToString()}"; 89 | } 90 | sb.AppendLine($":video_camera: **__{result.Snippet.ChannelTitle}__** -> [**{result.Snippet.Title}**]({fullVideoUrl})\n\n *{description}*\n"); 91 | } 92 | embed.Description = sb.ToString(); 93 | await RespondAsync(embed: embed.Build()); 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Modules/Steam/SteamApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Newtonsoft.Json; 7 | using System.Net; 8 | using NinjaBotCore.Models.Steam; 9 | using System.Net.Http; 10 | using System.Net.Http.Headers; 11 | using Microsoft.Extensions.Configuration; 12 | 13 | namespace NinjaBotCore.Modules.Steam 14 | { 15 | public class SteamApi 16 | { 17 | private readonly IConfigurationRoot _config; 18 | private string _key; 19 | 20 | public SteamApi(IConfigurationRoot config) 21 | { 22 | _config = config; 23 | _key = $"?key={_config["SteamApi"]}"; 24 | } 25 | 26 | private string getAPIRequest(string url) 27 | { 28 | string response; 29 | string prefix; 30 | prefix = "http://api.steampowered.com/ISteamUser/"; 31 | url = $"{prefix}{url}&format=json"; 32 | 33 | using (HttpClient httpClient = new HttpClient()) 34 | { 35 | httpClient.DefaultRequestHeaders 36 | .Accept 37 | .Add(new MediaTypeWithQualityHeaderValue("application/json")); 38 | //test = httpClient.PostAsJsonAsync(fullUrl, request).Result; 39 | response = httpClient.GetStringAsync(url).Result; 40 | } 41 | 42 | return response; 43 | } 44 | 45 | public SteamModel.Player GetProfileInfoBySteamID(long steamId) 46 | { 47 | SteamModel.UserInfo u; 48 | SteamModel.Player p; 49 | string url = string.Empty; 50 | url = $"GetPlayerSummaries/v0002/{_key}&steamids={steamId}"; 51 | u = JsonConvert.DeserializeObject(getAPIRequest(url)); 52 | p = u.response.players[0]; 53 | 54 | return p; 55 | } 56 | 57 | public SteamModel.VanitySteam GetSteamIDbyVanityURL(string vanityName) 58 | { 59 | SteamModel.VanityResponse p = new SteamModel.VanityResponse(); 60 | SteamModel.VanitySteam vs = new SteamModel.VanitySteam(); 61 | string url = string.Empty; 62 | url = $"ResolveVanityURL/v0001/{_key}&vanityurl={vanityName}"; 63 | p = JsonConvert.DeserializeObject(getAPIRequest(url)); 64 | vs = p.response; 65 | 66 | return vs; 67 | } 68 | 69 | public SteamModel.Player GetSteamPlayerInfo(string lookupPlayer) 70 | { 71 | SteamModel.Player p = new SteamModel.Player(); 72 | try 73 | { 74 | long steamID = 0; 75 | if (lookupPlayer.Length == 17) 76 | { 77 | long.TryParse(lookupPlayer, out steamID); 78 | Console.WriteLine($"{steamID}"); 79 | if (steamID != 0) 80 | { 81 | try 82 | { 83 | GetProfileInfoBySteamID(steamID); 84 | } 85 | catch (Exception ex) 86 | { 87 | Console.WriteLine($"{ex.Message}"); 88 | } 89 | } 90 | } 91 | else 92 | { 93 | SteamModel.VanitySteam v; 94 | v = GetSteamIDbyVanityURL(lookupPlayer); 95 | if (v.success == 1) 96 | { 97 | p = GetProfileInfoBySteamID(long.Parse(v.steamid)); 98 | Console.WriteLine(p.steamid); 99 | } 100 | else 101 | { 102 | 103 | } 104 | } 105 | 106 | } 107 | catch (Exception ex) 108 | { 109 | Console.WriteLine($"{ex.Message}"); 110 | } 111 | return p; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Modules/Wow/ApiRequestorThrottle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net.Http; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Microsoft.Extensions.Logging; 8 | using NinjaBotCore.Common; 9 | 10 | namespace NinjaBotCore.Modules.Wow 11 | { 12 | internal class ApiRequestorThrottle : WclApiRequestor, IApiRequestorThrottle 13 | { 14 | private readonly Semaphore _queue; 15 | private int _rateLimitRemaining; 16 | private DateTime _rateLimitResetRemaining; 17 | private IServiceProvider _services; 18 | 19 | public ApiRequestorThrottle(string apiKey, string baseUrl, HttpClient client) : base(apiKey, baseUrl, client) 20 | { 21 | _queue = new Semaphore(1, 1); 22 | _rateLimitRemaining = 1; 23 | _rateLimitResetRemaining = DateTime.UtcNow.AddSeconds(1); 24 | } 25 | 26 | protected override async Task SendAsync(HttpRequestMessage request) 27 | { 28 | try 29 | { 30 | _queue.WaitOne(); 31 | 32 | if (_rateLimitRemaining == 0) 33 | { 34 | var startTime = DateTime.UtcNow; 35 | //var difference = _rateLimitResetRemaining - startTime; 36 | //System.Console.WriteLine($"dif: {difference}"); 37 | 38 | await Task.Delay(1000); 39 | 40 | _rateLimitRemaining = 1; 41 | _rateLimitResetRemaining.AddSeconds(1); 42 | } 43 | 44 | var response = await base.SendAsync(request); 45 | _rateLimitRemaining -= 1; 46 | _rateLimitResetRemaining = _rateLimitResetRemaining.AddSeconds(-1); 47 | //System.Console.WriteLine(_rateLimitRemaining); 48 | return response; 49 | } 50 | finally 51 | { 52 | _queue.Release(); 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Modules/Wow/RaiderIOApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Net; 7 | using Newtonsoft.Json; 8 | using System.Text.RegularExpressions; 9 | using HtmlAgilityPack; 10 | using NinjaBotCore.Models.Wow; 11 | using System.IO; 12 | using NinjaBotCore.Database; 13 | using System.Net.Http; 14 | using System.Net.Http.Headers; 15 | using Microsoft.Extensions.Configuration; 16 | using Microsoft.Extensions.Logging; 17 | using Microsoft.Extensions.DependencyInjection; 18 | 19 | namespace NinjaBotCore.Modules.Wow 20 | { 21 | public class RaiderIOApi 22 | { 23 | 24 | private readonly IConfigurationRoot _config; 25 | private readonly ILogger _logger; 26 | 27 | public RaiderIOApi(IServiceProvider services) 28 | { 29 | try 30 | { 31 | _logger = services.GetRequiredService>(); 32 | _config = services.GetRequiredService(); 33 | 34 | } 35 | catch (Exception ex) 36 | { 37 | _logger.LogError($"Error creating RaiderIO class -> [{ex.Message}]"); 38 | } 39 | } 40 | 41 | 42 | public string GetApiRequest(string url, string region = "us", string locale = "en") 43 | { 44 | string response; 45 | string prefix; 46 | 47 | prefix = $"https://raider.io/api/v1"; 48 | url = $"{prefix}{url}?region={region}&locale={locale}"; 49 | 50 | _logger.LogInformation($"RaiderIO API request to {url}"); 51 | 52 | using (HttpClient httpClient = new HttpClient()) 53 | { 54 | httpClient.DefaultRequestHeaders 55 | .Accept 56 | .Add(new MediaTypeWithQualityHeaderValue("application/json")); 57 | //test = httpClient.PostAsJsonAsync(fullUrl, request).Result; 58 | response = httpClient.GetStringAsync(url).Result; 59 | } 60 | 61 | return response; 62 | } 63 | 64 | public string GetApiRequest(string url, string region = "us") 65 | { 66 | string response; 67 | string prefix; 68 | 69 | prefix = $"https://raider.io/api/v1"; 70 | url = $"{prefix}{url}?region={region}"; 71 | 72 | _logger.LogInformation($"RaiderIO API request to {url}"); 73 | 74 | using (HttpClient httpClient = new HttpClient()) 75 | { 76 | httpClient.DefaultRequestHeaders 77 | .Accept 78 | .Add(new MediaTypeWithQualityHeaderValue("application/json")); 79 | //test = httpClient.PostAsJsonAsync(fullUrl, request).Result; 80 | response = httpClient.GetStringAsync(url).Result; 81 | } 82 | 83 | return response; 84 | } 85 | 86 | public string GetApiRequest(string url) 87 | { 88 | string response; 89 | string prefix; 90 | 91 | prefix = $"https://raider.io/api/v1"; 92 | url = $"{prefix}{url}"; 93 | 94 | _logger.LogInformation($"RaiderIO API request to {url}"); 95 | 96 | using (HttpClient httpClient = new HttpClient()) 97 | { 98 | httpClient.DefaultRequestHeaders 99 | .Accept 100 | .Add(new MediaTypeWithQualityHeaderValue("application/json")); 101 | //test = httpClient.PostAsJsonAsync(fullUrl, request).Result; 102 | response = httpClient.GetStringAsync(url).Result; 103 | } 104 | 105 | return response; 106 | } 107 | 108 | public RaiderIOModels.Affix GetCurrentAffix(string region = "us", string locale = "en") 109 | { 110 | RaiderIOModels.Affix affixes = null; 111 | string url = $"/mythic-plus/affixes"; 112 | affixes = JsonConvert.DeserializeObject(GetApiRequest(url: url, region: region, locale: locale)); 113 | return affixes; 114 | } 115 | 116 | public RaiderIOModels.RioGuildInfo GetRioGuildInfo(string guildName, string realmName, string region) 117 | { 118 | RaiderIOModels.RioGuildInfo guildInfo = null; 119 | guildName = guildName.Replace(" ", "%20"); 120 | realmName = realmName.Replace(" ", "%20"); 121 | string url = $"/guilds/profile?region={region}&realm={realmName}&name={guildName}&fields=raid_progression%2Craid_rankings"; 122 | guildInfo = JsonConvert.DeserializeObject(GetApiRequest(url: url)); 123 | return guildInfo; 124 | } 125 | 126 | public RaiderIOModels.RioMythicPlusChar GetCharMythicPlusInfo(string charName, string realmName, string region = "us") 127 | { 128 | RaiderIOModels.RioMythicPlusChar mythicCharInfo = null; 129 | string url = $"/characters/profile?region={region}&realm={realmName}&name={charName}&fields=mythic_plus_scores_by_season:current%2Cmythic_plus_ranks%2Cmythic_plus_scores%2Cmythic_plus_highest_level_runs%2Cmythic_plus_recent_runs%2Cmythic_plus_best_runs%2Craid_progression"; 130 | mythicCharInfo = JsonConvert.DeserializeObject(GetApiRequest(url: url)); 131 | return mythicCharInfo; 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /src/Modules/Wow/WclApiRequestor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Net; 7 | using Newtonsoft.Json; 8 | using NinjaBotCore.Models.Wow; 9 | using System.Net.Http; 10 | using System.Net.Http.Headers; 11 | using System.Threading; 12 | using NinjaBotCore.Database; 13 | using Discord; 14 | using Discord.Net; 15 | using Discord.WebSocket; 16 | using Microsoft.Extensions.Configuration; 17 | using NinjaBotCore.Common; 18 | 19 | namespace NinjaBotCore.Modules.Wow 20 | { 21 | public class WclApiRequestor : IWclApiRequestor, IDisposable 22 | { 23 | private readonly HttpClient _client; 24 | private readonly string _apiKey; 25 | private string apiKey; 26 | private string _baseUrl; 27 | 28 | public WclApiRequestor(string apiKey, string baseUrl, HttpClient client) 29 | { 30 | _baseUrl = baseUrl; 31 | _client = client; 32 | _client.BaseAddress = new Uri(_baseUrl); 33 | _client.DefaultRequestHeaders 34 | .Accept 35 | .Add(new MediaTypeWithQualityHeaderValue("application/json")); 36 | _apiKey = apiKey; 37 | } 38 | 39 | public async Task Get(string relativeUrl) 40 | { 41 | using (var request = new HttpRequestMessage(HttpMethod.Get, $"{relativeUrl}api_key={_apiKey}")) 42 | using (var response = await SendAsync(request)) 43 | { 44 | var result = await response.Content.ReadAsStringAsync(); 45 | 46 | return JsonConvert.DeserializeObject(result); 47 | } 48 | } 49 | 50 | protected virtual async Task SendAsync(HttpRequestMessage request) 51 | { 52 | var response = await _client.SendAsync(request); 53 | if (response.IsSuccessStatusCode) 54 | { 55 | return response; 56 | } 57 | 58 | try 59 | { 60 | var errorMessage = await response.Content.ReadAsStringAsync(); 61 | 62 | if (string.IsNullOrEmpty(errorMessage)) 63 | { 64 | throw new Exception("No message!"); 65 | } 66 | else 67 | { 68 | throw new Exception($"{errorMessage}"); 69 | } 70 | 71 | } 72 | catch (JsonException e) 73 | { 74 | throw new Exception($"{e.Message}"); 75 | } 76 | } 77 | 78 | public void Dispose() 79 | { 80 | _client?.Dispose(); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/Modules/Wow/WowProgress.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using HtmlAgilityPack; 7 | using System.IO; 8 | using System.IO.Compression; 9 | using System.Net; 10 | using NinjaBotCore.Models.Wow; 11 | using Newtonsoft.Json; 12 | using System.Net.Http; 13 | using System.Net.Http.Headers; 14 | 15 | namespace NinjaBotCore.Modules.Wow 16 | { 17 | class WowProgress 18 | { 19 | public WowProgress() 20 | { 21 | string baseURL = "http://www.wowprogress.com/export/ranks/"; 22 | _links = this.GetLinks(baseURL); 23 | } 24 | 25 | public List _links; 26 | 27 | public string GetApiRequest(string url, string regionName = "us") 28 | { 29 | string fullUrl = $"http://www.wowprogress.com/guild/{regionName}/{url}/json_rank"; 30 | Console.WriteLine(fullUrl); 31 | string response = string.Empty; 32 | using (HttpClient httpClient = new HttpClient()) 33 | { 34 | httpClient.DefaultRequestHeaders 35 | .Accept 36 | .Add(new MediaTypeWithQualityHeaderValue("application/json")); 37 | response = httpClient.GetStringAsync(fullUrl).Result; 38 | } 39 | return response; 40 | } 41 | 42 | public ProgressGuildRanks.GuildRank GetGuildRank(string guildName, string realmName, string regionName = "us") 43 | { 44 | string url = $"{realmName.Replace("'", "-")}/{guildName.Replace(' ', '+')}"; 45 | Console.WriteLine($"{realmName}/{guildName.Replace(' ', '+')}"); 46 | ProgressGuildRanks.GuildRank rank = new ProgressGuildRanks.GuildRank(); 47 | rank = JsonConvert.DeserializeObject(GetApiRequest(url, regionName)); 48 | return rank; 49 | } 50 | 51 | public List GetRealmObject(string realmName, List links, string regionName = "us") 52 | { 53 | realmName = realmName.Replace("'", "-"); 54 | string downloadURL = FindRealmLink(links, realmName, regionName); 55 | Console.WriteLine($"l{links} r{realmName}"); 56 | DateTime remoteFileModified = GetLastModifyTime(downloadURL); 57 | DateTime localFileModified = new DateTime(); 58 | 59 | if (File.Exists($"{realmName}-{regionName}.json")) 60 | { 61 | localFileModified = File.GetLastWriteTime($"{realmName}-{regionName}.json"); 62 | } 63 | string bytesAsString = string.Empty; 64 | Console.WriteLine($"remote: {remoteFileModified} local: {localFileModified}"); 65 | if (remoteFileModified > localFileModified) 66 | { 67 | 68 | byte[] fileDL = GetRankingsFile(downloadURL); 69 | var decompressed = DecompressFile(fileDL); 70 | File.WriteAllBytes($"{realmName}-{regionName}.json", decompressed); 71 | File.SetLastWriteTime($"{realmName}-{regionName}.json", GetLastModifyTime(downloadURL)); 72 | bytesAsString = Encoding.ASCII.GetString(decompressed); 73 | } 74 | else 75 | { 76 | bytesAsString = Encoding.ASCII.GetString(File.ReadAllBytes($"{realmName}-{regionName}.json")); 77 | } 78 | var realmObject = JsonConvert.DeserializeObject>(bytesAsString); 79 | return realmObject; 80 | } 81 | 82 | private static string FindRealmLink(List links, string realmName, string regionName = "us") 83 | { 84 | string baseURL = "http://www.wowprogress.com/export/ranks/"; 85 | string url = string.Empty; 86 | string pattern = $"^{regionName}.+{realmName.ToLower()}.+\\.gz$"; 87 | List possibleLinks = new List(); 88 | foreach (HtmlNode link in links) 89 | { 90 | if (System.Text.RegularExpressions.Regex.IsMatch(link.InnerText, pattern)) 91 | { 92 | possibleLinks.Add(link); 93 | } 94 | } 95 | url = $"{baseURL}{possibleLinks.Select(l => l.InnerHtml).LastOrDefault()}"; 96 | return url; 97 | } 98 | 99 | public byte[] GetRankingsFile(string url) 100 | { 101 | byte[] fileDL; 102 | using (HttpClient httpClient = new HttpClient()) 103 | { 104 | httpClient.DefaultRequestHeaders 105 | .Accept 106 | .Add(new MediaTypeWithQualityHeaderValue("application/json")); 107 | 108 | fileDL = httpClient.GetByteArrayAsync(url).Result; 109 | } 110 | return fileDL; 111 | } 112 | 113 | public DateTime GetLastModifyTime(string url) 114 | { 115 | System.Console.WriteLine("I'm here in last modified"); 116 | using (HttpClient httpClient = new HttpClient()) 117 | { 118 | HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Head, new Uri(url)); 119 | HttpResponseMessage response = httpClient.SendAsync(request).Result; 120 | string lastModifyString = response.Content.Headers.LastModified.ToString(); 121 | DateTime remoteTime; 122 | if (DateTime.TryParse(lastModifyString, out remoteTime)) 123 | { 124 | return remoteTime; 125 | } 126 | return DateTime.MinValue; 127 | } 128 | } 129 | 130 | public byte[] DecompressFile(byte[] gzip) 131 | { 132 | // Create a GZIP stream with decompression mode. 133 | // ... Then create a buffer and write into while reading from the GZIP stream. 134 | using (GZipStream stream = new GZipStream(new MemoryStream(gzip), 135 | CompressionMode.Decompress)) 136 | { 137 | const int size = 4096; 138 | byte[] buffer = new byte[size]; 139 | using (MemoryStream memory = new MemoryStream()) 140 | { 141 | int count = 0; 142 | do 143 | { 144 | count = stream.Read(buffer, 0, size); 145 | if (count > 0) 146 | { 147 | memory.Write(buffer, 0, count); 148 | } 149 | } 150 | while (count > 0); 151 | return memory.ToArray(); 152 | } 153 | } 154 | } 155 | 156 | public List GetLinks(string url) 157 | { 158 | string url_string = string.Empty; 159 | HtmlDocument doc = new HtmlDocument(); 160 | using (var httpclient = new HttpClient()) 161 | { 162 | url_string = httpclient.GetStringAsync(url).Result; 163 | } 164 | doc.LoadHtml(url_string); 165 | List links = new List(); 166 | string sPattern = "^(us|eu).+\\.gz$"; 167 | foreach (HtmlNode link in doc.DocumentNode.SelectNodes("//a[@href]")) 168 | { 169 | if (System.Text.RegularExpressions.Regex.IsMatch(link.InnerText, sPattern)) 170 | { 171 | links.Add(link); 172 | } 173 | } 174 | return links; 175 | } 176 | } 177 | } -------------------------------------------------------------------------------- /src/Modules/YouTube/YouTubeApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Net; 7 | using Newtonsoft.Json; 8 | using NinjaBotCore.Models.YouTube; 9 | using Google; 10 | using Google.Apis; 11 | using Google.Apis.YouTube.v3; 12 | using System.Net.Http; 13 | using System.Net.Http.Headers; 14 | using Google.Apis.YouTube.v3.Data; 15 | using Google.Apis.Services; 16 | using Microsoft.Extensions.Configuration; 17 | 18 | namespace NinjaBotCore.Modules.YouTube 19 | { 20 | public class YouTubeApi 21 | { 22 | private string _key; 23 | private readonly IConfigurationRoot _config; 24 | 25 | public YouTubeApi(IConfigurationRoot config) 26 | { 27 | _config = config; 28 | _key = _config["YouTubeApi"]; 29 | } 30 | private string getYouTubeApiRequest(string url) 31 | { 32 | string reponse = string.Empty; 33 | 34 | string fullUrl = $"https://www.googleapis.com/youtube/v3/search?key={_key}{url}"; 35 | Console.WriteLine($"YouTube API Request {fullUrl}"); 36 | 37 | string response = string.Empty; 38 | 39 | using (HttpClient httpClient = new HttpClient()) 40 | { 41 | httpClient.DefaultRequestHeaders 42 | .Accept 43 | .Add(new MediaTypeWithQualityHeaderValue("application/json")); 44 | //test = httpClient.PostAsJsonAsync(fullUrl, request).Result; 45 | response = httpClient.GetStringAsync(url).Result; 46 | } 47 | 48 | return response; 49 | } 50 | 51 | public string getLatestVideoByID(string id, int numVideos = 1) 52 | { 53 | string videoURL = string.Empty; 54 | string url = $"&channelId={id}&part=snippet,id&order=date&maxResults={numVideos}"; 55 | YouTubeModel.Video videos = JsonConvert.DeserializeObject(getYouTubeApiRequest(url)); 56 | videoURL = $"https://www.youtube.com/watch?v={videos.items[0].id.videoId}"; 57 | return videoURL; 58 | } 59 | 60 | public string getRandomVideoByID(string id, int numVideos = 50) 61 | { 62 | string videoURL = string.Empty; 63 | string url = $"&channelId={id}&part=snippet,id&order=date&maxResults={numVideos}"; 64 | YouTubeModel.Video videos = JsonConvert.DeserializeObject(getYouTubeApiRequest(url)); 65 | Random getRandom = new Random(); 66 | int random = getRandom.Next(0, numVideos); 67 | videoURL = $"https://www.youtube.com/watch?v={videos.items[random].id.videoId}"; 68 | return videoURL; 69 | } 70 | 71 | public async Task> SearchChannelsAsync(string keyword = "space", int maxResults = 5) 72 | { 73 | var youtubeService = new YouTubeService(new BaseClientService.Initializer() 74 | { 75 | ApiKey = _key, 76 | ApplicationName = this.GetType().ToString() 77 | }); 78 | var searchListRequest = youtubeService.Search.List("snippet"); 79 | searchListRequest.Q = keyword; 80 | searchListRequest.MaxResults = maxResults; 81 | var searchListResponse = await searchListRequest.ExecuteAsync(); 82 | return searchListResponse.Items.ToList(); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/NinjaBot.cs: -------------------------------------------------------------------------------- 1 | using Discord; 2 | using Discord.Commands; 3 | using Discord.Interactions; 4 | using Discord.WebSocket; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using System; 8 | using NinjaBotCore.Modules.Wow; 9 | using NinjaBotCore.Modules.Admin; 10 | using NinjaBotCore.Modules.Steam; 11 | using NinjaBotCore.Modules.Interactions.Away; 12 | using Microsoft.Extensions.Configuration; 13 | using NinjaBotCore.Services; 14 | using NinjaBotCore.Modules.YouTube; 15 | using Serilog; 16 | using Microsoft.Extensions.DependencyInjection.Extensions; 17 | using Microsoft.Extensions.Http; 18 | using ArgentPonyWarcraftClient; 19 | using ArgentPonyWarcraftClient.Extensions.DependencyInjection; 20 | 21 | namespace NinjaBotCore 22 | { 23 | public class NinjaBot 24 | { 25 | private IConfigurationRoot _config; 26 | 27 | public async Task StartAsync() 28 | { 29 | //Create the configuration 30 | var _builder = new ConfigurationBuilder() 31 | .SetBasePath(AppContext.BaseDirectory) 32 | .AddJsonFile(path: "config.json"); 33 | _config = _builder.Build(); 34 | 35 | //Configure services 36 | var services = new ServiceCollection() 37 | .AddSingleton(new DiscordShardedClient(new DiscordSocketConfig 38 | { 39 | GatewayIntents = GatewayIntents.AllUnprivileged | 40 | GatewayIntents.GuildMembers, 41 | LogLevel = LogSeverity.Error, 42 | MessageCacheSize = 1000, 43 | AlwaysDownloadUsers = true 44 | })) 45 | .AddSingleton(_config) 46 | .AddSingleton(new CommandService(new CommandServiceConfig 47 | { 48 | DefaultRunMode = Discord.Commands.RunMode.Async, 49 | LogLevel = LogSeverity.Verbose, 50 | CaseSensitiveCommands = false, 51 | ThrowOnError = false 52 | })) 53 | .AddHttpClient() 54 | .AddSingleton() 55 | .AddSingleton() 56 | .AddSingleton() 57 | .AddSingleton() 58 | .AddSingleton() 59 | .AddSingleton() 60 | .AddSingleton() 61 | .AddSingleton(x => new InteractionService(x.GetRequiredService())) 62 | .AddSingleton() 63 | .AddSingleton() 64 | .AddSingleton() 65 | .AddSingleton() 66 | .AddSingleton() 67 | .AddSingleton() 68 | .AddWarcraftClients(_config["WoWClient"], _config["WoWSecret"]) 69 | .AddSingleton(); 70 | 71 | //Add logging 72 | ConfigureServices(services); 73 | 74 | //Build services 75 | var serviceProvider = services.BuildServiceProvider(); 76 | 77 | //Instantiate logger/tie-in logging 78 | serviceProvider.GetRequiredService(); 79 | 80 | // interaction testing 81 | await serviceProvider.GetRequiredService() 82 | .InitializeAsync(); 83 | 84 | //Start the bot 85 | await serviceProvider.GetRequiredService().StartAsync(); 86 | 87 | //Load up services 88 | serviceProvider.GetRequiredService(); 89 | serviceProvider.GetRequiredService(); 90 | 91 | //Block this program until it is closed. 92 | await Task.Delay(-1); 93 | } 94 | 95 | private static void ConfigureServices(IServiceCollection services) 96 | { 97 | //Add SeriLog 98 | services.AddLogging(configure => configure.AddSerilog()); 99 | //Remove default HttpClient logging as it is extremely verbose 100 | services.RemoveAll(); 101 | //Configure logging level 102 | var logLevel = "info"; 103 | //var logLevel = Environment.GetEnvironmentVariable("NJA_LOG_LEVEL"); 104 | var level = Serilog.Events.LogEventLevel.Error; 105 | if (!string.IsNullOrEmpty(logLevel)) 106 | { 107 | switch (logLevel.ToLower()) 108 | { 109 | case "error": 110 | { 111 | level = Serilog.Events.LogEventLevel.Error; 112 | break; 113 | } 114 | case "info": 115 | { 116 | level = Serilog.Events.LogEventLevel.Information; 117 | break; 118 | } 119 | case "debug": 120 | { 121 | level = Serilog.Events.LogEventLevel.Debug; 122 | break; 123 | } 124 | case "crit": 125 | { 126 | level = Serilog.Events.LogEventLevel.Fatal; 127 | break; 128 | } 129 | case "warn": 130 | { 131 | level = Serilog.Events.LogEventLevel.Warning; 132 | break; 133 | } 134 | case "trace": 135 | { 136 | level = Serilog.Events.LogEventLevel.Debug; 137 | break; 138 | } 139 | } 140 | } 141 | Log.Logger = new LoggerConfiguration() 142 | .WriteTo.File("logs/njabot.log", rollingInterval: RollingInterval.Day) 143 | .WriteTo.Console() 144 | .MinimumLevel.Is(level) 145 | .CreateLogger(); 146 | } 147 | public static bool IsDebug() 148 | { 149 | #if DEBUG 150 | return true; 151 | #else 152 | return false; 153 | #endif 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /src/NinjaBotCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Discord.Net; 3 | using Discord; 4 | using Discord.Commands; 5 | using System.Threading.Tasks; 6 | using NinjaBotCore.Database; 7 | using Microsoft.Data.Sqlite; 8 | using Microsoft.EntityFrameworkCore; 9 | using System.Linq; 10 | using Serilog; 11 | using Microsoft.Extensions.Logging; 12 | using Microsoft.Extensions.Hosting; 13 | 14 | namespace NinjaBotCore 15 | { 16 | class Program 17 | { 18 | public static IHostBuilder CreateHostBuilder(string[] args) 19 | { 20 | return Host.CreateDefaultBuilder(); 21 | } 22 | 23 | public static void Main(string[] args) 24 | { 25 | try 26 | { 27 | new NinjaBot().StartAsync().GetAwaiter().GetResult(); 28 | } 29 | catch (Exception ex) 30 | { 31 | Console.WriteLine(ex.Message); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Services/AudioService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Threading.Tasks; 5 | using Discord; 6 | using Discord.Audio; 7 | 8 | namespace NinjaBotCore.Services 9 | { 10 | public class AudioService 11 | { 12 | private readonly ConcurrentDictionary ConnectedChannels = new ConcurrentDictionary(); 13 | 14 | public async Task JoinAudio(IGuild guild, IVoiceChannel target) 15 | { 16 | IAudioClient client; 17 | if (ConnectedChannels.TryGetValue(guild.Id, out client)) 18 | { 19 | return; 20 | } 21 | if (target.Guild.Id != guild.Id) 22 | { 23 | return; 24 | } 25 | 26 | var audioClient = await target.ConnectAsync(); 27 | 28 | if (ConnectedChannels.TryAdd(guild.Id, audioClient)) 29 | { 30 | // If you add a method to log happenings from this service, 31 | // you can uncomment these commented lines to make use of that. 32 | //await Log(LogSeverity.Info, $"Connected to voice on {guild.Name}."); 33 | } 34 | } 35 | 36 | public async Task LeaveAudio(IGuild guild) 37 | { 38 | IAudioClient client; 39 | if (ConnectedChannels.TryRemove(guild.Id, out client)) 40 | { 41 | await client.StopAsync(); 42 | //await Log(LogSeverity.Info, $"Disconnected from voice on {guild.Name}."); 43 | } 44 | } 45 | 46 | public async Task SendAudioAsync(IGuild guild, IMessageChannel channel, string path) 47 | { 48 | // Your task: Get a full path to the file if the value of 'path' is only a filename. 49 | if (!File.Exists(path)) 50 | { 51 | await channel.SendMessageAsync("File does not exist."); 52 | return; 53 | } 54 | IAudioClient client; 55 | if (ConnectedChannels.TryGetValue(guild.Id, out client)) 56 | { 57 | //await Log(LogSeverity.Debug, $"Starting playback of {path} in {guild.Name}"); 58 | using (var ffmpeg = CreateProcess(path)) 59 | using (var stream = client.CreatePCMStream(AudioApplication.Music)) 60 | { 61 | try { await ffmpeg.StandardOutput.BaseStream.CopyToAsync(stream); } 62 | finally { await stream.FlushAsync(); } 63 | } 64 | } 65 | } 66 | 67 | private Process CreateProcess(string path) 68 | { 69 | return Process.Start(new ProcessStartInfo 70 | { 71 | FileName = "ffmpeg", 72 | Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f s16le -ar 48000 pipe:1", 73 | UseShellExecute = false, 74 | RedirectStandardOutput = true 75 | }); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/Services/ChannelCheck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using NinjaBotCore.Database; 7 | using Discord; 8 | using Discord.Net; 9 | using Discord.Commands; 10 | using Discord.WebSocket; 11 | using System.Threading; 12 | 13 | namespace NinjaBotCore.Services 14 | { 15 | public class ChannelCheck 16 | { 17 | //if (Context.Channel is IDMChannel) 18 | //{ 19 | // await ReplyAsync("DM"); 20 | //} 21 | //else if (Context.Channel is IGuildChannel) 22 | //{ 23 | // await ReplyAsync("Channel"); 24 | //} 25 | public async Task SetGuildBotChannelAsync(ulong channelId, string channelName, ulong userId, string userName, string guildName, ulong guildId) 26 | { 27 | await Task.Run(async () => 28 | { 29 | using (var db = new NinjaBotEntities()) 30 | { 31 | var currentChannel = db.ChannelOutputs.FirstOrDefault(o => o.ServerId == (long)guildId); 32 | if (currentChannel == null) 33 | { 34 | var createChannel = new ChannelOutput 35 | { 36 | ChannelId = (long)channelId, 37 | ChannelName = channelName, 38 | ServerId = (long)guildId, 39 | ServerName = guildName, 40 | SetById = (long)userId, 41 | SetByName = userName, 42 | SetTime = DateTime.Now 43 | }; 44 | db.ChannelOutputs.Add(createChannel); 45 | } 46 | else 47 | { 48 | currentChannel.ChannelId = (long)channelId; 49 | currentChannel.ChannelName = channelName; 50 | currentChannel.ServerId = (long)guildId; 51 | currentChannel.ServerName = guildName; 52 | currentChannel.SetById = (long)userId; 53 | currentChannel.SetByName = userName; 54 | currentChannel.SetTime = DateTime.Now; 55 | } 56 | await db.SaveChangesAsync(); 57 | } 58 | }); 59 | } 60 | 61 | public ChannelOutput GetGuildBotChannel(ulong guildId) 62 | { 63 | ChannelOutput outputChannel = new ChannelOutput(); 64 | 65 | using (var db = new NinjaBotEntities()) 66 | { 67 | outputChannel = db.ChannelOutputs.FirstOrDefault(o => o.ServerId == (long)guildId); 68 | } 69 | if (outputChannel == null) 70 | { 71 | outputChannel = new ChannelOutput(); 72 | } 73 | 74 | return outputChannel; 75 | } 76 | 77 | public async Task Reply(ICommandContext context, EmbedBuilder embed) 78 | { 79 | await Task.Run(async() => 80 | { 81 | ChannelOutput replyChannel; 82 | var guildInfo = context.Guild; 83 | if (guildInfo == null) 84 | { 85 | replyChannel = new ChannelOutput(); 86 | } 87 | else 88 | { 89 | replyChannel = GetGuildBotChannel(context.Guild.Id); 90 | } 91 | if (!string.IsNullOrEmpty(replyChannel.ChannelName)) 92 | { 93 | var messageChannel = await context.Client.GetChannelAsync((ulong)replyChannel.ChannelId) as ISocketMessageChannel; 94 | await messageChannel.SendMessageAsync("", false, embed.Build()); 95 | } 96 | else 97 | { 98 | await context.Channel.SendMessageAsync("", false, embed.Build()); 99 | } 100 | }); 101 | } 102 | 103 | public async Task Reply(ICommandContext context, string message) 104 | { 105 | await Task.Run(async () => 106 | { 107 | ChannelOutput replyChannel; 108 | var guildInfo = context.Guild; 109 | if (guildInfo == null) 110 | { 111 | replyChannel = new ChannelOutput(); 112 | } 113 | else 114 | { 115 | replyChannel = GetGuildBotChannel(context.Guild.Id); 116 | } 117 | if (!string.IsNullOrEmpty(replyChannel.ChannelName)) 118 | { 119 | var messageChannel = await context.Client.GetChannelAsync((ulong)replyChannel.ChannelId) as ISocketMessageChannel; 120 | await messageChannel.SendMessageAsync(message); 121 | } 122 | else 123 | { 124 | await context.Channel.SendMessageAsync(message); 125 | } 126 | }); 127 | } 128 | 129 | public async Task SetLoadingEmoji(ICommandContext context) 130 | { 131 | //await context.Message.AddReactionAsync(EmojiExtensions.FromText(":cd:")); 132 | } 133 | 134 | public async Task SetDoneEmoji(ICommandContext context) 135 | { 136 | ChannelPermissions botPerms = await GetBotPerms(context); 137 | if (botPerms.ManageMessages) 138 | { 139 | await context.Message.RemoveAllReactionsAsync(); 140 | } 141 | //await context.Message.AddReactionAsync(EmojiExtensions.FromText(":white_check_mark:")); 142 | } 143 | 144 | private async Task GetBotPerms(ICommandContext context) 145 | { 146 | var botUser = await context.Guild.GetUserAsync(291289031822802944); 147 | var perms = botUser.GetPermissions(context.Channel as IGuildChannel); 148 | return perms; 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/Services/CommandHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using System.Reflection; 3 | using Discord.Net; 4 | using Discord.Commands; 5 | using Discord.WebSocket; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using System; 8 | using System.Linq; 9 | using System.Collections.Generic; 10 | using NinjaBotCore.Database; 11 | using Discord; 12 | using Microsoft.Extensions.Configuration; 13 | using Microsoft.Extensions.Logging; 14 | 15 | namespace NinjaBotCore.Services 16 | { 17 | public class CommandHandler 18 | { 19 | private CommandService _commands; 20 | private DiscordShardedClient _client; 21 | private readonly IConfigurationRoot _config; 22 | private readonly ILogger _logger; 23 | private readonly IServiceProvider _services; 24 | 25 | public CommandHandler(IServiceProvider services) 26 | { 27 | _services = services; 28 | _config = services.GetRequiredService(); 29 | _client = services.GetRequiredService(); 30 | _commands = services.GetRequiredService(); 31 | _client.MessageReceived += HandleCommand; 32 | _logger = services.GetRequiredService>(); 33 | } 34 | 35 | public async Task HandleCommand(SocketMessage parameterMessage) 36 | { 37 | // Don't handle the command if it is a system message 38 | var message = parameterMessage as SocketUserMessage; 39 | if (message == null) return; 40 | 41 | // Don't listen to bots 42 | if (message.Source != MessageSource.User) 43 | { 44 | return; 45 | } 46 | 47 | // Mark where the prefix ends and the command begins 48 | int argPos = 0; 49 | 50 | // Create a Command Context 51 | var context = new ShardedCommandContext(_client, message); 52 | 53 | char prefix = Char.Parse(_config["prefix"]); 54 | 55 | var serverPrefix = GetPrefix((long)context.Guild.Id); 56 | 57 | if (serverPrefix != null) 58 | { 59 | prefix = serverPrefix.Prefix; 60 | } 61 | 62 | // Determine if the message has a valid prefix, adjust argPos 63 | if (!(message.HasMentionPrefix(_client.CurrentUser, ref argPos) || message.HasCharPrefix(prefix, ref argPos))) return; 64 | 65 | //Check blacklist 66 | List blacklist = new List(); 67 | 68 | using (var db = new NinjaBotEntities()) 69 | { 70 | blacklist = db.Blacklist.ToList(); 71 | } 72 | if (blacklist != null) 73 | { 74 | var matched = blacklist.Where(b => b.DiscordUserId == (long)context.User.Id).FirstOrDefault(); 75 | if (matched != null) 76 | { 77 | return; 78 | } 79 | } 80 | 81 | // Execute the Command, store the result 82 | var result = await _commands.ExecuteAsync(context, argPos, _services); 83 | 84 | await LogCommandUsage(context, result); 85 | // If the command failed, notify the user 86 | if (!result.IsSuccess) 87 | { 88 | if (result.ErrorReason != "Unknown command.") 89 | { 90 | await message.Channel.SendMessageAsync($"**Error:** {result.ErrorReason}"); 91 | } 92 | } 93 | } 94 | 95 | private PrefixList GetPrefix(long serverId) 96 | { 97 | PrefixList prefix = null; 98 | 99 | using (var db = new NinjaBotEntities()) 100 | { 101 | prefix = db.PrefixList.Where(p => p.ServerId == serverId).FirstOrDefault(); 102 | } 103 | 104 | return prefix; 105 | } 106 | 107 | private async Task LogCommandUsage(SocketCommandContext context, IResult result) 108 | { 109 | await Task.Run(async () => 110 | { 111 | if (context.Channel is IGuildChannel) 112 | { 113 | var logTxt = $"User: [{context.User.Username}]<->[{context.User.Id}] Discord Server: [{context.Guild.Name}] -> [{context.Message.Content}]"; 114 | _logger.LogInformation(logTxt); 115 | } 116 | else 117 | { 118 | var logTxt = $"User: [{context.User.Username}]<->[{context.User.Id}] -> [{context.Message.Content}]"; 119 | _logger.LogInformation(logTxt); 120 | } 121 | }); 122 | 123 | /* 124 | string commandIssued = string.Empty; 125 | if (!result.IsSuccess) 126 | { 127 | request.Success = false; 128 | request.FailureReason = result.ErrorReason; 129 | } 130 | request.ChannelId = (long)context.Channel.Id; 131 | request.ChannelName = context.Channel.Name; 132 | request.UserId = (long)context.User.Id; 133 | request.Command = context.Message.Content; 134 | request.UserName = context.User.Username; 135 | request.Success = true; 136 | request.RequestTime = DateTime.Now; 137 | using (var db = new NinjaBotEntities()) 138 | { 139 | 140 | db.Requests.Add(request); 141 | await db.SaveChangesAsync(); 142 | } 143 | */ 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /src/Services/InteractionHandler.cs: -------------------------------------------------------------------------------- 1 | using Discord; 2 | using Discord.Interactions; 3 | using Discord.WebSocket; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Logging; 7 | using System; 8 | using System.Reflection; 9 | using System.Threading.Tasks; 10 | 11 | namespace NinjaBotCore.Services 12 | { 13 | public class InteractionHandler 14 | { 15 | private readonly DiscordShardedClient _client; 16 | private readonly InteractionService _handler; 17 | private readonly IServiceProvider _services; 18 | private readonly IConfigurationRoot _configuration; 19 | private readonly ILogger _logger; 20 | 21 | public InteractionHandler(DiscordShardedClient client, InteractionService handler, IServiceProvider services, IConfigurationRoot config) 22 | { 23 | _client = client; 24 | _handler = handler; 25 | _services = services; 26 | _configuration = config; 27 | _logger = services.GetRequiredService>(); 28 | } 29 | 30 | public async Task InitializeAsync() 31 | { 32 | // Process when the client is ready, so we can register our commands. 33 | _client.ShardReady += ReadyAsync; 34 | 35 | // Add the public modules that inherit InteractionModuleBase to the InteractionService 36 | await _handler.AddModulesAsync(Assembly.GetEntryAssembly(), _services); 37 | 38 | // Process the InteractionCreated payloads to execute Interactions commands 39 | _client.InteractionCreated += HandleInteraction; 40 | } 41 | 42 | private async Task ReadyAsync(DiscordSocketClient arg) 43 | { 44 | // Context & Slash commands can be automatically registered, but this process needs to happen after the client enters the READY state. 45 | // Since Global Commands take around 1 hour to register, we should use a test guild to instantly update and test our commands. 46 | if (NinjaBot.IsDebug()) 47 | { 48 | System.Console.WriteLine("debug"); 49 | await _handler.RegisterCommandsToGuildAsync(Convert.ToUInt64(_configuration["testGuild"]), true); 50 | } 51 | else 52 | { 53 | await _handler.RegisterCommandsGloballyAsync(true); 54 | } 55 | } 56 | 57 | private async Task HandleInteraction(SocketInteraction interaction) 58 | { 59 | try 60 | { 61 | // Create an execution context that matches the generic type parameter of your InteractionModuleBase modules. 62 | var context = new ShardedInteractionContext( 63 | _client, interaction); 64 | 65 | // Execute the incoming command. 66 | var result = await _handler.ExecuteCommandAsync(context, _services); 67 | 68 | if (!result.IsSuccess) 69 | switch (result.Error) 70 | { 71 | case InteractionCommandError.UnmetPrecondition: 72 | // implement 73 | break; 74 | default: 75 | break; 76 | } 77 | } 78 | catch 79 | { 80 | // If Slash Command execution fails it is most likely that the original interaction acknowledgement will persist. It is a good idea to delete the original 81 | // response, or at least let the user know that something went wrong during the command execution. 82 | if (interaction.Type is InteractionType.ApplicationCommand) 83 | { 84 | await interaction.GetOriginalResponseAsync().ContinueWith(async (msg) => await msg.Result.DeleteAsync()); 85 | } 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/Services/LoggingService.cs: -------------------------------------------------------------------------------- 1 | using Discord; 2 | using Discord.WebSocket; 3 | using System; 4 | using System.IO; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.Logging; 7 | using Discord.Interactions; 8 | 9 | namespace NinjaBotCore.Services 10 | { 11 | public class LoggingService 12 | { 13 | private readonly ILogger _logger; 14 | private readonly DiscordShardedClient _discord; 15 | private readonly InteractionService _interactions; 16 | 17 | public LoggingService(ILogger logger, DiscordShardedClient discord, InteractionService interactionService) 18 | { 19 | _discord = discord; 20 | _interactions = interactionService; 21 | _logger = logger; 22 | 23 | 24 | _discord.Log += OnLogAsync; 25 | _interactions.Log += OnLogAsync; 26 | } 27 | 28 | public Task OnLogAsync(LogMessage msg) 29 | { 30 | string logText = $"{msg.Source}: {msg.Exception?.ToString() ?? msg.Message}"; 31 | 32 | switch (msg.Severity.ToString()) 33 | { 34 | case "Critical": 35 | { 36 | _logger.LogCritical(logText); 37 | break; 38 | } 39 | case "Warning": 40 | { 41 | _logger.LogWarning(logText); 42 | break; 43 | } 44 | case "Info": 45 | { 46 | _logger.LogInformation(logText); 47 | break; 48 | } 49 | case "Verbose": 50 | { 51 | _logger.LogInformation(logText); 52 | break; 53 | } 54 | case "Debug": 55 | { 56 | _logger.LogDebug(logText); 57 | break; 58 | } 59 | case "Error": 60 | { 61 | _logger.LogError(logText); 62 | break; 63 | } 64 | } 65 | return Task.CompletedTask; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/Services/NinjaExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace NinjaBotCore.Services 6 | { 7 | public static class NinjaExtensions 8 | { 9 | public static DateTime UnixTimeStampToDateTime(this uint unixTimeStamp) 10 | { 11 | // Unix timestamp is seconds past epoch 12 | System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); 13 | dtDateTime = dtDateTime.AddMilliseconds(unixTimeStamp).ToLocalTime(); 14 | return dtDateTime; 15 | } 16 | 17 | public static DateTime UnixTimeStampToDateTimeSeconds(this uint unixTimeStamp) 18 | { 19 | // Unix timestamp is seconds past epoch 20 | System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); 21 | dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToLocalTime(); 22 | return dtDateTime; 23 | } 24 | 25 | public static string FirstFromSplit(this string source, char delimiter) 26 | { 27 | var i = source.IndexOf(delimiter); 28 | return i == -1 ? source : source.Substring(0, i); 29 | } 30 | 31 | public static string FirstFromSplit(this string source, string delimiter) 32 | { 33 | var i = source.IndexOf(delimiter); 34 | return i == -1 ? source : source.Substring(0, i); 35 | } 36 | 37 | public static string OmitFirstFromSplit(this string source, string delimiter) 38 | { 39 | var i = source.IndexOf(delimiter) + 1; 40 | return i == 1 ? source : source.Substring(i); 41 | } 42 | 43 | public static IAsyncEnumerable AsAsyncEnumerable(this Microsoft.EntityFrameworkCore.DbSet obj) where TEntity : class 44 | { 45 | return Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsAsyncEnumerable(obj); 46 | } 47 | 48 | public static IQueryable Where(this Microsoft.EntityFrameworkCore.DbSet obj, System.Linq.Expressions.Expression> predicate) where TEntity : class 49 | { 50 | return System.Linq.Queryable.Where(obj, predicate); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/Services/StartupService.cs: -------------------------------------------------------------------------------- 1 | using Discord; 2 | using Discord.Commands; 3 | using Discord.WebSocket; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using System; 7 | using System.Reflection; 8 | using System.Threading.Tasks; 9 | 10 | namespace NinjaBotCore.Services 11 | { 12 | public class StartupService 13 | { 14 | private readonly DiscordShardedClient _discord; 15 | private readonly CommandService _commands; 16 | private readonly IConfigurationRoot _config; 17 | private readonly IServiceProvider _services; 18 | 19 | public StartupService(IServiceProvider services) 20 | { 21 | _services = services; 22 | _config = _services.GetRequiredService(); 23 | _discord = _services.GetRequiredService(); 24 | } 25 | 26 | public async Task StartAsync() 27 | { 28 | string discordToken = _config["Token"]; 29 | if (string.IsNullOrWhiteSpace(discordToken)) 30 | { 31 | throw new Exception("Token missing from config.json! Please enter your token there (root directory)"); 32 | } 33 | 34 | await _discord.LoginAsync(TokenType.Bot, discordToken); 35 | await _discord.StartAsync(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /test/NinjaBotCore.Tests/NinjaBotCore.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/NinjaBotCore.Tests/WowUtilitiesTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | using NinjaBotCore.Modules.Wow; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using NinjaBotCore.Services; 6 | using Discord.WebSocket; 7 | using Microsoft.Extensions.Configuration; 8 | using Serilog; 9 | using Microsoft.Extensions.Logging; 10 | using Microsoft.Extensions.Logging.Abstractions; 11 | using System.Collections.Generic; 12 | 13 | namespace NinjaBotCore.Tests 14 | { 15 | public class WowUtilitiesTests 16 | { 17 | WowUtilities _utils; 18 | Microsoft.Extensions.Logging.ILogger logger; 19 | IConfigurationRoot _config; 20 | IServiceProvider _provider; 21 | 22 | public WowUtilitiesTests() 23 | { 24 | var _builder = new ConfigurationBuilder() 25 | .SetBasePath(AppContext.BaseDirectory); 26 | _config = _builder.Build(); 27 | var services = new ServiceCollection() 28 | .AddHttpClient() 29 | .AddSingleton() 30 | .AddSingleton() 31 | .AddSingleton() 32 | .AddSingleton() 33 | .AddSingleton() 34 | .AddSingleton() 35 | .AddSingleton() 36 | .AddSingleton(_config); 37 | 38 | Log.Logger = new LoggerConfiguration() 39 | .WriteTo.Console() 40 | .CreateLogger(); 41 | 42 | services.AddLogging(); 43 | 44 | var serviceProvider = services.BuildServiceProvider(); 45 | _provider = serviceProvider; 46 | 47 | } 48 | 49 | [Fact] 50 | public void GetEmojiFromStringTest() 51 | { 52 | //Arrange 53 | _utils = _provider.GetRequiredService(); 54 | var numMap = new List<(int, string)>() 55 | { 56 | (1, ":one:"), 57 | (2, ":two:"), 58 | (3, ":three:"), 59 | (4, ":four:"), 60 | (5, ":five:"), 61 | (6, ":six:"), 62 | (7, ":seven:"), 63 | (8, ":eight:"), 64 | (9, ":nine:"), 65 | (0, ":zero:"), 66 | (10, ":one::zero:"), 67 | (11, ":one::one:"), 68 | (12, ":one::two:"), 69 | (13, ":one::three:"), 70 | (14, ":one::four:"), 71 | (15, ":one::five:"), 72 | (16, ":one::six:"), 73 | (17, ":one::seven:"), 74 | (18, ":one::eight:"), 75 | (19, ":one::nine:"), 76 | (20, ":two::zero:"), 77 | }; 78 | 79 | //Act and Assert 80 | foreach (var map in numMap) 81 | { 82 | var result = _utils.GetNumberEmojiFromString(map.Item1); 83 | Assert.Equal(map.Item2, result); 84 | } 85 | } 86 | } 87 | } 88 | --------------------------------------------------------------------------------