├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── new-feature---task.md │ └── question.md └── workflows │ └── cicd.yml ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── PRIVACY_POLICY.md ├── azure-pipelines.yml ├── docs ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md └── img │ ├── apps.png │ ├── github-download.png │ ├── vsdeps-asp.png │ ├── vsdeps-base.png │ └── vsdeps-win.png └── src ├── .ruleset ├── Directory.Build.props ├── Miunie.Core ├── Attributes │ └── ServiceAttribute.cs ├── Commands │ ├── CommandPipelineStep.cs │ ├── CommandProcessor.cs │ ├── CommandProcessorInput.cs │ ├── ICommandPipelineStep.cs │ ├── ICommandProcessor.cs │ ├── IMiunieServiceCollection.cs │ ├── MiunieCommandContext.cs │ ├── MiunieServiceCommand.cs │ └── PipelineSteps │ │ ├── PreconditionCheckStep.cs │ │ └── ServiceLocationStep.cs ├── Configuration │ ├── BotConfiguration.cs │ └── IBotConfiguration.cs ├── Discord │ ├── IDiscordConnection.cs │ ├── IDiscordGuilds.cs │ ├── IDiscordImpersonation.cs │ └── IDiscordMessages.cs ├── Entities │ ├── ConnectionState.cs │ ├── Discord │ │ ├── MiunieChannel.cs │ │ ├── MiunieGuild.cs │ │ ├── MiunieRole.cs │ │ └── MiunieUser.cs │ ├── PhraseKey.cs │ ├── Reputation.cs │ ├── ReputationEntry.cs │ ├── ReputationType.cs │ ├── ServiceType.cs │ └── Views │ │ ├── GuildView.cs │ │ ├── MessageView.cs │ │ └── TextChannelView.cs ├── Events │ └── MessageReceivedEventArgs.cs ├── Infrastructure │ ├── IDateTime.cs │ └── IFileSystem.cs ├── Json │ └── IJsonConverter.cs ├── Logging │ ├── ILogReader.cs │ └── ILogWriter.cs ├── Miunie.Core.csproj ├── MiunieBot.cs ├── Providers │ ├── ILanguageProvider.cs │ ├── IMiunieUserProvider.cs │ ├── ITimeManipulationProvider.cs │ ├── IUserReputationProvider.cs │ ├── LanguageProvider.cs │ ├── MiunieUserProvider.cs │ ├── TimeManipulationProvider.cs │ └── UserReputationProvider.cs ├── Services │ ├── MiscService.cs │ ├── PrivacyService.cs │ ├── ProfileService.cs │ ├── RemoteRepositoryService.cs │ └── TimeService.cs ├── Storage │ └── IPersistentStorage.cs ├── Strings.Designer.cs └── Strings.resx ├── Miunie.Discord ├── Adapters │ ├── DiscordGuildsAdapter.cs │ └── DiscordMessagesAdapter.cs ├── CommandHandler.cs ├── CommandModules │ ├── MiscCommands.cs │ ├── PrivacyCommand.cs │ ├── ProfileCommand.cs │ ├── RemoteRepositoryCommand.cs │ └── TimeCommand.cs ├── Convertors │ ├── EntityConvertor.cs │ ├── MiunieChannelConvertor.cs │ ├── MiunieGuildConvertor.cs │ ├── MiunieRoleConvertor.cs │ └── MiunieUserConverter.cs ├── Embeds │ ├── EmbedConstructor.cs │ └── Paginator.cs ├── IDiscord.cs ├── Impersonation.cs ├── Logging │ └── DiscordLogger.cs ├── Miunie.Discord.csproj ├── MiunieDiscord.cs ├── MiunieDiscordClient.cs └── TypeReaders │ └── MiunieUserTypeReader.cs ├── Miunie.Infrastructure ├── Json │ └── JsonConverter.cs ├── LiteDbStorage │ └── PersistentStorage.cs ├── Logging │ ├── ConsoleLogger.cs │ └── InMemoryLogger.cs ├── Miunie.Infrastructure.csproj └── OS │ ├── SystemDateTime.cs │ └── SystemFileSystem.cs ├── Miunie.InversionOfControl ├── Container.cs └── Miunie.InversionOfControl.csproj ├── Miunie.Tests ├── Commands │ ├── MessagePreconditonTests.cs │ └── ServiceLocatorTests.cs ├── Data │ └── DummyMiunieUsers.cs ├── Miunie.Tests.csproj ├── MiunieDiscordClientTests.cs ├── MiunieDiscordTests.cs ├── Providers │ ├── MiunieUserProviderTests.cs │ ├── TimeManipulationProviderTests.cs │ └── UserReputationProviderTests.cs └── Services │ ├── ProfileServiceReputationTests.cs │ ├── ProfileServiceTests.cs │ ├── TimeServiceTests.cs │ └── YesNoServiceTests.cs ├── Miunie.sln └── stylecop.json /.gitattributes: -------------------------------------------------------------------------------- 1 | **/wwwroot/lib/* linguist-vendored 2 | lib/* linguist-vendored 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-feature---task.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New Feature / Task 3 | about: For new issues regarding a new feature or a task 4 | title: "\U0001F49C - Feature Name" 5 | labels: up-for-grabs 6 | assignees: '' 7 | 8 | --- 9 | 10 | > 🟥🟩 **WINDOWS 10** - Version 1903+ is required for the UWP UI. 11 | > 🟦🟨 [How to setup UWP](https://docs.microsoft.com/en-us/windows/uwp/get-started/get-set-up) 12 | 13 | # Remove the above notice if the issue is not about UWP 14 | 15 | > 🌻 This issue is perfect for developers who are new to Miunie! 16 | 17 | ## Summary 18 | 19 | ## How to implement 20 | 21 | ## Interested? 😊 22 | 23 | If you'd like to help us by solving this issue, just say so in the comments. ❤️ 24 | And don't shy away from asking any kind of question you might have. 25 | 26 | Should you have any questions at all, feel free to contact either me (@petrspelos) or @DraxCodes on our Discord server: 27 | 28 | [![Discord](https://img.shields.io/discord/377879473158356992?color=7289DA&label=Discord%20Server&style=for-the-badge)](https://discord.gg/cGhEZuk) 29 | 30 | _And of course, thank you so much for contributing! 🎉 It's because of amazing people like yourself that Miunie exists._ 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Have a question? Feel free to ask. 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Summary 11 | 12 | _Describe what your question is about._ 😊 13 | -------------------------------------------------------------------------------- /.github/workflows/cicd.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | multiplatform_build: 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [ubuntu-latest, windows-latest, macOS-latest] 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Setup .NET Core 20 | uses: actions/setup-dotnet@v1 21 | with: 22 | dotnet-version: 3.1.101 23 | - name: Build with dotnet 24 | run: dotnet build src/Miunie.sln --configuration Release 25 | - name: Run tests 26 | run: dotnet test src/Miunie.Tests 27 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (console)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/src/Miunie.Avalonia/bin/Debug/netcoreapp3.0/Miunie.Avalonia.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/src/Miunie.Avalonia", 16 | // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console 17 | "console": "internalConsole", 18 | "stopAtEntry": false 19 | }, 20 | { 21 | "name": ".NET Core Attach", 22 | "type": "coreclr", 23 | "request": "attach", 24 | "processId": "${command:pickProcess}" 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "titleBar.activeBackground": "#b92a82", 4 | "titleBar.inactiveBackground": "#81275f", 5 | "titleBar.activeForeground": "#ffffff" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/src/Miunie.Avalonia/Miunie.Avalonia.csproj", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | }, 16 | { 17 | "label": "publish", 18 | "command": "dotnet", 19 | "type": "process", 20 | "args": [ 21 | "publish", 22 | "${workspaceFolder}/src/Miunie.Avalonia/Miunie.Avalonia.csproj", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "problemMatcher": "$msCompile" 27 | }, 28 | { 29 | "label": "watch", 30 | "command": "dotnet", 31 | "type": "process", 32 | "args": [ 33 | "watch", 34 | "run", 35 | "${workspaceFolder}/src/Miunie.Avalonia/Miunie.Avalonia.csproj", 36 | "/property:GenerateFullPaths=true", 37 | "/consoleloggerparameters:NoSummary" 38 | ], 39 | "problemMatcher": "$msCompile" 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /PRIVACY_POLICY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | Your privacy is important to us. It is Control.NET policy to respect your privacy regarding any information we may collect from you through our app, Miunie. 4 | 5 | We only ask for personal information when we truly need it to provide a service to you. We collect it on your local machine by fair and lawful means, with your knowledge and consent. We also let you know why we’re collecting it and how it will be used. Your data will only be sent to Discord and will never be collected by us. 6 | 7 | We only retain collected information on your machine for as long as necessary to provide you with your requested service. What data we store, we’ll protect within commercially acceptable means to prevent loss and theft, as well as unauthorised access, disclosure, copying, use or modification. 8 | 9 | We cannot share any personally identifying information publicly or with third-parties, since all of your data is on your machine and is only accessed for ease of use purposes by the locally running application. 10 | 11 | Our app may link to external sites that are not operated by us. Please be aware that we have no control over the content and practices of these sites, and cannot accept responsibility or liability for their respective privacy policies. 12 | 13 | You are free to refuse our request for your personal information, with the understanding that we may be unable to provide you with some of your desired services. 14 | 15 | Your continued use of our application will be regarded as acceptance of our practices around privacy and personal information. If you have any questions about how we handle user data and personal information, feel free to contact us. 16 | 17 | This policy is effective as of 3 March 2020. 18 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # ASP.NET Core / .NET Core app 2 | # Build and test .NET Core projects. 3 | # Add steps that run tests, create a NuGet package, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: 'windows-2019' 11 | 12 | variables: 13 | buildConfiguration: 'Release' 14 | 15 | steps: 16 | - script: dotnet build src/ --configuration $(buildConfiguration) 17 | displayName: 'dotnet build $(buildConfiguration)' 18 | - task: DotNetCoreCLI@2 19 | inputs: 20 | command: test 21 | projects: '**/*Tests/*.csproj' 22 | arguments: '--configuration $(buildConfiguration)' -------------------------------------------------------------------------------- /docs/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at our discord server [here](https://discord.gg/cGhEZuk) . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /docs/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | ## Related Issue 3 | 4 | _What issue does this pull request relate to? If none, please create the issue first._ :+1: 5 | 6 | Fixes # (issue number) 7 | 8 | ## Changes 9 | _Please describe your changes._ 10 | 11 | ## Expected Feedback 12 | _Please describe what feedback you're looking for. This is a good place to mention your code is perhaps a Work In Progress or a Draft and might change._ 13 | 14 | ## Co-Authors 15 | _Please add any co-authors that may have helped with your PR._ 16 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ![Miunie](https://i.ibb.co/2SPrvT7/title.png) 2 | 3 | 4 | GitHub Workflow Status (branch) 5 | 6 | 7 | 8 | license 9 | 10 | 11 | license 12 | 13 | 14 | license 15 | 16 | 17 | **🧡 Miunie is built by these wonderful people:** 18 | 19 | [![](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/images/0)](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/links/0)[![](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/images/1)](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/links/1)[![](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/images/2)](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/links/2)[![](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/images/3)](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/links/3)[![](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/images/4)](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/links/4)[![](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/images/5)](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/links/5)[![](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/images/6)](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/links/6)[![](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/images/7)](https://sourcerer.io/fame/petrspelos/discord-bot-tutorial/Miunie/links/7) 20 | 21 | **💚 Special thanks to:** 22 | 23 | - 🎨 **[wayanfa](https://www.instagram.com/haelequin_55/)** for drawing Miunie. 24 | 25 | **Miunie Core** is a Discord bot framework targetting [.NET Standard](https://docs.microsoft.com/en-us/dotnet/standard/net-standard) 2.0. 26 | 27 | We use Miunie Core in the following front-end projects: 28 | 29 | [![UWP](https://img.shields.io/badge/Miunie-UWP-purple?style=for-the-badge&logo=windows)](https://github.com/control-net/miunie-uwp) 30 | [![Console](https://img.shields.io/badge/Miunie-Console-orange?style=for-the-badge&logo=linux)](https://github.com/control-net/miunie-console) 31 | [![Avalonia UI](https://img.shields.io/badge/Miunie-Avalonia%20Ui-blue?style=for-the-badge&logo=linux)](https://github.com/control-net/miunie-avalonia) 32 | 33 | ![platforms image](img/apps.png) 34 | 35 | ## [🔗 Learn more about Miunie...](https://github.com/control-net/Miunie/wiki/About-Miunie) 36 | 37 | ## Useful links 38 | 39 | ## [🔗 How to help the project](https://github.com/control-net/Miunie/wiki/How-to-help) 40 | 41 | ## [🔗 How to build Miunie from source](https://github.com/control-net/Miunie/wiki/Getting-started-with-Miunie) 42 | 43 | ## [🔗 How to deploy Miunie](https://github.com/control-net/Miunie/wiki/Deploying-Miunie) 44 | 45 | ## Built With 46 | 47 | - .NET Standard 2.0 48 | - [.Net Core 3.1](https://dotnet.microsoft.com/download/dotnet-core) 49 | - [Discord.NET](https://github.com/discord-net/Discord.Net) - Discord API wrapper library 50 | - 💙 Collaborative spirit 51 | - ❤️ Passion 52 | 53 | ## Authors 54 | 55 | - Petr Sedláček - Initial work - [petrspelos](https://github.com/petrspelos) 56 | 57 | See also the list of [contributors](https://github.com/control-net/Miunie/graphs/contributors) who participated in this project. 58 | 59 | ## License 60 | 61 | This project is licensed under the GPL-3.0 License - see the [LICENSE](https://github.com/control-net/Miunie/blob/master/LICENSE) file for details 62 | -------------------------------------------------------------------------------- /docs/img/apps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/control-net/Miunie/1cc652436fb42dca7659497600e350f3981461a8/docs/img/apps.png -------------------------------------------------------------------------------- /docs/img/github-download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/control-net/Miunie/1cc652436fb42dca7659497600e350f3981461a8/docs/img/github-download.png -------------------------------------------------------------------------------- /docs/img/vsdeps-asp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/control-net/Miunie/1cc652436fb42dca7659497600e350f3981461a8/docs/img/vsdeps-asp.png -------------------------------------------------------------------------------- /docs/img/vsdeps-base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/control-net/Miunie/1cc652436fb42dca7659497600e350f3981461a8/docs/img/vsdeps-base.png -------------------------------------------------------------------------------- /docs/img/vsdeps-win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/control-net/Miunie/1cc652436fb42dca7659497600e350f3981461a8/docs/img/vsdeps-win.png -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8.0 4 | ../.ruleset 5 | 6 | 7 | 8 | runtime; build; native; contentfiles; analyzers; buildtransitive 9 | all 10 | 11 | 12 | stylecop.json 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Miunie.Core/Attributes/ServiceAttribute.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities; 17 | using System; 18 | 19 | namespace Miunie.Core.Attributes 20 | { 21 | public sealed class ServiceAttribute : Attribute 22 | { 23 | public ServiceAttribute(ServiceType serviceType = ServiceType.SINGLETON) 24 | { 25 | ServiceType = serviceType; 26 | } 27 | 28 | public ServiceType ServiceType { get; private set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/CommandPipelineStep.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System.Threading.Tasks; 17 | 18 | namespace Miunie.Core.Commands 19 | { 20 | public abstract class CommandPipelineStep : ICommandPipelineStep 21 | { 22 | public CommandPipelineStep(ICommandPipelineStep nextStep) 23 | { 24 | NextStep = nextStep; 25 | } 26 | 27 | protected ICommandPipelineStep NextStep { get; } 28 | 29 | public abstract Task ProcessAsync(CommandProcessorInput input); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/CommandProcessor.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System.Threading.Tasks; 17 | 18 | namespace Miunie.Core.Commands 19 | { 20 | public class CommandProcessor : ICommandProcessor 21 | { 22 | public Task ProcessAsync(CommandProcessorInput input) 23 | { 24 | return Task.CompletedTask; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/CommandProcessorInput.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System.Collections.Generic; 17 | 18 | namespace Miunie.Core.Commands 19 | { 20 | public class CommandProcessorInput 21 | { 22 | public string Message { get; set; } 23 | 24 | /// 25 | /// Gets or sets the position in the Message where the prefix ends. 26 | /// 27 | public uint PrefixOffset { get; set; } 28 | 29 | public ulong MessageId { get; set; } 30 | 31 | public ulong UserId { get; set; } 32 | 33 | public ulong ChannelId { get; set; } 34 | 35 | public ulong? GuildId { get; set; } 36 | 37 | public IEnumerable TargetedCommands { get; set; } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/ICommandPipelineStep.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System.Threading.Tasks; 17 | 18 | namespace Miunie.Core.Commands 19 | { 20 | public interface ICommandPipelineStep 21 | { 22 | Task ProcessAsync(CommandProcessorInput input); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/ICommandProcessor.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System.Threading.Tasks; 17 | 18 | namespace Miunie.Core.Commands 19 | { 20 | public interface ICommandProcessor 21 | { 22 | Task ProcessAsync(CommandProcessorInput input); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/IMiunieServiceCollection.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System.Collections.Generic; 17 | 18 | namespace Miunie.Core.Commands 19 | { 20 | public interface IMiunieServiceCollection 21 | { 22 | IEnumerable GetAvailableCommands(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/MiunieCommandContext.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Commands 17 | { 18 | public class MiunieCommandContext 19 | { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/MiunieServiceCommand.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Commands 17 | { 18 | public class MiunieServiceCommand 19 | { 20 | public string Prompt { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/PipelineSteps/PreconditionCheckStep.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Configuration; 17 | using System.Threading.Tasks; 18 | 19 | namespace Miunie.Core.Commands.PipelineSteps 20 | { 21 | public class PreconditionCheckStep : CommandPipelineStep 22 | { 23 | private readonly IBotConfiguration _config; 24 | 25 | public PreconditionCheckStep(ICommandPipelineStep step, IBotConfiguration config) 26 | : base(step) 27 | { 28 | _config = config; 29 | } 30 | 31 | public override Task ProcessAsync(CommandProcessorInput input) 32 | { 33 | if (!_config.PrefixIsSet) 34 | { 35 | return NextStep.ProcessAsync(input); 36 | } 37 | 38 | if (input.Message.StartsWith(_config.CommandPrefix)) 39 | { 40 | input.PrefixOffset = (uint)_config.CommandPrefix.Length; 41 | return NextStep.ProcessAsync(input); 42 | } 43 | 44 | return Task.CompletedTask; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Miunie.Core/Commands/PipelineSteps/ServiceLocationStep.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Logging; 17 | using System.Linq; 18 | using System.Threading.Tasks; 19 | 20 | namespace Miunie.Core.Commands.PipelineSteps 21 | { 22 | public class ServiceLocationStep : CommandPipelineStep 23 | { 24 | private readonly IMiunieServiceCollection _serviceCollection; 25 | private readonly ILogWriter _logWriter; 26 | 27 | public ServiceLocationStep(ICommandPipelineStep step, IMiunieServiceCollection serviceCollection, ILogWriter logWriter) 28 | : base(step) 29 | { 30 | _serviceCollection = serviceCollection; 31 | _logWriter = logWriter; 32 | } 33 | 34 | public override Task ProcessAsync(CommandProcessorInput input) 35 | { 36 | var commands = _serviceCollection.GetAvailableCommands(); 37 | 38 | if (commands is null || !commands.Any()) 39 | { 40 | _logWriter.Log("Service Location did not get any available commands."); 41 | return Task.CompletedTask; 42 | } 43 | 44 | var prompt = input.Message.Substring((int)input.PrefixOffset).Trim(); 45 | 46 | input.TargetedCommands = commands.Where(c => prompt.StartsWith(c.Prompt)); 47 | return NextStep.ProcessAsync(input); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Miunie.Core/Configuration/BotConfiguration.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Configuration 17 | { 18 | public class BotConfiguration : IBotConfiguration 19 | { 20 | public string DiscordToken { get; set; } 21 | 22 | public bool CommandsEnabled { get; set; } = true; 23 | 24 | public string CommandPrefix { get; set; } 25 | 26 | public bool PrefixIsSet => !string.IsNullOrWhiteSpace(CommandPrefix); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Miunie.Core/Configuration/IBotConfiguration.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Configuration 17 | { 18 | public interface IBotConfiguration 19 | { 20 | bool CommandsEnabled { get; set; } 21 | 22 | string DiscordToken { get; set; } 23 | 24 | string CommandPrefix { get; set; } 25 | 26 | bool PrefixIsSet { get; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Miunie.Core/Discord/IDiscordConnection.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities; 17 | using Miunie.Core.Entities.Discord; 18 | using System; 19 | using System.Threading; 20 | using System.Threading.Tasks; 21 | 22 | namespace Miunie.Core.Discord 23 | { 24 | public interface IDiscordConnection 25 | { 26 | event EventHandler ConnectionChanged; 27 | 28 | ConnectionState ConnectionState { get; } 29 | 30 | bool UserIsMiunie(MiunieUser user); 31 | 32 | Task RunAsync(CancellationToken cancellationToken); 33 | 34 | string GetBotAvatarUrl(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Miunie.Core/Discord/IDiscordGuilds.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities.Discord; 17 | using System.Threading.Tasks; 18 | 19 | namespace Miunie.Core.Discord 20 | { 21 | public interface IDiscordGuilds 22 | { 23 | Task FromAsync(MiunieUser user); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Miunie.Core/Discord/IDiscordImpersonation.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities.Views; 17 | using Miunie.Core.Events; 18 | using System; 19 | using System.Collections.Generic; 20 | using System.Threading.Tasks; 21 | 22 | namespace Miunie.Core.Discord 23 | { 24 | public interface IDiscordImpersonation 25 | { 26 | event EventHandler MessageReceived; 27 | 28 | void SubscribeForMessages(); 29 | 30 | void UnsubscribeForMessages(); 31 | 32 | IEnumerable GetAvailableGuilds(); 33 | 34 | Task> GetAvailableTextChannelsAsync(ulong guildId); 35 | 36 | Task> GetMessagesFromTextChannelAsync(ulong guildId, ulong channelId); 37 | 38 | Task SendTextToChannelAsync(string text, ulong id); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Miunie.Core/Discord/IDiscordMessages.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities; 17 | using Miunie.Core.Entities.Discord; 18 | using System.Collections.Generic; 19 | using System.Threading.Tasks; 20 | 21 | namespace Miunie.Core.Discord 22 | { 23 | public interface IDiscordMessages 24 | { 25 | Task SendMessageAsync(MiunieChannel targetChannel, PhraseKey phraseKey, params object[] parameters); 26 | 27 | Task SendMessageAsync(MiunieChannel targetChannel, MiunieUser user); 28 | 29 | Task SendMessageAsync(MiunieChannel targetChannel, MiunieGuild guild); 30 | 31 | Task SendMessageAsync(MiunieChannel mc, IEnumerable repEntries, int index); 32 | 33 | Task SendDirectFileMessageAsync(MiunieUser mu, string userAsJson); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/ConnectionState.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Entities 17 | { 18 | public enum ConnectionState 19 | { 20 | CONNECTED, 21 | CONNECTING, 22 | DISCONNECTED 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/Discord/MiunieChannel.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Entities.Discord 17 | { 18 | public class MiunieChannel 19 | { 20 | public ulong ChannelId { get; set; } 21 | 22 | public ulong GuildId { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/Discord/MiunieGuild.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | 19 | namespace Miunie.Core.Entities.Discord 20 | { 21 | public class MiunieGuild 22 | { 23 | public ulong Id { get; set; } 24 | 25 | public string Name { get; set; } 26 | 27 | public IEnumerable Roles { get; set; } 28 | 29 | public IEnumerable ChannelNames { get; set; } 30 | 31 | public DateTime CreationDate { get; set; } 32 | 33 | public int TextChannelCount { get; set; } 34 | 35 | public int VoiceChannelCount { get; set; } 36 | 37 | public int MemberCount { get; set; } 38 | 39 | public string IconUrl { get; set; } 40 | 41 | public string GetStats() 42 | => $"{MemberCount} members chatting in \n" + 43 | $":pencil: {TextChannelCount} Text Channel/s & \n" + 44 | $":loudspeaker: {VoiceChannelCount} Voice Channel/s."; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/Discord/MiunieRole.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Entities.Discord 17 | { 18 | public class MiunieRole 19 | { 20 | public ulong Id { get; set; } 21 | 22 | public string Name { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/Discord/MiunieUser.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using System.Linq; 19 | 20 | namespace Miunie.Core.Entities.Discord 21 | { 22 | public class MiunieUser 23 | { 24 | public Guid Id => GenerateSeededGuid(); 25 | 26 | public string Name { get; set; } 27 | 28 | public ulong GuildId { get; set; } 29 | 30 | public ulong UserId { get; set; } 31 | 32 | public Reputation Reputation { get; set; } 33 | 34 | public DateTime JoinedAt { get; set; } 35 | 36 | public DateTime CreatedAt { get; set; } 37 | 38 | public bool IsBot { get; set; } 39 | 40 | public IEnumerable Roles { get; set; } 41 | 42 | public string AvatarUrl { get; set; } 43 | 44 | public TimeSpan? UtcTimeOffset { get; set; } 45 | 46 | private Guid GenerateSeededGuid() 47 | { 48 | var left = BitConverter.GetBytes(GuildId); 49 | var right = BitConverter.GetBytes(UserId); 50 | var bytes = left.Concat(right).ToArray(); 51 | return new Guid(bytes); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/PhraseKey.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Entities 17 | { 18 | public enum PhraseKey 19 | { 20 | REPUTATION_GIVEN, 21 | REPUTATION_TAKEN, 22 | CANNOT_SELF_REP, 23 | SHOW_REMOTE_REPO, 24 | USER_EMBED_TITLE, 25 | USER_EMBED_NAME_TITLE, 26 | USER_EMBED_IS_BOT, 27 | USER_EMBED_IS_HUMAN, 28 | USER_EMBED_REALNESS_TITLE, 29 | USER_EMBED_REP_TITLE, 30 | USER_EMBED_REP_LOG_TITLE, 31 | USER_EMBED_REP_LOG_EMPTY, 32 | USER_EMBED_ROLES_TITLE, 33 | USER_EMBED_JOINED_AT_TITLE, 34 | USER_EMBED_CREATED_AT_TITLE, 35 | GUILD_EMBED_TITLE, 36 | GUILD_EMBED_NAME_TITLE, 37 | GUILD_EMBED_STATS_TITLE, 38 | GUILD_EMBED_ROLES_TITLE, 39 | GUILD_EMBED_CREATED_AT_TITLE, 40 | TIME_NO_TIMEZONE_INFO, 41 | TIME_TIMEZONE_INFO, 42 | TIME_NEW_OFFSET_SET, 43 | TIME_NEW_OFFSET_SET_ADMIN, 44 | USER_EMBED_TIME_TITLE, 45 | USER_EMBED_TIME_NOSET, 46 | USER_EMBED_TIME, 47 | YES_NO_MAYBE, 48 | TIME_USERTIME_FROM_LOCAL, 49 | TIME_USERTIME_IN_FUTURE, 50 | TIME_USERTIME_IN_FUTURE_UNPARSABLE, 51 | TIME_NO_MESSAGE, 52 | TIME_MESSAGE_INFO_EDIT, 53 | TIME_MESSAGE_INFO_NO_EDIT, 54 | INCORRECT_VERB, 55 | REPUTATION_TAKEN_BOT, 56 | REPUTATION_GIVEN_BOT, 57 | USER_PRIVACY_FILE_MESSAGE, 58 | USER_PRIVACY_DATA_REMOVED, 59 | GPL3_NOTICE 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/Reputation.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System; 17 | using System.Collections.Concurrent; 18 | 19 | namespace Miunie.Core.Entities 20 | { 21 | public class Reputation 22 | { 23 | public Reputation() 24 | { 25 | PlusRepLog = new ConcurrentDictionary(); 26 | MinusRepLog = new ConcurrentDictionary(); 27 | } 28 | 29 | public int Value { get; set; } 30 | 31 | public ConcurrentDictionary PlusRepLog { get; set; } 32 | 33 | public ConcurrentDictionary MinusRepLog { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/ReputationEntry.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System; 17 | 18 | namespace Miunie.Core.Entities 19 | { 20 | public class ReputationEntry 21 | { 22 | public ReputationEntry(ulong targetId, string targetName, DateTime givenAt, ReputationType type, bool isfromInvoker = false) 23 | { 24 | TargetId = targetId; 25 | TargetName = targetName; 26 | GivenAt = givenAt; 27 | Type = type; 28 | IsFromInvoker = isfromInvoker; 29 | } 30 | 31 | public ulong TargetId { get; set; } 32 | 33 | public string TargetName { get; set; } 34 | 35 | public DateTime GivenAt { get; set; } 36 | 37 | public ReputationType Type { get; set; } 38 | 39 | public bool IsFromInvoker { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/ReputationType.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Entities 17 | { 18 | public enum ReputationType 19 | { 20 | Plus = 1, 21 | Minus = 2 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/ServiceType.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Entities 17 | { 18 | public enum ServiceType 19 | { 20 | SCOPED, 21 | SINGLETON, 22 | TRANSIENT 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/Views/GuildView.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Entities.Views 17 | { 18 | public class GuildView 19 | { 20 | public ulong Id { get; set; } 21 | 22 | public string Name { get; set; } 23 | 24 | public string IconUrl { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/Views/MessageView.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System; 17 | 18 | namespace Miunie.Core.Entities.Views 19 | { 20 | public class MessageView 21 | { 22 | public ulong ChannelId { get; set; } 23 | 24 | public string AuthorName { get; set; } 25 | 26 | public string AuthorAvatarUrl { get; set; } 27 | 28 | public string Content { get; set; } 29 | 30 | public DateTimeOffset TimeStamp { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Miunie.Core/Entities/Views/TextChannelView.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System.Collections.Generic; 17 | 18 | namespace Miunie.Core.Entities.Views 19 | { 20 | public class TextChannelView 21 | { 22 | public ulong Id { get; set; } 23 | 24 | public string Name { get; set; } 25 | 26 | public IEnumerable Messages { get; set; } 27 | 28 | public bool CanSendMessages { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Miunie.Core/Events/MessageReceivedEventArgs.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities.Views; 17 | using System; 18 | 19 | namespace Miunie.Core.Events 20 | { 21 | public class MessageReceivedEventArgs : EventArgs 22 | { 23 | public MessageReceivedEventArgs(MessageView message) 24 | { 25 | Message = message; 26 | } 27 | 28 | public MessageView Message { get; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Miunie.Core/Infrastructure/IDateTime.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System; 17 | 18 | namespace Miunie.Core.Infrastructure 19 | { 20 | public interface IDateTime 21 | { 22 | DateTime UtcNow { get; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Miunie.Core/Infrastructure/IFileSystem.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Infrastructure 17 | { 18 | public interface IFileSystem 19 | { 20 | string DataStoragePath { get; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Miunie.Core/Json/IJsonConverter.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Json 17 | { 18 | public interface IJsonConverter 19 | { 20 | string Serialize(T obj); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Miunie.Core/Logging/ILogReader.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | 19 | namespace Miunie.Core.Logging 20 | { 21 | public interface ILogReader 22 | { 23 | event EventHandler LogRecieved; 24 | 25 | IEnumerable RetrieveLogs(int ammount = 5); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Miunie.Core/Logging/ILogWriter.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Logging 17 | { 18 | public interface ILogWriter 19 | { 20 | void Log(string message); 21 | 22 | void LogError(string message); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Miunie.Core/Miunie.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | GPL-3.0 6 | LICENSE 7 | https://github.com/control-net/Miunie 8 | https://github.com/control-net/Miunie 9 | git 10 | 11 | 12 | 13 | 14 | True 15 | True 16 | Strings.resx 17 | 18 | 19 | 20 | 21 | 22 | PublicResXFileCodeGenerator 23 | Strings.Designer.cs 24 | 25 | 26 | 27 | 28 | 29 | True 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Miunie.Core/MiunieBot.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Configuration; 17 | using Miunie.Core.Discord; 18 | using System.Threading; 19 | using System.Threading.Tasks; 20 | 21 | namespace Miunie.Core 22 | { 23 | public class MiunieBot 24 | { 25 | private CancellationTokenSource _tokenSource; 26 | 27 | public MiunieBot(IDiscordConnection miunieDiscord, IBotConfiguration botConfig, IDiscordImpersonation impersonation) 28 | { 29 | MiunieDiscord = miunieDiscord; 30 | BotConfiguration = botConfig; 31 | Impersonation = impersonation; 32 | } 33 | 34 | public IBotConfiguration BotConfiguration { get; } 35 | 36 | public IDiscordConnection MiunieDiscord { get; } 37 | 38 | public IDiscordImpersonation Impersonation { get; } 39 | 40 | public async Task StartAsync() 41 | { 42 | _tokenSource = new CancellationTokenSource(); 43 | await MiunieDiscord.RunAsync(_tokenSource.Token); 44 | } 45 | 46 | public void Stop() 47 | { 48 | if (_tokenSource is null) { return; } 49 | _tokenSource.Cancel(); 50 | _tokenSource.Dispose(); 51 | _tokenSource = null; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Miunie.Core/Providers/ILanguageProvider.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | namespace Miunie.Core.Providers 17 | { 18 | public interface ILanguageProvider 19 | { 20 | string GetPhrase(string key, params object[] objs); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Miunie.Core/Providers/IMiunieUserProvider.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities.Discord; 17 | using System.Collections.Generic; 18 | 19 | namespace Miunie.Core.Providers 20 | { 21 | public interface IMiunieUserProvider 22 | { 23 | MiunieUser GetById(ulong userId, ulong guildId); 24 | 25 | void StoreUser(MiunieUser u); 26 | 27 | void RemoveUser(MiunieUser u); 28 | 29 | IEnumerable GetAllUsers(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Miunie.Core/Providers/ITimeManipulationProvider.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities.Discord; 17 | using System; 18 | 19 | namespace Miunie.Core.Providers 20 | { 21 | public interface ITimeManipulationProvider 22 | { 23 | TimeSpan? GetTimeSpanFromString(string timeframe, int units); 24 | 25 | DateTime? GetDateTimeLocalToUser(DateTime? utcDateTime, MiunieUser user); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Miunie.Core/Providers/IUserReputationProvider.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities; 17 | using Miunie.Core.Entities.Discord; 18 | using System.Collections.Generic; 19 | 20 | namespace Miunie.Core.Providers 21 | { 22 | public interface IUserReputationProvider 23 | { 24 | int TimeoutInSeconds { get; } 25 | 26 | void AddReputation(MiunieUser invoker, MiunieUser target); 27 | 28 | void RemoveReputation(MiunieUser invoker, MiunieUser target); 29 | 30 | bool CanAddReputation(MiunieUser invoker, MiunieUser target); 31 | 32 | bool CanRemoveReputation(MiunieUser invoker, MiunieUser target); 33 | 34 | IEnumerable GetReputation(MiunieUser user); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Miunie.Core/Providers/LanguageProvider.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Logging; 17 | using System; 18 | 19 | namespace Miunie.Core.Providers 20 | { 21 | public class LanguageProvider : ILanguageProvider 22 | { 23 | private static readonly string[] ResourceSeparators = { "{{OR}}" }; 24 | 25 | private readonly ILogWriter _logger; 26 | private readonly Random _random; 27 | 28 | public LanguageProvider(ILogWriter logger, Random random) 29 | { 30 | _logger = logger; 31 | _random = random; 32 | } 33 | 34 | public string GetPhrase(string key, params object[] objs) 35 | { 36 | var resource = Strings.ResourceManager.GetString(key); 37 | if (resource is null) 38 | { 39 | _logger.LogError($"Unable to find Language Resource with the following key: {key}"); 40 | return string.Empty; 41 | } 42 | 43 | var pool = resource.Split(ResourceSeparators, StringSplitOptions.RemoveEmptyEntries); 44 | return string.Format(pool[_random.Next(0, pool.Length)], objs); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Miunie.Core/Providers/MiunieUserProvider.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities; 17 | using Miunie.Core.Entities.Discord; 18 | using Miunie.Core.Storage; 19 | using System.Collections.Generic; 20 | 21 | namespace Miunie.Core.Providers 22 | { 23 | public class MiunieUserProvider : IMiunieUserProvider 24 | { 25 | private readonly IPersistentStorage _persistentStorage; 26 | 27 | public MiunieUserProvider(IPersistentStorage persistentStorage) 28 | { 29 | _persistentStorage = persistentStorage; 30 | } 31 | 32 | public MiunieUser GetById(ulong userId, ulong guildId) 33 | { 34 | var user = _persistentStorage.RestoreSingle(u => u.UserId == userId && u.GuildId == guildId); 35 | return EnsureExists(user, userId, guildId); 36 | } 37 | 38 | public void StoreUser(MiunieUser user) 39 | { 40 | if (_persistentStorage.Exists(u => u.UserId == user.UserId && u.GuildId == user.GuildId)) 41 | { 42 | _persistentStorage.Update(user); 43 | } 44 | else 45 | { 46 | _persistentStorage.Store(user); 47 | } 48 | } 49 | 50 | public void RemoveUser(MiunieUser user) 51 | { 52 | if (_persistentStorage.Exists(u => u.UserId == user.UserId && u.GuildId == user.GuildId)) 53 | { 54 | _persistentStorage.Remove(u => u.UserId == user.UserId && u.GuildId == user.GuildId); 55 | } 56 | } 57 | 58 | public IEnumerable GetAllUsers() 59 | => _persistentStorage.RestoreAll(); 60 | 61 | private MiunieUser EnsureExists( 62 | MiunieUser user, 63 | ulong userId, 64 | ulong guildId) 65 | { 66 | if (user is null) 67 | { 68 | user = new MiunieUser 69 | { 70 | GuildId = guildId, 71 | UserId = userId, 72 | Reputation = new Reputation() 73 | }; 74 | StoreUser(user); 75 | } 76 | 77 | return user; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Miunie.Core/Providers/TimeManipulationProvider.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities.Discord; 17 | using System; 18 | 19 | namespace Miunie.Core.Providers 20 | { 21 | public class TimeManipulationProvider : ITimeManipulationProvider 22 | { 23 | public TimeSpan? GetTimeSpanFromString(string timeframe, int units) 24 | { 25 | if (string.IsNullOrWhiteSpace(timeframe) || units <= 0) 26 | { 27 | return null; 28 | } 29 | 30 | timeframe = timeframe.Trim().ToLower(); 31 | 32 | return timeframe switch { 33 | var tframe when 34 | tframe == "hours" || tframe == "hour" || tframe == "hrs" || tframe == "hr" 35 | => new TimeSpan(units, 0, 0), 36 | var tframe when 37 | tframe == "minutes" || tframe == "minute" || tframe == "mins" || tframe == "min" 38 | => new TimeSpan(0, units, 0), 39 | var tframe when 40 | tframe == "seconds" || tframe == "second" || tframe == "secs" || tframe == "sec" 41 | => new TimeSpan(0, 0, units), 42 | _ => null, 43 | }; 44 | } 45 | 46 | public DateTime? GetDateTimeLocalToUser(DateTime? utcDateTime, MiunieUser user) 47 | { 48 | if (!utcDateTime.HasValue) 49 | { 50 | return utcDateTime; 51 | } 52 | 53 | if (user.UtcTimeOffset.HasValue) 54 | { 55 | return utcDateTime.Value.Add(user.UtcTimeOffset.Value); 56 | } 57 | 58 | return utcDateTime; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Miunie.Core/Providers/UserReputationProvider.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities; 17 | using Miunie.Core.Entities.Discord; 18 | using Miunie.Core.Infrastructure; 19 | using System; 20 | using System.Collections.Concurrent; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | namespace Miunie.Core.Providers 25 | { 26 | public class UserReputationProvider : IUserReputationProvider 27 | { 28 | private readonly IMiunieUserProvider _userProvider; 29 | private readonly IDateTime _dateTime; 30 | 31 | public UserReputationProvider(IMiunieUserProvider userProvider, IDateTime dateTime) 32 | { 33 | _userProvider = userProvider; 34 | _dateTime = dateTime; 35 | } 36 | 37 | public int TimeoutInSeconds { get; } = 1800; 38 | 39 | public IEnumerable GetReputation(MiunieUser invoker) 40 | { 41 | var rep = new List(); 42 | 43 | if (invoker is null || invoker.Reputation is null) { return rep; } 44 | 45 | foreach (MiunieUser user in _userProvider.GetAllUsers().Where(x => x.Id != invoker.Id)) 46 | { 47 | if (user.Reputation.PlusRepLog.ContainsKey(invoker.UserId)) 48 | { 49 | rep.Add(new ReputationEntry(user.UserId, user.Name, user.Reputation.PlusRepLog[invoker.UserId], ReputationType.Plus, true)); 50 | } 51 | 52 | if (user.Reputation.MinusRepLog.ContainsKey(invoker.UserId)) 53 | { 54 | rep.Add(new ReputationEntry(user.UserId, user.Name, user.Reputation.PlusRepLog[invoker.UserId], ReputationType.Minus, true)); 55 | } 56 | } 57 | 58 | foreach (KeyValuePair entry in invoker.Reputation.PlusRepLog) 59 | { 60 | var user = _userProvider.GetById(entry.Key, invoker.GuildId); 61 | rep.Add(new ReputationEntry(user.UserId, user.Name, entry.Value, ReputationType.Plus)); 62 | } 63 | 64 | foreach (KeyValuePair entry in invoker.Reputation.MinusRepLog) 65 | { 66 | var user = _userProvider.GetById(entry.Key, invoker.GuildId); 67 | rep.Add(new ReputationEntry(user.UserId, user.Name, entry.Value, ReputationType.Minus)); 68 | } 69 | 70 | return rep.OrderByDescending(x => x.GivenAt); 71 | } 72 | 73 | public void AddReputation(MiunieUser invoker, MiunieUser target) 74 | { 75 | target.Reputation.Value++; 76 | _ = target.Reputation.PlusRepLog.TryAdd(invoker.UserId, _dateTime.UtcNow); 77 | _userProvider.StoreUser(target); 78 | } 79 | 80 | public void RemoveReputation(MiunieUser invoker, MiunieUser target) 81 | { 82 | target.Reputation.Value--; 83 | _ = target.Reputation.MinusRepLog.TryAdd(invoker.UserId, _dateTime.UtcNow); 84 | _userProvider.StoreUser(target); 85 | } 86 | 87 | public bool CanAddReputation(MiunieUser invoker, MiunieUser target) 88 | => HasTimeout(target.Reputation.PlusRepLog, invoker); 89 | 90 | public bool CanRemoveReputation(MiunieUser invoker, MiunieUser target) 91 | => HasTimeout(target.Reputation.MinusRepLog, invoker); 92 | 93 | private bool HasTimeout(ConcurrentDictionary log, MiunieUser invoker) 94 | { 95 | _ = log.TryGetValue(invoker.UserId, out var lastRepDateTime); 96 | 97 | if ((_dateTime.UtcNow - lastRepDateTime).TotalSeconds <= TimeoutInSeconds) { return true; } 98 | 99 | _ = log.TryRemove(invoker.UserId, out _); 100 | _userProvider.StoreUser(invoker); 101 | return false; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Miunie.Core/Services/MiscService.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Attributes; 17 | using Miunie.Core.Discord; 18 | using Miunie.Core.Entities; 19 | using Miunie.Core.Entities.Discord; 20 | using System.Threading.Tasks; 21 | 22 | namespace Miunie.Core 23 | { 24 | [Service] 25 | public class MiscService 26 | { 27 | private readonly IDiscordMessages _messages; 28 | 29 | public MiscService(IDiscordMessages messages) 30 | { 31 | _messages = messages; 32 | } 33 | 34 | public async Task SendRandomYesNoAnswerAsync(MiunieChannel channel) 35 | { 36 | await _messages.SendMessageAsync(channel, PhraseKey.YES_NO_MAYBE); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Miunie.Core/Services/PrivacyService.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Attributes; 17 | using Miunie.Core.Discord; 18 | using Miunie.Core.Entities; 19 | using Miunie.Core.Entities.Discord; 20 | using Miunie.Core.Json; 21 | using Miunie.Core.Providers; 22 | using System.Threading.Tasks; 23 | 24 | namespace Miunie.Core 25 | { 26 | [Service] 27 | public class PrivacyService 28 | { 29 | private readonly IDiscordMessages _messages; 30 | private readonly IMiunieUserProvider _users; 31 | private readonly IJsonConverter _jsonParser; 32 | 33 | public PrivacyService(IDiscordMessages messages, IMiunieUserProvider users, IJsonConverter jsonParser) 34 | { 35 | _messages = messages; 36 | _users = users; 37 | _jsonParser = jsonParser; 38 | } 39 | 40 | public async Task OutputUserJsonDataAsync(MiunieUser user) 41 | { 42 | var userJson = _jsonParser.Serialize(user); 43 | await _messages.SendDirectFileMessageAsync(user, userJson); 44 | } 45 | 46 | public async Task RemoveUserData(MiunieUser user, MiunieChannel channel) 47 | { 48 | _users.RemoveUser(user); 49 | await _messages.SendMessageAsync(channel, PhraseKey.USER_PRIVACY_DATA_REMOVED, user.Name); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Miunie.Core/Services/ProfileService.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Attributes; 17 | using Miunie.Core.Discord; 18 | using Miunie.Core.Entities; 19 | using Miunie.Core.Entities.Discord; 20 | using Miunie.Core.Logging; 21 | using Miunie.Core.Providers; 22 | using System.Threading.Tasks; 23 | 24 | namespace Miunie.Core 25 | { 26 | [Service] 27 | public class ProfileService 28 | { 29 | private readonly IDiscordMessages _discordMessages; 30 | private readonly IUserReputationProvider _reputationProvider; 31 | private readonly ILogWriter _logger; 32 | private readonly IDiscordConnection _miunieDiscord; 33 | 34 | public ProfileService(IDiscordMessages discordMessages, IUserReputationProvider reputationProvider, ILogWriter logger, IDiscordConnection miunieDiscord) 35 | { 36 | _discordMessages = discordMessages; 37 | _reputationProvider = reputationProvider; 38 | _logger = logger; 39 | _miunieDiscord = miunieDiscord; 40 | } 41 | 42 | public async Task ShowProfileAsync(MiunieUser user, MiunieChannel c) 43 | => await _discordMessages.SendMessageAsync(c, user); 44 | 45 | public async Task ShowReputationLogAsync(MiunieUser user, int page, MiunieChannel c) 46 | { 47 | page -= 1; 48 | var repGiven = _reputationProvider.GetReputation(user); 49 | 50 | await _discordMessages.SendMessageAsync(c, repGiven, page); 51 | } 52 | 53 | public async Task GiveReputationAsync(MiunieUser invoker, MiunieUser target, MiunieChannel c) 54 | { 55 | if (invoker.UserId == target.UserId) 56 | { 57 | await _discordMessages.SendMessageAsync(c, PhraseKey.CANNOT_SELF_REP, invoker.Name); 58 | return; 59 | } 60 | 61 | if (_reputationProvider.CanAddReputation(invoker, target)) 62 | { 63 | _logger.Log($"User '{invoker.Name}' has a reputation timeout for User '{target.Name}', ignoring..."); 64 | return; 65 | } 66 | 67 | _reputationProvider.AddReputation(invoker, target); 68 | 69 | if (_miunieDiscord.UserIsMiunie(target)) 70 | { 71 | await _discordMessages.SendMessageAsync(c, PhraseKey.REPUTATION_GIVEN_BOT, invoker.Name); 72 | return; 73 | } 74 | 75 | await _discordMessages.SendMessageAsync(c, PhraseKey.REPUTATION_GIVEN, target.Name, invoker.Name); 76 | } 77 | 78 | public async Task RemoveReputationAsync(MiunieUser invoker, MiunieUser target, MiunieChannel c) 79 | { 80 | if (invoker.UserId == target.UserId) 81 | { 82 | await _discordMessages.SendMessageAsync(c, PhraseKey.CANNOT_SELF_REP, invoker.Name); 83 | return; 84 | } 85 | 86 | if (_reputationProvider.CanRemoveReputation(invoker, target)) { return; } 87 | 88 | _reputationProvider.RemoveReputation(invoker, target); 89 | 90 | if (_miunieDiscord.UserIsMiunie(target)) 91 | { 92 | await _discordMessages.SendMessageAsync(c, PhraseKey.REPUTATION_TAKEN_BOT, invoker.Name); 93 | return; 94 | } 95 | 96 | await _discordMessages.SendMessageAsync(c, PhraseKey.REPUTATION_TAKEN, invoker.Name, target.Name); 97 | } 98 | 99 | public async Task ShowGuildProfileAsync(MiunieGuild guild, MiunieChannel c) 100 | => await _discordMessages.SendMessageAsync(c, guild); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Miunie.Core/Services/RemoteRepositoryService.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Attributes; 17 | using Miunie.Core.Discord; 18 | using Miunie.Core.Entities; 19 | using Miunie.Core.Entities.Discord; 20 | using System.Threading.Tasks; 21 | 22 | namespace Miunie.Core 23 | { 24 | [Service] 25 | public class RemoteRepositoryService 26 | { 27 | private readonly IDiscordMessages _discordMessages; 28 | 29 | public RemoteRepositoryService(IDiscordMessages discordMessages) 30 | { 31 | _discordMessages = discordMessages; 32 | } 33 | 34 | public async Task ShowRepositoryAsync(MiunieChannel c) 35 | => await _discordMessages.SendMessageAsync(c, PhraseKey.SHOW_REMOTE_REPO); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Miunie.Core/Services/TimeService.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Attributes; 17 | using Miunie.Core.Discord; 18 | using Miunie.Core.Entities; 19 | using Miunie.Core.Entities.Discord; 20 | using Miunie.Core.Infrastructure; 21 | using Miunie.Core.Providers; 22 | using System; 23 | using System.Threading.Tasks; 24 | 25 | namespace Miunie.Core 26 | { 27 | [Service] 28 | public class TimeService 29 | { 30 | private readonly IDiscordMessages _messages; 31 | private readonly IDateTime _dateTime; 32 | private readonly IMiunieUserProvider _users; 33 | private readonly ITimeManipulationProvider _timeManipulator; 34 | 35 | public TimeService(IDiscordMessages messages, IDateTime dateTime, IMiunieUserProvider users, ITimeManipulationProvider timeManipulator) 36 | { 37 | _messages = messages; 38 | _dateTime = dateTime; 39 | _users = users; 40 | _timeManipulator = timeManipulator; 41 | } 42 | 43 | public async Task OutputCurrentTimeForUserAsync(MiunieUser user, MiunieChannel channel) 44 | { 45 | if (!user.UtcTimeOffset.HasValue) 46 | { 47 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_NO_TIMEZONE_INFO, user.Name); 48 | return; 49 | } 50 | 51 | var targetDateTime = _dateTime.UtcNow + user.UtcTimeOffset.Value; 52 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_TIMEZONE_INFO, user.Name, targetDateTime); 53 | } 54 | 55 | public async Task OutputCurrentTimeComparedToInputForUserAsync(MiunieUser requestUser, DateTime requestTime, string verb, MiunieUser user, MiunieChannel channel) 56 | { 57 | if (verb.Trim().ToLower() != "for") 58 | { 59 | await _messages.SendMessageAsync(channel, PhraseKey.INCORRECT_VERB, verb); 60 | return; 61 | } 62 | 63 | var requesterOffset = requestUser.UtcTimeOffset ?? default; 64 | var otherUserOffSet = user.UtcTimeOffset ?? default; 65 | 66 | var requestUtcTime = requestTime - requesterOffset; 67 | var otherUserTime = requestUtcTime + otherUserOffSet; 68 | 69 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_USERTIME_FROM_LOCAL, requestTime, user.Name, otherUserTime); 70 | } 71 | 72 | public async Task OutputFutureTimeForUserAsync(MiunieUser user, string verb, int units, string timeframe, MiunieChannel channel) 73 | { 74 | if (verb.Trim().ToLower() != "in") 75 | { 76 | await _messages.SendMessageAsync(channel, PhraseKey.INCORRECT_VERB, verb); 77 | return; 78 | } 79 | 80 | var timeFromLocal = _timeManipulator.GetTimeSpanFromString(timeframe, units); 81 | 82 | if (timeFromLocal is null) 83 | { 84 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_USERTIME_IN_FUTURE_UNPARSABLE, units.ToString(), timeframe); 85 | return; 86 | } 87 | 88 | var usersOffset = user.UtcTimeOffset ?? default; 89 | var usersLocalTime = _dateTime.UtcNow + usersOffset; 90 | var usersFutureTime = usersLocalTime + timeFromLocal; 91 | 92 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_USERTIME_IN_FUTURE, user.Name, usersFutureTime, units.ToString(), timeframe); 93 | } 94 | 95 | public async Task OutputMessageTimeAsLocalAsync(ulong messageId, DateTimeOffset? createdTimeOffset, DateTimeOffset? editTimeOffset, MiunieUser user, MiunieChannel channel) 96 | { 97 | if (createdTimeOffset is null) 98 | { 99 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_NO_MESSAGE, messageId.ToString()); 100 | return; 101 | } 102 | 103 | var messageCreated = _timeManipulator.GetDateTimeLocalToUser(createdTimeOffset?.UtcDateTime, user); 104 | var messageEdited = _timeManipulator.GetDateTimeLocalToUser(editTimeOffset?.UtcDateTime, user); 105 | 106 | if (messageEdited.HasValue) 107 | { 108 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_MESSAGE_INFO_EDIT, messageId.ToString(), messageCreated, messageEdited); 109 | return; 110 | } 111 | 112 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_MESSAGE_INFO_NO_EDIT, messageId.ToString(), messageCreated); 113 | } 114 | 115 | public async Task SetUtcOffsetForUserAsync(DateTime userTime, MiunieUser user, MiunieChannel channel) 116 | { 117 | var offset = TimeSpan.FromHours(userTime.Hour - _dateTime.UtcNow.Hour); 118 | user.UtcTimeOffset = offset; 119 | _users.StoreUser(user); 120 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_NEW_OFFSET_SET); 121 | } 122 | 123 | public async Task SetUtcOffsetForUserByAdminAsync(DateTime userTime, MiunieUser user, MiunieChannel channel) 124 | { 125 | var offset = TimeSpan.FromHours(userTime.Hour - _dateTime.UtcNow.Hour); 126 | user.UtcTimeOffset = offset; 127 | _users.StoreUser(user); 128 | await _messages.SendMessageAsync(channel, PhraseKey.TIME_NEW_OFFSET_SET_ADMIN, user.Name); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Miunie.Core/Storage/IPersistentStorage.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using System; 17 | using System.Collections.Generic; 18 | using System.Linq.Expressions; 19 | 20 | namespace Miunie.Core.Storage 21 | { 22 | public interface IPersistentStorage 23 | { 24 | void Store(T item); 25 | 26 | void Update(T item); 27 | 28 | void Remove(Expression> predicate); 29 | 30 | IEnumerable RestoreMany(Expression> predicate); 31 | 32 | IEnumerable RestoreAll(); 33 | 34 | T RestoreSingle(Expression> predicate); 35 | 36 | bool Exists(Expression> predicate); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Adapters/DiscordGuildsAdapter.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Discord; 17 | using Miunie.Core.Entities.Discord; 18 | using Miunie.Discord.Convertors; 19 | using System.Threading.Tasks; 20 | 21 | namespace Miunie.Discord.Adapters 22 | { 23 | public class DiscordGuildsAdapter : IDiscordGuilds 24 | { 25 | private readonly IDiscord _discord; 26 | private readonly EntityConvertor _entityConvertor; 27 | 28 | public DiscordGuildsAdapter(IDiscord discord, EntityConvertor entityConvertor) 29 | { 30 | _discord = discord; 31 | _entityConvertor = entityConvertor; 32 | } 33 | 34 | public Task FromAsync(MiunieUser user) 35 | { 36 | var guild = _discord.Client.GetGuild(user.GuildId); 37 | 38 | return Task.FromResult(_entityConvertor.ConvertGuild(guild)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Adapters/DiscordMessagesAdapter.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.WebSocket; 17 | using Miunie.Core.Discord; 18 | using Miunie.Core.Entities; 19 | using Miunie.Core.Entities.Discord; 20 | using Miunie.Core.Logging; 21 | using Miunie.Core.Providers; 22 | using Miunie.Discord.Embeds; 23 | using System.Collections.Generic; 24 | using System.IO; 25 | using System.Threading.Tasks; 26 | 27 | namespace Miunie.Discord.Adapters 28 | { 29 | public class DiscordMessagesAdapter : IDiscordMessages 30 | { 31 | private readonly IDiscord _discord; 32 | private readonly ILanguageProvider _lang; 33 | private readonly ILogWriter _log; 34 | 35 | public DiscordMessagesAdapter(IDiscord discord, ILanguageProvider lang, ILogWriter log) 36 | { 37 | _discord = discord; 38 | _lang = lang; 39 | _log = log; 40 | } 41 | 42 | public async Task SendMessageAsync(MiunieChannel mc, IEnumerable repEntries, int index) 43 | { 44 | var channel = _discord.Client.GetChannel(mc.ChannelId) as SocketTextChannel; 45 | var embed = EmbedConstructor.CreateReputationLog(repEntries, index, _lang); 46 | 47 | _ = await channel.SendMessageAsync(embed: embed); 48 | } 49 | 50 | public async Task SendMessageAsync(MiunieChannel mc, PhraseKey phraseKey, params object[] parameters) 51 | { 52 | var channel = _discord.Client.GetChannel(mc.ChannelId) as SocketTextChannel; 53 | var msg = _lang.GetPhrase(phraseKey.ToString(), parameters); 54 | _ = await channel.SendMessageAsync(msg); 55 | } 56 | 57 | public async Task SendMessageAsync(MiunieChannel mc, MiunieUser mu) 58 | { 59 | if (!(_discord.Client.GetChannel(mc.ChannelId) is SocketTextChannel channel)) 60 | { 61 | LogSocketTextChannelCastFailed(); 62 | return; 63 | } 64 | 65 | _ = await channel.SendMessageAsync(embed: mu.ToEmbed(_lang)); 66 | } 67 | 68 | public async Task SendMessageAsync(MiunieChannel mc, MiunieGuild mg) 69 | { 70 | if (!(_discord.Client.GetChannel(mc.ChannelId) is SocketTextChannel channel)) 71 | { 72 | LogSocketTextChannelCastFailed(); 73 | return; 74 | } 75 | 76 | _ = await channel.SendMessageAsync(embed: mg.ToEmbed(_lang)); 77 | } 78 | 79 | public async Task SendDirectFileMessageAsync(MiunieUser mu, string userAsJson) 80 | { 81 | var dmChannel = await _discord.Client.GetUser(mu.UserId).GetOrCreateDMChannelAsync(); 82 | var msg = _lang.GetPhrase(PhraseKey.USER_PRIVACY_FILE_MESSAGE.ToString(), mu.Name); 83 | 84 | using var fileStream = GenerateStreamFromString(userAsJson); 85 | _ = await dmChannel.SendFileAsync(fileStream, $"{mu.Name}.json", msg); 86 | } 87 | 88 | private static Stream GenerateStreamFromString(string s) 89 | { 90 | var stream = new MemoryStream(); 91 | var writer = new StreamWriter(stream); 92 | writer.Write(s); 93 | writer.Flush(); 94 | stream.Position = 0; 95 | return stream; 96 | } 97 | 98 | private void LogSocketTextChannelCastFailed() 99 | { 100 | _log.LogError("Invalid cast to SocketTextChannel."); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Miunie.Discord/CommandHandler.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.Commands; 17 | using Discord.WebSocket; 18 | using Miunie.Core.Commands; 19 | using Miunie.Core.Configuration; 20 | using Miunie.Core.Entities.Discord; 21 | using Miunie.Core.Logging; 22 | using Miunie.Discord.Convertors; 23 | using Miunie.Discord.TypeReaders; 24 | using System; 25 | using System.Reflection; 26 | using System.Threading.Tasks; 27 | 28 | namespace Miunie.Discord 29 | { 30 | public class CommandHandler 31 | { 32 | private readonly CommandService _commandService; 33 | private readonly IDiscord _discord; 34 | private readonly IServiceProvider _services; 35 | private readonly ILogWriter _logger; 36 | private readonly EntityConvertor _convertor; 37 | private readonly IBotConfiguration _botConfig; 38 | private readonly ICommandProcessor _commandProcessor; 39 | 40 | public CommandHandler(IDiscord discord, IServiceProvider services, ILogWriter logger, EntityConvertor convertor, IBotConfiguration botConfig, ICommandProcessor commandProcessor) 41 | { 42 | _discord = discord; 43 | _commandService = new CommandService(); 44 | _services = services; 45 | _logger = logger; 46 | _convertor = convertor; 47 | _botConfig = botConfig; 48 | _commandProcessor = commandProcessor; 49 | } 50 | 51 | public async Task InitializeAsync() 52 | { 53 | _commandService.AddTypeReader(typeof(MiunieUser), new MiunieUserTypeReader(_convertor)); 54 | 55 | _discord.Client.MessageReceived += HandleCommandAsync; 56 | _discord.Client.MessageReceived += ProcessMessageAsync; 57 | _ = await _commandService.AddModulesAsync(Assembly.GetExecutingAssembly(), _services); 58 | } 59 | 60 | private Task ProcessMessageAsync(SocketMessage s) 61 | { 62 | if (s is SocketUserMessage msg) 63 | { 64 | var input = new CommandProcessorInput 65 | { 66 | Message = msg.Content, 67 | MessageId = msg.Id, 68 | ChannelId = msg.Channel.Id, 69 | GuildId = (msg.Author as SocketGuildUser)?.Guild.Id 70 | }; 71 | 72 | return _commandProcessor.ProcessAsync(input); 73 | } 74 | 75 | return Task.CompletedTask; 76 | } 77 | 78 | private async Task HandleCommandAsync(SocketMessage s) 79 | { 80 | if (_botConfig.CommandsEnabled == false) 81 | { 82 | return; 83 | } 84 | 85 | if (!(s is SocketUserMessage msg)) 86 | { 87 | return; 88 | } 89 | 90 | var argPos = 0; 91 | if (msg.HasMentionPrefix(_discord.Client.CurrentUser, ref argPos)) 92 | { 93 | var context = new SocketCommandContext(_discord.Client, msg); 94 | await TryRunAsBotCommand(context, argPos).ConfigureAwait(false); 95 | } 96 | } 97 | 98 | private async Task TryRunAsBotCommand(SocketCommandContext context, int argPos) 99 | { 100 | var result = await _commandService.ExecuteAsync(context, argPos, _services); 101 | 102 | if (!result.IsSuccess) 103 | { 104 | _logger.Log($"Command execution failed. Reason: {result.ErrorReason}."); 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/Miunie.Discord/CommandModules/MiscCommands.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.Commands; 17 | using Discord.WebSocket; 18 | using Miunie.Core; 19 | using Miunie.Discord.Convertors; 20 | using System.Threading.Tasks; 21 | 22 | namespace Miunie.Discord.CommandModules 23 | { 24 | public class MiscCommands : ModuleBase 25 | { 26 | private readonly MiscService _service; 27 | private readonly EntityConvertor _entityConvertor; 28 | 29 | public MiscCommands(MiscService service, EntityConvertor entityConvertor) 30 | { 31 | _service = service; 32 | _entityConvertor = entityConvertor; 33 | } 34 | 35 | [Command("what do you think?")] 36 | public async Task SendRandomYesNoMaybeAnswer() 37 | { 38 | var c = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 39 | await _service.SendRandomYesNoAnswerAsync(c); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Miunie.Discord/CommandModules/PrivacyCommand.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.Commands; 17 | using Discord.WebSocket; 18 | using Miunie.Core; 19 | using Miunie.Discord.Convertors; 20 | using System.Threading.Tasks; 21 | 22 | namespace Miunie.Discord.CommandModules 23 | { 24 | public class PrivacyCommand : ModuleBase 25 | { 26 | private readonly EntityConvertor _entityConvertor; 27 | private readonly PrivacyService _service; 28 | 29 | public PrivacyCommand(PrivacyService service, EntityConvertor entityConvertor) 30 | { 31 | _entityConvertor = entityConvertor; 32 | _service = service; 33 | } 34 | 35 | [Command("personal data")] 36 | public async Task GetMyPersonalData() 37 | { 38 | var u = _entityConvertor.ConvertUser(Context.User as SocketGuildUser); 39 | await _service.OutputUserJsonDataAsync(u); 40 | } 41 | 42 | [Command("personal data remove")] 43 | public async Task RemoveMyPersonalData() 44 | { 45 | var u = _entityConvertor.ConvertUser(Context.User as SocketGuildUser); 46 | var c = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 47 | await _service.RemoveUserData(u, c); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Miunie.Discord/CommandModules/ProfileCommand.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.Commands; 17 | using Discord.WebSocket; 18 | using Miunie.Core; 19 | using Miunie.Core.Entities.Discord; 20 | using Miunie.Discord.Convertors; 21 | using System.Threading.Tasks; 22 | 23 | namespace Miunie.Discord.CommandModules 24 | { 25 | public class ProfileCommand : ModuleBase 26 | { 27 | private readonly EntityConvertor _entityConvertor; 28 | private readonly ProfileService _profileService; 29 | 30 | public ProfileCommand(EntityConvertor entityConvertor, ProfileService profileService) 31 | { 32 | _entityConvertor = entityConvertor; 33 | _profileService = profileService; 34 | } 35 | 36 | [Command("profile")] 37 | public async Task ShowProfileAsync(MiunieUser user = null) 38 | { 39 | if (user is null) 40 | { 41 | user = _entityConvertor.ConvertUser(Context.User as SocketGuildUser); 42 | } 43 | 44 | var channel = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 45 | await _profileService.ShowProfileAsync(user, channel); 46 | } 47 | 48 | [Command("rep log")] 49 | public async Task ShowReputationLogAsync(int page = 1) 50 | { 51 | var source = _entityConvertor.ConvertUser(Context.User as SocketGuildUser); 52 | var channel = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 53 | await _profileService.ShowReputationLogAsync(source, page, channel); 54 | } 55 | 56 | [Command("rep log for")] 57 | public async Task ShowReputationLogAsync(MiunieUser user, int page = 1) 58 | { 59 | var channel = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 60 | await _profileService.ShowReputationLogAsync(user, page, channel); 61 | } 62 | 63 | [Command("+rep")] 64 | public async Task AddReputationAsync(MiunieUser user) 65 | { 66 | var source = _entityConvertor.ConvertUser(Context.User as SocketGuildUser); 67 | var channel = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 68 | await _profileService.GiveReputationAsync(source, user, channel); 69 | } 70 | 71 | [Command("-rep")] 72 | public async Task RemoveReputationAsync(MiunieUser user) 73 | { 74 | var source = _entityConvertor.ConvertUser(Context.User as SocketGuildUser); 75 | var channel = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 76 | await _profileService.RemoveReputationAsync(source, user, channel); 77 | } 78 | 79 | [Command("guild")] 80 | public async Task ShowGuildInfoAsync() 81 | { 82 | var guild = _entityConvertor.ConvertGuild(Context.Guild); 83 | var channel = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 84 | await _profileService.ShowGuildProfileAsync(guild, channel); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Miunie.Discord/CommandModules/RemoteRepositoryCommand.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.Commands; 17 | using Discord.WebSocket; 18 | using Miunie.Core; 19 | using Miunie.Discord.Convertors; 20 | using System.Threading.Tasks; 21 | 22 | namespace Miunie.Discord.CommandModules 23 | { 24 | public class RemoteRepositoryCommand : ModuleBase 25 | { 26 | private readonly RemoteRepositoryService _remoteRepoService; 27 | private readonly EntityConvertor _entityConvertor; 28 | 29 | public RemoteRepositoryCommand(RemoteRepositoryService remoteRepoService, EntityConvertor entityConvertor) 30 | { 31 | _remoteRepoService = remoteRepoService; 32 | _entityConvertor = entityConvertor; 33 | } 34 | 35 | [Command("repo")] 36 | [Summary("Shows the official remote repository hosting the code of this bot")] 37 | public async Task ShowRepository() 38 | { 39 | var channel = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 40 | await _remoteRepoService.ShowRepositoryAsync(channel); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Miunie.Discord/CommandModules/TimeCommand.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord; 17 | using Discord.Commands; 18 | using Discord.WebSocket; 19 | using Miunie.Core; 20 | using Miunie.Core.Entities.Discord; 21 | using Miunie.Discord.Convertors; 22 | using System; 23 | using System.Threading.Tasks; 24 | 25 | namespace Miunie.Discord.CommandModules 26 | { 27 | public class TimeCommand : ModuleBase 28 | { 29 | private readonly TimeService _service; 30 | private readonly EntityConvertor _entityConvertor; 31 | 32 | public TimeCommand(TimeService service, EntityConvertor entityConvertor) 33 | { 34 | _service = service; 35 | _entityConvertor = entityConvertor; 36 | } 37 | 38 | [Command("time for")] 39 | public async Task ShowTimeForUser(MiunieUser user) 40 | { 41 | var c = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 42 | await _service.OutputCurrentTimeForUserAsync(user, c); 43 | } 44 | 45 | [Command("time for")] 46 | public async Task ShowTimeForUserWithOffset(MiunieUser user, string verb, int units, string timeframe) 47 | { 48 | var c = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 49 | await _service.OutputFutureTimeForUserAsync(user, verb, units, timeframe, c); 50 | } 51 | 52 | [Command("time get")] 53 | public async Task ShowTimeForUserComparedToCurrentUser(DateTime requestTime, string verb, MiunieUser user) 54 | { 55 | var u = _entityConvertor.ConvertUser(Context.User as SocketGuildUser); 56 | var c = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 57 | await _service.OutputCurrentTimeComparedToInputForUserAsync(u, requestTime, verb, user, c); 58 | } 59 | 60 | [Command("time of")] 61 | public async Task ShowTimeForMessage(ulong messageId) 62 | { 63 | var m = await Context.Channel.GetMessageAsync(messageId); 64 | var ct = m?.CreatedAt; 65 | var et = m?.EditedTimestamp; 66 | var u = _entityConvertor.ConvertUser(Context.User as SocketGuildUser); 67 | var c = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 68 | await _service.OutputMessageTimeAsLocalAsync(messageId, ct, et, u, c); 69 | } 70 | 71 | [Command("time set")] 72 | public async Task SetMyTimeOffset(DateTime currentTime) 73 | { 74 | var u = _entityConvertor.ConvertUser(Context.User as SocketGuildUser); 75 | var c = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 76 | await _service.SetUtcOffsetForUserAsync(currentTime, u, c); 77 | } 78 | 79 | [RequireUserPermission(GuildPermission.Administrator)] 80 | [Command("time set for")] 81 | public async Task SetMyTimeOffset(MiunieUser user, DateTime currentTime) 82 | { 83 | var c = _entityConvertor.ConvertChannel(Context.Channel as SocketGuildChannel); 84 | await _service.SetUtcOffsetForUserByAdminAsync(currentTime, user, c); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Convertors/EntityConvertor.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.WebSocket; 17 | using Miunie.Core.Entities.Discord; 18 | using Miunie.Core.Providers; 19 | 20 | namespace Miunie.Discord.Convertors 21 | { 22 | public class EntityConvertor 23 | { 24 | public EntityConvertor(IMiunieUserProvider miunieUserProvider) 25 | { 26 | ChannelConvertor = new MiunieChannelConvertor(); 27 | UserConvertor = new MiunieUserConverter(miunieUserProvider); 28 | GuildConvertor = new MiunieGuildConvertor(); 29 | } 30 | 31 | public MiunieChannelConvertor ChannelConvertor { get; } 32 | 33 | public MiunieUserConverter UserConvertor { get; } 34 | 35 | public MiunieGuildConvertor GuildConvertor { get; } 36 | 37 | public MiunieUser ConvertUser(SocketGuildUser m) 38 | => UserConvertor.DiscordMemberToMiunieUser(m); 39 | 40 | public MiunieChannel ConvertChannel(SocketGuildChannel c) 41 | => MiunieChannelConvertor.FromDiscordChannel(c); 42 | 43 | internal MiunieGuild ConvertGuild(SocketGuild g) 44 | => GuildConvertor.DiscordGuildToMiunieGuild(g); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Convertors/MiunieChannelConvertor.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.WebSocket; 17 | using Miunie.Core.Entities.Discord; 18 | using System; 19 | 20 | namespace Miunie.Discord.Convertors 21 | { 22 | public class MiunieChannelConvertor 23 | { 24 | public static MiunieChannel FromDiscordChannel(SocketGuildChannel channel) 25 | { 26 | if (channel is null) 27 | { 28 | throw new ArgumentNullException(nameof(channel)); 29 | } 30 | 31 | MiunieChannel miunieChannel; 32 | if (channel is default(SocketGuildChannel)) 33 | { 34 | miunieChannel = default; 35 | } 36 | else 37 | { 38 | miunieChannel = new MiunieChannel() 39 | { 40 | ChannelId = channel.Id, 41 | GuildId = channel.Guild.Id 42 | }; 43 | } 44 | 45 | return miunieChannel; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Convertors/MiunieGuildConvertor.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.WebSocket; 17 | using Miunie.Core.Entities.Discord; 18 | using System; 19 | using System.Linq; 20 | 21 | namespace Miunie.Discord.Convertors 22 | { 23 | public class MiunieGuildConvertor 24 | { 25 | public MiunieGuild DiscordGuildToMiunieGuild(SocketGuild g) 26 | => g != null ? new MiunieGuild 27 | { 28 | Id = g.Id, 29 | Name = g.Name, 30 | MemberCount = g.MemberCount, 31 | ChannelNames = g.Channels.Select(x => x.Name), 32 | TextChannelCount = g.Channels.Count(x => x is SocketTextChannel), 33 | VoiceChannelCount = g.Channels.Count(x => x is SocketVoiceChannel), 34 | CreationDate = g.CreatedAt.UtcDateTime, 35 | Roles = g.Roles.Select(r => r.DiscordRoleToMiunieRole()), 36 | IconUrl = g.IconUrl 37 | } 38 | : throw new ArgumentNullException(nameof(g)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Convertors/MiunieRoleConvertor.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.WebSocket; 17 | using Miunie.Core.Entities.Discord; 18 | 19 | namespace Miunie.Discord.Convertors 20 | { 21 | public static class MiunieRoleConvertor 22 | { 23 | public static MiunieRole DiscordRoleToMiunieRole(this SocketRole role) 24 | => new MiunieRole 25 | { 26 | Id = role.Id, 27 | Name = role.Name 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Convertors/MiunieUserConverter.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.WebSocket; 17 | using Miunie.Core.Entities.Discord; 18 | using Miunie.Core.Providers; 19 | using System; 20 | using System.Linq; 21 | 22 | namespace Miunie.Discord.Convertors 23 | { 24 | public class MiunieUserConverter 25 | { 26 | private readonly IMiunieUserProvider _userProvider; 27 | 28 | public MiunieUserConverter(IMiunieUserProvider userProvider) 29 | { 30 | _userProvider = userProvider; 31 | } 32 | 33 | public MiunieUser DiscordMemberToMiunieUser(SocketGuildUser user) 34 | { 35 | if (user is null) 36 | { 37 | throw new ArgumentNullException(nameof(user)); 38 | } 39 | 40 | var mUser = _userProvider.GetById(user.Id, user.Guild.Id); 41 | mUser.Name = user.Nickname ?? user.Username; 42 | mUser.AvatarUrl = user.GetAvatarUrl(); 43 | mUser.JoinedAt = user.JoinedAt?.UtcDateTime ?? default; 44 | mUser.CreatedAt = user.CreatedAt.UtcDateTime; 45 | mUser.IsBot = user.IsBot; 46 | mUser.Roles = user.Roles.Select(r => r.DiscordRoleToMiunieRole()); 47 | _userProvider.StoreUser(mUser); 48 | return mUser; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Embeds/EmbedConstructor.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord; 17 | using Miunie.Core.Entities; 18 | using Miunie.Core.Entities.Discord; 19 | using Miunie.Core.Providers; 20 | using System; 21 | using System.Collections.Generic; 22 | using System.Linq; 23 | 24 | namespace Miunie.Discord.Embeds 25 | { 26 | internal static class EmbedConstructor 27 | { 28 | private static readonly int RepLogPageSize = 10; 29 | 30 | public static Embed CreateReputationLog(IEnumerable entries, int index, ILanguageProvider lang) 31 | { 32 | var embed = Paginator.PaginateEmbed( 33 | entries, 34 | new EmbedBuilder() 35 | .WithColor(new Color(236, 64, 122)) 36 | .WithTitle(lang.GetPhrase(PhraseKey.USER_EMBED_REP_LOG_TITLE.ToString())), 37 | index, 38 | RepLogPageSize, 39 | x => $"{(x.IsFromInvoker ? "**To:**" : "**From:**")} {x.TargetName} (**{FormatReputationType(x.Type)}**) {x.GivenAt:d} at {x.GivenAt:t} UTC"); 40 | 41 | if (string.IsNullOrWhiteSpace(embed.Description)) 42 | { 43 | _ = embed.WithDescription(lang.GetPhrase(PhraseKey.USER_EMBED_REP_LOG_EMPTY.ToString())); 44 | } 45 | 46 | return embed.Build(); 47 | } 48 | 49 | public static Embed ToEmbed(this MiunieUser mUser, ILanguageProvider lang) 50 | { 51 | var realnessPhrase = lang.GetPhrase((mUser.IsBot ? PhraseKey.USER_EMBED_IS_BOT : PhraseKey.USER_EMBED_IS_HUMAN).ToString()); 52 | 53 | return new EmbedBuilder() 54 | .WithColor(new Color(236, 64, 122)) 55 | .WithTitle(lang.GetPhrase(PhraseKey.USER_EMBED_TITLE.ToString(), mUser.Name.ToUpper().ToPossessiveForm())) 56 | .WithThumbnailUrl(mUser.AvatarUrl) 57 | .AddField(lang.GetPhrase(PhraseKey.USER_EMBED_NAME_TITLE.ToString()), mUser.Name) 58 | .AddField(lang.GetPhrase(PhraseKey.USER_EMBED_REALNESS_TITLE.ToString()), realnessPhrase, true) 59 | .AddField(lang.GetPhrase(PhraseKey.USER_EMBED_REP_TITLE.ToString()), mUser.Reputation.Value.ToString(), true) 60 | .AddField(lang.GetPhrase(PhraseKey.USER_EMBED_ROLES_TITLE.ToString()), string.Join("\n", mUser.Roles.Select(r => r.Name)), true) 61 | .AddField(lang.GetPhrase(PhraseKey.USER_EMBED_JOINED_AT_TITLE.ToString()), $"{mUser.JoinedAt:d} at {mUser.JoinedAt:t} UTC") 62 | .AddField(lang.GetPhrase(PhraseKey.USER_EMBED_CREATED_AT_TITLE.ToString()), $"{mUser.CreatedAt:d} at {mUser.CreatedAt:t} UTC", true) 63 | .AddField(lang.GetPhrase(PhraseKey.USER_EMBED_TIME_TITLE.ToString()), mUser.UtcTimeOffset.HasValue ? lang.GetPhrase(PhraseKey.USER_EMBED_TIME.ToString(), DateTime.UtcNow + mUser.UtcTimeOffset) : lang.GetPhrase(PhraseKey.USER_EMBED_TIME_NOSET.ToString()), true) 64 | .Build(); 65 | } 66 | 67 | public static Embed ToEmbed(this MiunieGuild mGuild, ILanguageProvider lang) 68 | => new EmbedBuilder() 69 | .WithColor(new Color(236, 64, 122)) 70 | .WithThumbnailUrl(mGuild.IconUrl) 71 | .WithTitle(lang.GetPhrase(PhraseKey.GUILD_EMBED_TITLE.ToString())) 72 | .AddField(lang.GetPhrase(PhraseKey.GUILD_EMBED_NAME_TITLE.ToString()), mGuild.Name) 73 | .AddField(lang.GetPhrase(PhraseKey.GUILD_EMBED_STATS_TITLE.ToString()), mGuild.GetStats(), true) 74 | .AddField(lang.GetPhrase(PhraseKey.GUILD_EMBED_ROLES_TITLE.ToString()), string.Join(", ", mGuild.Roles.Select(r => r.Name.Replace("@", string.Empty))), true) 75 | .AddField(lang.GetPhrase(PhraseKey.GUILD_EMBED_CREATED_AT_TITLE.ToString()), $"{mGuild.CreationDate:d} at {mGuild.CreationDate:t} UTC") 76 | .Build(); 77 | 78 | private static string ToPossessiveForm(this string s) 79 | => s.Last() == 'S' 80 | ? s + "'" 81 | : s + "'S"; 82 | 83 | private static string FormatReputationType(ReputationType type) 84 | { 85 | switch (type) 86 | { 87 | case ReputationType.Plus: 88 | return "+1"; 89 | case ReputationType.Minus: 90 | return "-1"; 91 | default: 92 | throw new ArgumentException("Unknown ReputationType."); 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Embeds/Paginator.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord; 17 | using System; 18 | using System.Collections.Generic; 19 | using System.Linq; 20 | using System.Text; 21 | 22 | namespace Miunie.Discord.Embeds 23 | { 24 | internal static class Paginator 25 | { 26 | public static IEnumerable GroupAt(IEnumerable set, int index, int pageSize, bool defaultOnOverflow = false) 27 | { 28 | int maxPages = GetPageCount(set.Count(), pageSize); 29 | if (index < 0 || index >= maxPages) 30 | { 31 | return set; 32 | } 33 | 34 | var remainder = set.Skip(pageSize * (index - 1)); 35 | 36 | List group = new List(); 37 | for (int i = 0; i < pageSize; i++) 38 | { 39 | if (defaultOnOverflow) 40 | { 41 | group.Add(remainder.ElementAtOrDefault(i)); 42 | } 43 | else 44 | { 45 | if (remainder.Count() - 1 < i) 46 | { 47 | continue; 48 | } 49 | else 50 | { 51 | group.Add(remainder.ElementAt(i)); 52 | } 53 | } 54 | } 55 | 56 | return group; 57 | } 58 | 59 | public static EmbedBuilder PaginateEmbed(IEnumerable set, EmbedBuilder embed, int index, int pageSize) 60 | { 61 | return embed.WithDescription(Paginate(set, index, pageSize)) 62 | .WithFooter($"{(string.IsNullOrWhiteSpace(embed.Footer?.Text) ? string.Empty : $"{embed.Footer?.Text} | ")}{GetPageFooter(index, set.Count(), pageSize)}"); 63 | } 64 | 65 | public static EmbedBuilder PaginateEmbed(IEnumerable set, EmbedBuilder embed, int index, int pageSize, Func writer) 66 | { 67 | return embed.WithDescription(Paginate(set, index, pageSize, writer)) 68 | .WithFooter($"{(string.IsNullOrWhiteSpace(embed.Footer?.Text) ? string.Empty : $"{embed.Footer?.Text} | ")}{GetPageFooter(index, set.Count(), pageSize)}"); 69 | } 70 | 71 | public static string Paginate(IEnumerable set, int index, int pageSize) 72 | { 73 | var group = GroupAt(set, index, pageSize); 74 | StringBuilder page = new StringBuilder(); 75 | 76 | foreach (T item in group) 77 | { 78 | _ = page.AppendLine(item.ToString()); 79 | } 80 | 81 | return page.ToString(); 82 | } 83 | 84 | public static string Paginate(IEnumerable set, int index, int pageSize, Func writer) 85 | { 86 | var group = GroupAt(set, index, pageSize); 87 | StringBuilder page = new StringBuilder(); 88 | 89 | foreach (T item in group) 90 | { 91 | _ = page.AppendLine(writer.Invoke(item)); 92 | } 93 | 94 | return page.ToString(); 95 | } 96 | 97 | private static string GetPageFooter(int index, int collectionSize, int pageSize) 98 | { 99 | return $"Page {index + 1} of {GetPageCount(collectionSize, pageSize)}"; 100 | } 101 | 102 | private static int GetPageCount(int collectionSize, int pageSize) 103 | { 104 | return (int)Math.Ceiling((double)collectionSize / pageSize); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Miunie.Discord/IDiscord.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord.WebSocket; 17 | using System.Threading.Tasks; 18 | 19 | namespace Miunie.Discord 20 | { 21 | public interface IDiscord 22 | { 23 | DiscordSocketClient Client { get; } 24 | 25 | Task InitializeAsync(); 26 | 27 | void DisposeOfClient(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Impersonation.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord; 17 | using Discord.WebSocket; 18 | using Miunie.Core.Discord; 19 | using Miunie.Core.Entities.Views; 20 | using Miunie.Core.Events; 21 | using Miunie.Core.Logging; 22 | using System; 23 | using System.Collections.Generic; 24 | using System.Linq; 25 | using System.Threading.Tasks; 26 | 27 | namespace Miunie.Discord 28 | { 29 | public class Impersonation : IDiscordImpersonation 30 | { 31 | private readonly IDiscord _discord; 32 | private readonly ILogWriter _logger; 33 | 34 | public Impersonation(IDiscord discord, ILogWriter logger) 35 | { 36 | _discord = discord; 37 | _logger = logger; 38 | } 39 | 40 | public event EventHandler MessageReceived; 41 | 42 | public IEnumerable GetAvailableGuilds() 43 | => _discord.Client?.Guilds.Select(g => new GuildView 44 | { 45 | Id = g.Id, 46 | IconUrl = g.IconUrl, 47 | Name = g.Name 48 | }); 49 | 50 | public Task> GetAvailableTextChannelsAsync(ulong guildId) 51 | { 52 | if (guildId == 0) { return CompletedTextChannelViewTask(new TextChannelView[0]); } 53 | 54 | var guild = _discord.Client.GetGuild(guildId); 55 | var textChannels = guild.Channels 56 | .Where(IsViewableTextChannel) 57 | .Cast() 58 | .Select(ToTextChannelView); 59 | 60 | return CompletedTextChannelViewTask(textChannels); 61 | } 62 | 63 | public async Task> GetMessagesFromTextChannelAsync(ulong guildId, ulong channelId) 64 | { 65 | if (guildId == 0) { return new MessageView[0]; } 66 | 67 | var guild = _discord.Client.GetGuild(guildId); 68 | var textChannel = guild.Channels 69 | .Where(c => c.Id == channelId && IsViewableTextChannel(c)) 70 | .Cast() 71 | .FirstOrDefault(); 72 | 73 | if (textChannel == null) { return new MessageView[0]; } 74 | 75 | var result = new List(); 76 | 77 | try 78 | { 79 | result.AddRange(await GetMessagesFrom(textChannel)); 80 | } 81 | catch (Exception ex) 82 | { 83 | _logger.Log($"Miunie cannot read from the '{textChannel.Name}' channel. {ex.Message}"); 84 | } 85 | 86 | return result; 87 | } 88 | 89 | public async Task SendTextToChannelAsync(string text, ulong id) 90 | { 91 | if (string.IsNullOrWhiteSpace(text)) { return; } 92 | var textChannel = _discord.Client.GetChannel(id) as SocketTextChannel; 93 | if (textChannel is null) { return; } 94 | 95 | _ = await textChannel.SendMessageAsync(text); 96 | } 97 | 98 | public void SubscribeForMessages() 99 | { 100 | _discord.Client.MessageReceived += Client_MessageReceivedHandler; 101 | } 102 | 103 | public void UnsubscribeForMessages() 104 | { 105 | _discord.Client.MessageReceived -= Client_MessageReceivedHandler; 106 | } 107 | 108 | private Task> CompletedTextChannelViewTask(IEnumerable channels) 109 | => Task.FromResult(channels); 110 | 111 | private TextChannelView ToTextChannelView(SocketTextChannel channel) 112 | => new TextChannelView 113 | { 114 | Id = channel.Id, 115 | Name = $"# {channel.Name}", 116 | Messages = new MessageView[0], 117 | CanSendMessages = CanSendMessagesTo(channel) 118 | }; 119 | 120 | private bool CanSendMessagesTo(SocketTextChannel channel) 121 | => channel.GetUser(_discord.Client.CurrentUser.Id)?.GetPermissions(channel).SendMessages ?? false; 122 | 123 | private bool IsViewableTextChannel(SocketGuildChannel c) 124 | { 125 | if (!(c is SocketTextChannel)) { return false; } 126 | 127 | return c.GetUser(_discord.Client.CurrentUser.Id) != null; 128 | } 129 | 130 | private Task Client_MessageReceivedHandler(SocketMessage m) 131 | { 132 | MessageReceived?.Invoke(this, new MessageReceivedEventArgs(ToMessageView(m))); 133 | 134 | return Task.CompletedTask; 135 | } 136 | 137 | private async Task> GetMessagesFrom(SocketTextChannel channel) 138 | { 139 | var socketMessages = await channel.GetMessagesAsync(10).FlattenAsync(); 140 | 141 | return socketMessages.Select(ToMessageView); 142 | } 143 | 144 | private MessageView ToMessageView(IMessage message) => new MessageView 145 | { 146 | ChannelId = message.Channel.Id, 147 | AuthorAvatarUrl = message.Author.GetAvatarUrl(), 148 | AuthorName = message.Author.Username, 149 | Content = message.Content, 150 | TimeStamp = message.CreatedAt.ToLocalTime() 151 | }; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Logging/DiscordLogger.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord; 17 | using Miunie.Core.Logging; 18 | using System.Threading.Tasks; 19 | 20 | namespace Miunie.Discord.Logging 21 | { 22 | public class DiscordLogger 23 | { 24 | private readonly ILogWriter _logger; 25 | 26 | public DiscordLogger(ILogWriter logger) 27 | { 28 | _logger = logger; 29 | } 30 | 31 | internal Task Log(LogMessage evt) 32 | { 33 | if (evt.Severity == LogSeverity.Critical) 34 | { 35 | _logger.LogError(evt.Message); 36 | } 37 | else 38 | { 39 | _logger.Log(evt.Message); 40 | } 41 | 42 | return Task.CompletedTask; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Miunie.Discord/Miunie.Discord.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | GPL-3.0 6 | LICENSE 7 | https://github.com/control-net/Miunie 8 | https://github.com/control-net/Miunie 9 | git 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | True 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Miunie.Discord/MiunieDiscord.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord; 17 | using Miunie.Core.Discord; 18 | using Miunie.Core.Entities.Discord; 19 | using Miunie.Core.Logging; 20 | using Miunie.Discord.Logging; 21 | using System; 22 | using System.Threading; 23 | using System.Threading.Tasks; 24 | 25 | namespace Miunie.Discord 26 | { 27 | public class MiunieDiscord : IDiscordConnection 28 | { 29 | private readonly IDiscord _discord; 30 | private readonly DiscordLogger _discordLogger; 31 | private readonly ILogWriter _logger; 32 | private readonly CommandHandler _commandHandler; 33 | private Core.Entities.ConnectionState _connectionState; 34 | 35 | public MiunieDiscord(IDiscord discord, DiscordLogger discordLogger, ILogWriter logger, CommandHandler commandHandler) 36 | { 37 | _discord = discord; 38 | _discordLogger = discordLogger; 39 | _logger = logger; 40 | _commandHandler = commandHandler; 41 | 42 | _connectionState = Core.Entities.ConnectionState.DISCONNECTED; 43 | } 44 | 45 | public event EventHandler ConnectionChanged; 46 | 47 | public Core.Entities.ConnectionState ConnectionState 48 | { 49 | get => _connectionState; 50 | private set 51 | { 52 | _connectionState = value; 53 | ConnectionChanged?.Invoke(this, EventArgs.Empty); 54 | } 55 | } 56 | 57 | public bool UserIsMiunie(MiunieUser user) 58 | => user.UserId == _discord.Client?.CurrentUser?.Id; 59 | 60 | public string GetBotAvatarUrl() 61 | => _discord.Client?.CurrentUser?.GetAvatarUrl(); 62 | 63 | public async Task RunAsync(CancellationToken cancellationToken) 64 | { 65 | ConnectionState = Core.Entities.ConnectionState.CONNECTING; 66 | 67 | try 68 | { 69 | await _discord.InitializeAsync(); 70 | _discord.Client.Log += _discordLogger.Log; 71 | _discord.Client.Ready += ClientOnReady; 72 | await _commandHandler.InitializeAsync(); 73 | await _discord.Client.StartAsync(); 74 | await Task.Delay(-1, cancellationToken); 75 | } 76 | catch (Exception ex) 77 | { 78 | if (_discord.Client != null) 79 | { 80 | await _discord.Client.LogoutAsync(); 81 | _discord.DisposeOfClient(); 82 | } 83 | 84 | _logger.LogError(ex.Message); 85 | } 86 | finally 87 | { 88 | ConnectionState = Core.Entities.ConnectionState.DISCONNECTED; 89 | } 90 | } 91 | 92 | private Task ClientOnReady() 93 | { 94 | _logger.Log("Client Ready"); 95 | #if DEBUG 96 | _discord.Client.SetGameAsync("Herself being created.", type: ActivityType.Watching); 97 | #endif 98 | ConnectionState = Core.Entities.ConnectionState.CONNECTED; 99 | return Task.CompletedTask; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/Miunie.Discord/MiunieDiscordClient.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord; 17 | using Discord.WebSocket; 18 | using Miunie.Core.Configuration; 19 | using System; 20 | using System.Threading.Tasks; 21 | 22 | namespace Miunie.Discord 23 | { 24 | public class MiunieDiscordClient : IDiscord 25 | { 26 | private readonly IBotConfiguration _botConfig; 27 | 28 | public MiunieDiscordClient(IBotConfiguration botConfig) 29 | { 30 | _botConfig = botConfig; 31 | } 32 | 33 | public DiscordSocketClient Client { get; private set; } 34 | 35 | public async Task InitializeAsync() 36 | { 37 | if (string.IsNullOrWhiteSpace(_botConfig.DiscordToken)) 38 | { 39 | throw new ArgumentNullException(nameof(_botConfig.DiscordToken)); 40 | } 41 | 42 | Client = new DiscordSocketClient(new DiscordSocketConfig 43 | { 44 | LogLevel = LogSeverity.Info, 45 | }); 46 | 47 | await Client.LoginAsync(TokenType.Bot, _botConfig.DiscordToken); 48 | } 49 | 50 | public void DisposeOfClient() => Client = null; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Miunie.Discord/TypeReaders/MiunieUserTypeReader.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Discord; 17 | using Discord.Commands; 18 | using Discord.WebSocket; 19 | using Miunie.Discord.Convertors; 20 | using System; 21 | using System.Threading.Tasks; 22 | 23 | namespace Miunie.Discord.TypeReaders 24 | { 25 | public class MiunieUserTypeReader : TypeReader 26 | { 27 | private readonly EntityConvertor _convertor; 28 | 29 | public MiunieUserTypeReader(EntityConvertor convertor) 30 | { 31 | _convertor = convertor; 32 | } 33 | 34 | public override async Task ReadAsync(ICommandContext context, string input, IServiceProvider services) 35 | { 36 | var discordUserId = MentionUtils.TryParseUser(input, out var userId); 37 | 38 | if (await context.Guild.GetUserAsync(userId) is SocketGuildUser discordUser) 39 | { 40 | var miunieUserResult = _convertor.UserConvertor.DiscordMemberToMiunieUser(discordUser); 41 | return TypeReaderResult.FromSuccess(miunieUserResult); 42 | } 43 | 44 | return TypeReaderResult.FromError(CommandError.ParseFailed, "Input could not be parsed as a MiunieUser."); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Miunie.Infrastructure/Json/JsonConverter.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Json; 17 | using Newtonsoft.Json; 18 | 19 | namespace Miunie.Infrastructure.Json 20 | { 21 | public class JsonConverter : IJsonConverter 22 | { 23 | public string Serialize(T obj) 24 | { 25 | return JsonConvert.SerializeObject(obj); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Miunie.Infrastructure/LiteDbStorage/PersistentStorage.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using LiteDB; 17 | using Miunie.Core.Infrastructure; 18 | using Miunie.Core.Storage; 19 | using System; 20 | using System.Collections.Generic; 21 | using System.IO; 22 | using System.Linq; 23 | using System.Linq.Expressions; 24 | 25 | namespace Miunie.Infrastructure.LiteDbStorage 26 | { 27 | public class PersistentStorage : IPersistentStorage 28 | { 29 | private readonly string _dbFileName; 30 | 31 | public PersistentStorage(IFileSystem fileSystem) 32 | { 33 | _dbFileName = Path.Combine(fileSystem.DataStoragePath, "Miunie.db"); 34 | } 35 | 36 | public IEnumerable RestoreMany(Expression> predicate) 37 | { 38 | using var db = new LiteDatabase(_dbFileName); 39 | var collection = db.GetCollection(); 40 | return collection.Find(predicate); 41 | } 42 | 43 | public IEnumerable RestoreAll() 44 | { 45 | using var db = new LiteDatabase(_dbFileName); 46 | var collection = db.GetCollection(); 47 | return collection.FindAll(); 48 | } 49 | 50 | public T RestoreSingle(Expression> predicate) 51 | => RestoreMany(predicate).FirstOrDefault(); 52 | 53 | public bool Exists(Expression> predicate) 54 | { 55 | using var db = new LiteDatabase(_dbFileName); 56 | var collection = db.GetCollection(); 57 | return collection.Exists(predicate); 58 | } 59 | 60 | public void Store(T item) 61 | { 62 | using var db = new LiteDatabase(_dbFileName); 63 | var collection = db.GetCollection(); 64 | _ = collection.Insert(item); 65 | } 66 | 67 | public void Update(T item) 68 | { 69 | using var db = new LiteDatabase(_dbFileName); 70 | var collection = db.GetCollection(); 71 | _ = collection.Update(item); 72 | } 73 | 74 | public void Remove(Expression> predicate) 75 | { 76 | using var db = new LiteDatabase(_dbFileName); 77 | var collection = db.GetCollection(); 78 | _ = collection.Delete(predicate); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Miunie.Infrastructure/Logging/ConsoleLogger.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Logging; 17 | using System; 18 | 19 | namespace Miunie.Infrastructure.Logging 20 | { 21 | public class ConsoleLogger : ILogWriter 22 | { 23 | public void Log(string message) 24 | { 25 | Console.WriteLine($"{DateTime.Now:G} - {message}"); 26 | } 27 | 28 | public void LogError(string message) 29 | { 30 | Console.ForegroundColor = ConsoleColor.Red; 31 | Console.WriteLine($"{DateTime.Now:G} - {message}"); 32 | Console.ResetColor(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Miunie.Infrastructure/Logging/InMemoryLogger.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Logging; 17 | using System; 18 | using System.Collections.Generic; 19 | 20 | namespace Miunie.Infrastructure.Logging 21 | { 22 | public class InMemoryLogger : ILogWriter, ILogReader 23 | { 24 | public event EventHandler LogRecieved; 25 | 26 | public List Logs { get; private set; } = new List(); 27 | 28 | public void Log(string message) 29 | { 30 | Logs.Add(message); 31 | LogRecieved?.Invoke(this, EventArgs.Empty); 32 | } 33 | 34 | public void LogError(string message) => Log($"ERROR: {message}"); 35 | 36 | public IEnumerable RetrieveLogs(int ammount = 5) 37 | { 38 | if (Logs.Count < ammount) 39 | { 40 | return Logs; 41 | } 42 | 43 | return Logs.GetRange(Logs.Count - ammount, ammount); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Miunie.Infrastructure/Miunie.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | netstandard2.0 9 | GPL-3.0 10 | LICENSE 11 | https://github.com/control-net/Miunie 12 | https://github.com/control-net/Miunie 13 | git 14 | 15 | 16 | 17 | 18 | True 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Miunie.Infrastructure/OS/SystemDateTime.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Infrastructure; 17 | using System; 18 | 19 | namespace Miunie.Infrastructure.OS 20 | { 21 | public class SystemDateTime : IDateTime 22 | { 23 | public DateTime UtcNow => DateTime.UtcNow; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Miunie.Infrastructure/OS/SystemFileSystem.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Infrastructure; 17 | using System.IO; 18 | using System.Reflection; 19 | 20 | namespace Miunie.Infrastructure.OS 21 | { 22 | public class SystemFileSystem : IFileSystem 23 | { 24 | public SystemFileSystem() 25 | { 26 | DataStoragePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); 27 | } 28 | 29 | public string DataStoragePath { get; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Miunie.InversionOfControl/Container.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Microsoft.Extensions.DependencyInjection; 17 | using Miunie.Core.Attributes; 18 | using Miunie.Core.Commands; 19 | using Miunie.Core.Configuration; 20 | using Miunie.Core.Discord; 21 | using Miunie.Core.Entities; 22 | using Miunie.Core.Json; 23 | using Miunie.Core.Providers; 24 | using Miunie.Core.Storage; 25 | using Miunie.Discord; 26 | using Miunie.Discord.Adapters; 27 | using Miunie.Discord.Convertors; 28 | using Miunie.Discord.Logging; 29 | using Miunie.Infrastructure.Json; 30 | using Miunie.Infrastructure.LiteDbStorage; 31 | using System; 32 | using System.Linq; 33 | using System.Reflection; 34 | 35 | namespace Miunie.InversionOfControl 36 | { 37 | public static class Container 38 | { 39 | public static IServiceCollection AddMiunieTypes(this IServiceCollection collection) 40 | => collection.AddSingleton() 41 | .AddScoped() 42 | .AddSingleton() 43 | .AddSingleton() 44 | .AddScoped() 45 | .AddScoped() 46 | .AddSingleton() 47 | .AddSingleton() 48 | .AddSingleton() 49 | .AddSingleton() 50 | .AddSingleton() 51 | .AddSingleton() 52 | .AddSingleton() 53 | .AddScoped() 54 | .AddSingleton() 55 | .AddSingleton() 56 | .AddSingleton() 57 | .AddSingleton() 58 | .AddMiunieServices(); 59 | 60 | private static IServiceCollection AddMiunieServices(this IServiceCollection collection) 61 | { 62 | var serviceAttributeType = typeof(ServiceAttribute); 63 | var serviceTypes = Assembly.GetAssembly(serviceAttributeType) 64 | .GetTypes() 65 | .Where(x => x.GetCustomAttributes(serviceAttributeType, true).Length > 0).ToList(); 66 | 67 | serviceTypes.ForEach((x) => 68 | { 69 | var attribute = x.GetCustomAttribute(serviceAttributeType) as ServiceAttribute; 70 | switch (attribute.ServiceType) 71 | { 72 | case ServiceType.SCOPED: 73 | _ = collection.AddScoped(x); 74 | break; 75 | case ServiceType.SINGLETON: 76 | _ = collection.AddSingleton(x); 77 | break; 78 | case ServiceType.TRANSIENT: 79 | _ = collection.AddTransient(x); 80 | break; 81 | default: 82 | break; 83 | } 84 | }); 85 | 86 | return collection; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Miunie.InversionOfControl/Miunie.InversionOfControl.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | GPL-3.0 6 | LICENSE 7 | https://github.com/control-net/Miunie 8 | https://github.com/control-net/Miunie 9 | git 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | True 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Miunie.Tests/Commands/MessagePreconditonTests.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Commands; 17 | using Miunie.Core.Commands.PipelineSteps; 18 | using Miunie.Core.Configuration; 19 | using Moq; 20 | using System.Threading.Tasks; 21 | using Xunit; 22 | 23 | namespace Miunie.Tests.Commands 24 | { 25 | public class MessagePreconditonTests 26 | { 27 | [Fact] 28 | public async Task MessageWithNoPrefixIsIgnored() 29 | { 30 | var botConfig = CreateBotConfigWithPrefix("MyPrefix"); 31 | var input = CreateInputWithMessage("Message without a prefix"); 32 | var nextStep = new Mock(); 33 | var step = new PreconditionCheckStep(nextStep.Object, botConfig); 34 | 35 | await step.ProcessAsync(input); 36 | 37 | AssertNextStepIsNotCalled(nextStep); 38 | } 39 | 40 | [Fact] 41 | public async Task MessageWithPrefixCallsNextStep() 42 | { 43 | const uint ExpectedPrefixOffset = 8; 44 | var botConfig = CreateBotConfigWithPrefix("MyPrefix"); 45 | var input = CreateInputWithMessage("MyPrefix Message with a prefix"); 46 | var nextStep = new Mock(); 47 | var step = new PreconditionCheckStep(nextStep.Object, botConfig); 48 | 49 | await step.ProcessAsync(input); 50 | 51 | AssertNextStepIsCalled(nextStep); 52 | Assert.Equal(ExpectedPrefixOffset, input.PrefixOffset); 53 | } 54 | 55 | [Fact] 56 | public async Task NoPrefixSetIgnoreAllMessages() 57 | { 58 | const uint ExpectedPrefixOffset = 0; 59 | var botConfig = CreateBotConfigWithNoPrefix(); 60 | var input = CreateInputWithMessage("Any Message"); 61 | var nextStep = new Mock(); 62 | var step = new PreconditionCheckStep(nextStep.Object, botConfig); 63 | 64 | await step.ProcessAsync(input); 65 | 66 | AssertNextStepIsCalled(nextStep); 67 | Assert.Equal(ExpectedPrefixOffset, input.PrefixOffset); 68 | } 69 | 70 | private void AssertNextStepIsNotCalled(Mock step) 71 | => step.Verify(s => s.ProcessAsync(It.IsAny()), Times.Never()); 72 | 73 | private void AssertNextStepIsCalled(Mock step) 74 | => step.Verify(s => s.ProcessAsync(It.IsAny()), Times.Once()); 75 | 76 | private IBotConfiguration CreateBotConfigWithPrefix(string prefix) 77 | => new BotConfiguration 78 | { 79 | CommandPrefix = prefix 80 | }; 81 | 82 | private IBotConfiguration CreateBotConfigWithNoPrefix() 83 | => new BotConfiguration 84 | { 85 | CommandPrefix = string.Empty 86 | }; 87 | 88 | private CommandProcessorInput CreateInputWithMessage(string message) 89 | => new CommandProcessorInput 90 | { 91 | Message = message 92 | }; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Miunie.Tests/Data/DummyMiunieUsers.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities; 17 | using Miunie.Core.Entities.Discord; 18 | using System; 19 | 20 | namespace Miunie.Core.XUnit.Tests.Data 21 | { 22 | public class DummyMiunieUsers 23 | { 24 | public static readonly ulong DummyGuildId = 420; 25 | 26 | public MiunieUser Senne { get; private set; } = new MiunieUser 27 | { 28 | UserId = 69420911, 29 | GuildId = DummyGuildId, 30 | Name = "Senne", 31 | Reputation = new Reputation 32 | { 33 | Value = 55 34 | } 35 | }; 36 | 37 | public MiunieUser Peter { get; private set; } = new MiunieUser 38 | { 39 | UserId = 182941761801420802, 40 | GuildId = DummyGuildId, 41 | Name = "Peter", 42 | Reputation = new Reputation 43 | { 44 | Value = 100 45 | } 46 | }; 47 | 48 | public MiunieUser Drax { get; private set; } = new MiunieUser 49 | { 50 | UserId = 123456789, 51 | GuildId = DummyGuildId, 52 | Name = "Drax", 53 | Reputation = new Reputation 54 | { 55 | Value = -1 56 | } 57 | }; 58 | 59 | public MiunieUser DraxWithUtcTimeOffSet { get; private set; } = new MiunieUser 60 | { 61 | UserId = 123456789, 62 | GuildId = DummyGuildId, 63 | Name = "Drax", 64 | UtcTimeOffset = new TimeSpan(0, 0, 0) 65 | }; 66 | 67 | public MiunieUser PeterWithNoTimeSet { get; private set; } = new MiunieUser 68 | { 69 | UserId = 182941761801420802, 70 | GuildId = DummyGuildId, 71 | Name = "Peter" 72 | }; 73 | 74 | public MiunieUser PeterWithUtcPlusOneHourTimeSet { get; private set; } = new MiunieUser 75 | { 76 | UserId = 123456789, 77 | GuildId = DummyGuildId, 78 | Name = "Drax", 79 | UtcTimeOffset = new TimeSpan(1, 0, 0) 80 | }; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Miunie.Tests/Miunie.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | false 6 | GPL-3.0 7 | LICENSE 8 | https://github.com/control-net/Miunie 9 | https://github.com/control-net/Miunie 10 | git 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | True 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/Miunie.Tests/MiunieDiscordClientTests.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Configuration; 17 | using Miunie.Discord; 18 | using System; 19 | using Xunit; 20 | 21 | namespace Miunie.Core.XUnit.Tests 22 | { 23 | public class MiunieDiscordClientTests 24 | { 25 | [Theory] 26 | [InlineData(null)] 27 | [InlineData("")] 28 | [InlineData(" ")] 29 | public void Initialize_ShouldThrowArgumentNullException_IfInvalidToken(string token) 30 | { 31 | IBotConfiguration config = new BotConfiguration 32 | { 33 | DiscordToken = token, 34 | CommandsEnabled = true 35 | }; 36 | var client = new MiunieDiscordClient(config); 37 | 38 | _ = Assert.ThrowsAsync(client.InitializeAsync); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Miunie.Tests/MiunieDiscordTests.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Configuration; 17 | using Miunie.Discord; 18 | using Moq; 19 | using System.Threading; 20 | using System.Threading.Tasks; 21 | using Xunit; 22 | 23 | namespace Miunie.Core.XUnit.Tests 24 | { 25 | public class MiunieDiscordTests 26 | { 27 | [Fact] 28 | public async Task RunAsync_ShouldThrowException_IfInvalidToken() 29 | { 30 | var config = Mock.Of(c => c.DiscordToken == "ObviouslyFakeToken"); 31 | var discord = new Mock(config); 32 | 33 | var miunie = new MiunieDiscord(discord.Object, null, null, null); 34 | 35 | var ex = await Record.ExceptionAsync(async () => await miunie.RunAsync(CancellationToken.None)); 36 | 37 | Assert.NotNull(ex); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Miunie.Tests/Providers/MiunieUserProviderTests.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Entities; 17 | using Miunie.Core.Entities.Discord; 18 | using Miunie.Core.Providers; 19 | using Miunie.Core.Storage; 20 | using Miunie.Core.XUnit.Tests.Data; 21 | using Moq; 22 | using System; 23 | using System.Linq.Expressions; 24 | using Xunit; 25 | 26 | namespace Miunie.Core.XUnit.Tests.Providers 27 | { 28 | public class MiunieUserProviderTests 29 | { 30 | private readonly Mock _storageMock; 31 | private readonly MiunieUserProvider _userProvider; 32 | private readonly DummyMiunieUsers _users; 33 | private readonly Expression> _hasDraxIdAndGuildId; 34 | 35 | public MiunieUserProviderTests() 36 | { 37 | _storageMock = new Mock(); 38 | _userProvider = new MiunieUserProvider(_storageMock.Object); 39 | _users = new DummyMiunieUsers(); 40 | _hasDraxIdAndGuildId = u => u.UserId == _users.Drax.UserId && u.GuildId == _users.Drax.GuildId; 41 | } 42 | 43 | [Fact] 44 | public void GetById_ShouldFindAndReturnExpectedUser_IfUserFound() 45 | { 46 | var expected = _users.Drax; 47 | _ = _storageMock.Setup(s => s.RestoreSingle(It.IsAny>>())) 48 | .Returns(expected); 49 | _ = _storageMock.Setup(s => s.Store(It.IsAny())); 50 | 51 | var actual = _userProvider.GetById(expected.UserId, expected.GuildId); 52 | 53 | _storageMock.Verify(s => s.RestoreSingle(It.IsAny>>()), Times.Once); 54 | _storageMock.Verify(s => s.Store(It.Is(_hasDraxIdAndGuildId)), Times.Never); 55 | Assert.True(expected.UserId == actual.UserId && expected.GuildId == actual.GuildId); 56 | } 57 | 58 | [Theory] 59 | [InlineData(0, 0)] 60 | [InlineData(1234, 4321)] 61 | public void GetById_ShouldStoreAndReturnNewUser_IfUserNotFound(ulong userId, ulong guildID) 62 | { 63 | MiunieUser nullUser = null; 64 | _ = _storageMock.Setup(s => s.RestoreSingle(It.IsAny>>())) 65 | .Returns(nullUser); 66 | _ = _storageMock.Setup(s => s.Store(nullUser)); 67 | 68 | var newUser = _userProvider.GetById(userId, guildID); 69 | 70 | _storageMock.Verify(s => s.RestoreSingle(It.IsAny>>()), Times.Once); 71 | _storageMock.Verify(s => s.Store(It.Is(u => u.UserId == userId && u.GuildId == guildID)), Times.Once); 72 | Assert.True(newUser.UserId == userId && newUser.GuildId == guildID); 73 | } 74 | 75 | [Fact] 76 | public void StoreUser_ShouldUpdateUser_IfUserExists() 77 | { 78 | _ = _storageMock.Setup(s => s.Store(It.IsAny())); 79 | _ = _storageMock.Setup(s => s.Update(It.IsAny())); 80 | _ = _storageMock.Setup(s => s.Exists(It.IsAny>>())) 81 | .Returns(true); 82 | 83 | _userProvider.StoreUser(_users.Drax); 84 | 85 | _storageMock.Verify(s => s.Exists(It.IsAny>>()), Times.Once); 86 | _storageMock.Verify(s => s.Update(It.IsAny()), Times.Once); 87 | _storageMock.Verify(s => s.Store(It.IsAny()), Times.Never); 88 | } 89 | 90 | [Fact] 91 | public void StoreUser_ShouldStoreUser_IfUserDoesntExist() 92 | { 93 | var user = new MiunieUser 94 | { 95 | GuildId = 0, 96 | UserId = 0, 97 | Reputation = new Reputation() 98 | }; 99 | _ = _storageMock.Setup(s => s.Store(It.IsAny())); 100 | _ = _storageMock.Setup(s => s.Update(It.IsAny())); 101 | _ = _storageMock.Setup(s => s.Exists(It.IsAny>>())) 102 | .Returns(false); 103 | 104 | _userProvider.StoreUser(user); 105 | 106 | _storageMock.Verify(s => s.Exists(It.IsAny>>()), Times.Once); 107 | _storageMock.Verify(s => s.Store(It.IsAny()), Times.Once); 108 | _storageMock.Verify(s => s.Update(It.IsAny()), Times.Never); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Miunie.Tests/Providers/TimeManipulationProviderTests.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Providers; 17 | using Miunie.Core.XUnit.Tests.Data; 18 | using Moq; 19 | using System; 20 | using Xunit; 21 | 22 | namespace Miunie.Core.XUnit.Tests.Providers 23 | { 24 | public class TimeManipulationProviderTests 25 | { 26 | private readonly ITimeManipulationProvider _provider; 27 | private readonly DummyMiunieUsers _dummyUsers; 28 | 29 | public TimeManipulationProviderTests() 30 | { 31 | _provider = new TimeManipulationProvider(); 32 | _dummyUsers = new DummyMiunieUsers(); 33 | } 34 | 35 | [Fact] 36 | public void InvalidTimeFrame_ShouldReturnNull() 37 | { 38 | var result = _provider.GetTimeSpanFromString("IncorrectTimeFrame", It.IsAny()); 39 | 40 | Assert.Null(result); 41 | } 42 | 43 | [Theory] 44 | [InlineData("hours", 1)] 45 | [InlineData("hrs", 10)] 46 | [InlineData("hr", 20)] 47 | [InlineData("hr", 30)] 48 | [InlineData("hours", 3000)] 49 | public void TimeFrameFromHours_ShouldReturnTimeSpanWithSetHours(string timeFrame, int amountOfHours) 50 | { 51 | var expected = new TimeSpan(amountOfHours, 0, 0); 52 | var actual = _provider.GetTimeSpanFromString(timeFrame, amountOfHours); 53 | 54 | Assert.Equal(expected, actual); 55 | } 56 | 57 | [Theory] 58 | [InlineData("minutes", 1)] 59 | [InlineData("minute", 10)] 60 | [InlineData("mins", 20)] 61 | [InlineData("min", 21)] 62 | public void TimeFrameFromMinutes_ShouldReturnTimeSpanWithSetMinutes(string timeFrame, int amountOfMinutes) 63 | { 64 | var expected = new TimeSpan(0, amountOfMinutes, 0); 65 | var actual = _provider.GetTimeSpanFromString(timeFrame, amountOfMinutes); 66 | 67 | Assert.Equal(expected, actual); 68 | } 69 | 70 | [Theory] 71 | [InlineData("seconds", 1)] 72 | [InlineData("second", 10)] 73 | [InlineData("secs", 20)] 74 | [InlineData("sec", 21)] 75 | public void TimeFrameFromSeconds_ShouldReturnTimeSpanWithSetSeconds(string timeFrame, int amountOfSeconds) 76 | { 77 | var expected = new TimeSpan(0, 0, amountOfSeconds); 78 | var actual = _provider.GetTimeSpanFromString(timeFrame, amountOfSeconds); 79 | 80 | Assert.Equal(expected, actual); 81 | } 82 | 83 | [Theory] 84 | [InlineData(-3)] 85 | [InlineData(0)] 86 | public void ZeroOrNegativeAmountOfTime_ShouldReturnNull(int amountOfTime) 87 | { 88 | const string validTimeFrame = "hours"; 89 | var result = _provider.GetTimeSpanFromString(validTimeFrame, amountOfTime); 90 | 91 | Assert.Null(result); 92 | } 93 | 94 | [Fact] 95 | public void EnteredDateTimeIsNull_ReturnsNull() 96 | { 97 | var result = _provider.GetDateTimeLocalToUser(null, _dummyUsers.DraxWithUtcTimeOffSet); 98 | 99 | Assert.Null(result); 100 | } 101 | 102 | [Fact] 103 | public void UserHasNoTimeSet_ReturnsEnteredDateTime() 104 | { 105 | var expectedDateTime = DateTime.UtcNow; 106 | 107 | var actual = _provider.GetDateTimeLocalToUser(expectedDateTime, _dummyUsers.PeterWithNoTimeSet); 108 | 109 | Assert.Equal(expectedDateTime, actual); 110 | } 111 | 112 | [Fact] 113 | public void DateTimeNullAndUserTimeNotSet_ShouldReturnNull() 114 | { 115 | var result = _provider.GetDateTimeLocalToUser(null, _dummyUsers.PeterWithNoTimeSet); 116 | 117 | Assert.Null(result); 118 | } 119 | 120 | [Fact] 121 | public void ValidDateTimeAndUserTimeSet_ShouldReturnDateTimeBasedOnUsersLocalTime() 122 | { 123 | var testDateTime = DateTime.UtcNow; 124 | var expectedUtcPlusOneDateTime = testDateTime.AddHours(1); 125 | 126 | var actual = _provider.GetDateTimeLocalToUser(testDateTime, _dummyUsers.PeterWithUtcPlusOneHourTimeSet); 127 | 128 | Assert.Equal(expectedUtcPlusOneDateTime, actual); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Miunie.Tests/Services/ProfileServiceReputationTests.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Discord; 17 | using Miunie.Core.Entities.Discord; 18 | using Miunie.Core.Logging; 19 | using Miunie.Core.Providers; 20 | using Miunie.Core.XUnit.Tests.Data; 21 | using Moq; 22 | using System; 23 | using System.Linq.Expressions; 24 | using System.Threading.Tasks; 25 | using Xunit; 26 | 27 | namespace Miunie.Core.XUnit.Tests.Services 28 | { 29 | public class ProfileServiceReputationTests 30 | { 31 | private readonly Mock _repProviderMock; 32 | private readonly ProfileService _profileService; 33 | private readonly DummyMiunieUsers _users; 34 | 35 | private readonly Expression> _hasDraxId; 36 | private readonly Expression> _hasSenneId; 37 | 38 | public ProfileServiceReputationTests() 39 | { 40 | _repProviderMock = new Mock(); 41 | var discordMsgMock = new Mock(); 42 | _profileService = new ProfileService(discordMsgMock.Object, _repProviderMock.Object, new Mock().Object, new Mock().Object); 43 | _users = new DummyMiunieUsers(); 44 | 45 | _hasDraxId = u => u.UserId == _users.Drax.UserId; 46 | _hasSenneId = u => u.UserId == _users.Senne.UserId; 47 | } 48 | 49 | [Fact] 50 | public async Task GiveReputationAsync_ShouldCheckForTimeoutBeforeAdding() 51 | { 52 | await _profileService.GiveReputationAsync(_users.Drax, _users.Senne, new MiunieChannel()); 53 | 54 | _repProviderMock.Verify( 55 | rp => rp.CanAddReputation( 56 | It.Is(_hasDraxId), 57 | It.Is(_hasSenneId)), Times.Once()); 58 | 59 | _repProviderMock.Verify( 60 | rp => rp.AddReputation( 61 | It.Is(_hasDraxId), 62 | It.Is(_hasSenneId)), Times.Once()); 63 | } 64 | 65 | [Fact] 66 | public async Task GiveReputationAsync_ShouldNotAddRepToSelf() 67 | { 68 | await _profileService.GiveReputationAsync(_users.Senne, _users.Senne, new MiunieChannel()); 69 | 70 | // NOTE(Peter): 71 | // Makes sure the service didn't add reputation to self 72 | // and that it didn't bother with checking the timeout either. 73 | _repProviderMock.VerifyNoOtherCalls(); 74 | } 75 | 76 | [Fact] 77 | public async Task GiveReputationAsync_ShouldCheckForTimeoutBeforeRemoving() 78 | { 79 | await _profileService.RemoveReputationAsync(_users.Drax, _users.Senne, new MiunieChannel()); 80 | 81 | _repProviderMock.Verify( 82 | rp => rp.CanRemoveReputation( 83 | It.Is(_hasDraxId), 84 | It.Is(_hasSenneId)), Times.Once()); 85 | 86 | _repProviderMock.Verify( 87 | rp => rp.RemoveReputation( 88 | It.Is(_hasDraxId), 89 | It.Is(_hasSenneId)), Times.Once()); 90 | } 91 | 92 | [Fact] 93 | public async Task GiveReputationAsync_ShouldNotRemoveRepFromSelf() 94 | { 95 | await _profileService.RemoveReputationAsync(_users.Senne, _users.Senne, new MiunieChannel()); 96 | 97 | _repProviderMock.VerifyNoOtherCalls(); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/Miunie.Tests/Services/ProfileServiceTests.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Discord; 17 | using Miunie.Core.Entities.Discord; 18 | using Moq; 19 | using System.Threading.Tasks; 20 | using Xunit; 21 | 22 | namespace Miunie.Core.XUnit.Tests.Services 23 | { 24 | public class ProfileServiceTests 25 | { 26 | private readonly Mock _msgMock; 27 | private readonly ProfileService _profileService; 28 | 29 | public ProfileServiceTests() 30 | { 31 | _msgMock = new Mock(); 32 | _profileService = new ProfileService(_msgMock.Object, null, null, null); 33 | } 34 | 35 | [Fact] 36 | public async Task ShowProfileAsync_ShouldExecuteOnce() 37 | { 38 | _ = _msgMock.Setup(m => m.SendMessageAsync(It.IsAny(), It.IsAny())) 39 | .Returns(Task.CompletedTask); 40 | 41 | await _profileService.ShowProfileAsync(null, null); 42 | 43 | _msgMock.Verify(m => m.SendMessageAsync(It.IsAny(), It.IsAny()), Times.Once); 44 | } 45 | 46 | [Fact] 47 | public async Task ShowGuildProfileAsync_ShouldExecuteOnce() 48 | { 49 | _ = _msgMock.Setup(m => m.SendMessageAsync(It.IsAny(), It.IsAny())) 50 | .Returns(Task.CompletedTask); 51 | 52 | await _profileService.ShowGuildProfileAsync(null, null); 53 | 54 | _msgMock.Verify(m => m.SendMessageAsync(It.IsAny(), It.IsAny()), Times.Once); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Miunie.Tests/Services/TimeServiceTests.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Discord; 17 | using Miunie.Core.Entities; 18 | using Miunie.Core.Entities.Discord; 19 | using Miunie.Core.Infrastructure; 20 | using Miunie.Core.Providers; 21 | using Moq; 22 | using System; 23 | using System.Threading.Tasks; 24 | using Xunit; 25 | 26 | namespace Miunie.Core.XUnit.Tests.Services 27 | { 28 | public class TimeServiceTests 29 | { 30 | private readonly Mock _messages; 31 | private readonly Mock _dateTime; 32 | private readonly Mock _users; 33 | private readonly Mock _timeManipulator; 34 | private readonly TimeService _service; 35 | 36 | public TimeServiceTests() 37 | { 38 | _messages = new Mock(); 39 | _dateTime = new Mock(); 40 | _users = new Mock(); 41 | _timeManipulator = new Mock(); 42 | _service = new TimeService(_messages.Object, _dateTime.Object, _users.Object, _timeManipulator.Object); 43 | } 44 | 45 | [Fact] 46 | public async Task NoTimezoneInfo_ShouldOutputWarning() 47 | { 48 | var channel = CreateTestChannel(); 49 | var user = CreateUserWithoutOffset(); 50 | 51 | await _service.OutputCurrentTimeForUserAsync(user, channel); 52 | 53 | AssertNoTimezoneInfoSent(); 54 | AssertNoOtherMessages(); 55 | } 56 | 57 | [Fact] 58 | public async Task CorrectOffset_ShouldOutputCorrectTime() 59 | { 60 | var channel = CreateTestChannel(); 61 | var user = CreateUserWithOffset(TimeSpan.FromHours(2)); 62 | SetCurrentTime(new DateTime(2020, 2, 21, 20, 30, 0)); 63 | var expectedTime = new DateTime(2020, 2, 21, 22, 30, 0); 64 | 65 | await _service.OutputCurrentTimeForUserAsync(user, channel); 66 | 67 | AssertCorrectTimeInfoSent(expectedTime); 68 | AssertNoOtherMessages(); 69 | } 70 | 71 | [Fact] 72 | public async Task SettingNewOffset_ShouldSaveAndOutputInfo() 73 | { 74 | SetCurrentTime(new DateTime(2020, 2, 22, 10, 59, 4)); 75 | var channel = CreateTestChannel(); 76 | var user = CreateUserWithoutOffset(); 77 | var enteredDateTime = new DateTime(1, 1, 1, 8, 0, 0); 78 | var expectedOffset = TimeSpan.FromHours(-2); 79 | 80 | await _service.SetUtcOffsetForUserAsync(enteredDateTime, user, channel); 81 | 82 | AssertOffsetChangedInfoSent(); 83 | AssertUserWithOffsetSaved(expectedOffset); 84 | AssertNoOtherMessages(); 85 | } 86 | 87 | private MiunieChannel CreateTestChannel() 88 | { 89 | return new MiunieChannel 90 | { 91 | ChannelId = 10, 92 | GuildId = 900 93 | }; 94 | } 95 | 96 | private MiunieUser CreateUserWithoutOffset() 97 | { 98 | return new MiunieUser 99 | { 100 | Name = "User", 101 | UtcTimeOffset = null 102 | }; 103 | } 104 | 105 | private MiunieUser CreateUserWithOffset(TimeSpan offset) 106 | { 107 | return new MiunieUser 108 | { 109 | Name = "User", 110 | UtcTimeOffset = offset 111 | }; 112 | } 113 | 114 | private void AssertOffsetChangedInfoSent() 115 | { 116 | _messages.Verify(m => m.SendMessageAsync(It.IsAny(), It.Is(pk => pk == PhraseKey.TIME_NEW_OFFSET_SET))); 117 | } 118 | 119 | private void AssertUserWithOffsetSaved(TimeSpan expectedOffset) 120 | { 121 | _users.Verify(u => u.StoreUser(It.Is(u => u.UtcTimeOffset == expectedOffset))); 122 | } 123 | 124 | private void AssertCorrectTimeInfoSent(DateTime expectedTime) 125 | { 126 | _messages.Verify(m => m.SendMessageAsync(It.IsAny(), It.Is(pk => pk == PhraseKey.TIME_TIMEZONE_INFO), It.IsAny(), It.Is(dt => dt == expectedTime))); 127 | } 128 | 129 | private void AssertNoTimezoneInfoSent() 130 | { 131 | _messages.Verify(m => m.SendMessageAsync(It.IsAny(), It.Is(pk => pk == PhraseKey.TIME_NO_TIMEZONE_INFO), It.IsAny())); 132 | } 133 | 134 | private void AssertNoOtherMessages() 135 | => _messages.VerifyNoOtherCalls(); 136 | 137 | private void SetCurrentTime(DateTime dateTime) 138 | => _dateTime.Setup(dt => dt.UtcNow).Returns(dateTime); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/Miunie.Tests/Services/YesNoServiceTests.cs: -------------------------------------------------------------------------------- 1 | // This file is part of Miunie. 2 | // 3 | // Miunie is free software: you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation, either version 3 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // Miunie is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with Miunie. If not, see . 15 | 16 | using Miunie.Core.Discord; 17 | using Miunie.Core.Entities; 18 | using Miunie.Core.Entities.Discord; 19 | using Moq; 20 | using System.Threading.Tasks; 21 | using Xunit; 22 | 23 | namespace Miunie.Core.XUnit.Tests.Services 24 | { 25 | public class YesNoServiceTests 26 | { 27 | [Fact] 28 | public async Task YesNo_ShouldDelegateProperly() 29 | { 30 | var messagesMock = new Mock(); 31 | var service = new MiscService(messagesMock.Object); 32 | 33 | await service.SendRandomYesNoAnswerAsync(new MiunieChannel()).ConfigureAwait(false); 34 | 35 | messagesMock.Verify(m => m.SendMessageAsync(It.IsAny(), It.Is(pk => pk == PhraseKey.YES_NO_MAYBE))); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Miunie.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}") = "Miunie.Core", "Miunie.Core\Miunie.Core.csproj", "{34A2664F-DB7E-45B1-8C6E-E5B9671337E8}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Miunie.Discord", "Miunie.Discord\Miunie.Discord.csproj", "{6677E885-5BB7-43D2-A2CE-0DE987F63367}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Miunie.Infrastructure", "Miunie.Infrastructure\Miunie.Infrastructure.csproj", "{792F5374-DDDD-464D-8C1B-F6BCB075397C}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Miunie.InversionOfControl", "Miunie.InversionOfControl\Miunie.InversionOfControl.csproj", "{396442A6-DB98-40D8-98D0-0432ABD1329E}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Miunie.Tests", "Miunie.Tests\Miunie.Tests.csproj", "{63FF7E44-2237-4C38-97F3-F06DA9567447}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Debug|x64 = Debug|x64 20 | Debug|x86 = Debug|x86 21 | Release|Any CPU = Release|Any CPU 22 | Release|x64 = Release|x64 23 | Release|x86 = Release|x86 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Debug|x64.ActiveCfg = Debug|Any CPU 32 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Debug|x64.Build.0 = Debug|Any CPU 33 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Debug|x86.ActiveCfg = Debug|Any CPU 34 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Debug|x86.Build.0 = Debug|Any CPU 35 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Release|x64.ActiveCfg = Release|Any CPU 38 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Release|x64.Build.0 = Release|Any CPU 39 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Release|x86.ActiveCfg = Release|Any CPU 40 | {34A2664F-DB7E-45B1-8C6E-E5B9671337E8}.Release|x86.Build.0 = Release|Any CPU 41 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Debug|x64.ActiveCfg = Debug|Any CPU 44 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Debug|x64.Build.0 = Debug|Any CPU 45 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Debug|x86.ActiveCfg = Debug|Any CPU 46 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Debug|x86.Build.0 = Debug|Any CPU 47 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Release|x64.ActiveCfg = Release|Any CPU 50 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Release|x64.Build.0 = Release|Any CPU 51 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Release|x86.ActiveCfg = Release|Any CPU 52 | {6677E885-5BB7-43D2-A2CE-0DE987F63367}.Release|x86.Build.0 = Release|Any CPU 53 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 54 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Debug|Any CPU.Build.0 = Debug|Any CPU 55 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Debug|x64.ActiveCfg = Debug|Any CPU 56 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Debug|x64.Build.0 = Debug|Any CPU 57 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Debug|x86.ActiveCfg = Debug|Any CPU 58 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Debug|x86.Build.0 = Debug|Any CPU 59 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Release|Any CPU.ActiveCfg = Release|Any CPU 60 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Release|Any CPU.Build.0 = Release|Any CPU 61 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Release|x64.ActiveCfg = Release|Any CPU 62 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Release|x64.Build.0 = Release|Any CPU 63 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Release|x86.ActiveCfg = Release|Any CPU 64 | {792F5374-DDDD-464D-8C1B-F6BCB075397C}.Release|x86.Build.0 = Release|Any CPU 65 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 66 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Debug|Any CPU.Build.0 = Debug|Any CPU 67 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Debug|x64.ActiveCfg = Debug|Any CPU 68 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Debug|x64.Build.0 = Debug|Any CPU 69 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Debug|x86.ActiveCfg = Debug|Any CPU 70 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Debug|x86.Build.0 = Debug|Any CPU 71 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Release|Any CPU.ActiveCfg = Release|Any CPU 72 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Release|Any CPU.Build.0 = Release|Any CPU 73 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Release|x64.ActiveCfg = Release|Any CPU 74 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Release|x64.Build.0 = Release|Any CPU 75 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Release|x86.ActiveCfg = Release|Any CPU 76 | {396442A6-DB98-40D8-98D0-0432ABD1329E}.Release|x86.Build.0 = Release|Any CPU 77 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 78 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Debug|Any CPU.Build.0 = Debug|Any CPU 79 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Debug|x64.ActiveCfg = Debug|Any CPU 80 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Debug|x64.Build.0 = Debug|Any CPU 81 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Debug|x86.ActiveCfg = Debug|Any CPU 82 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Debug|x86.Build.0 = Debug|Any CPU 83 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Release|Any CPU.ActiveCfg = Release|Any CPU 84 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Release|Any CPU.Build.0 = Release|Any CPU 85 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Release|x64.ActiveCfg = Release|Any CPU 86 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Release|x64.Build.0 = Release|Any CPU 87 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Release|x86.ActiveCfg = Release|Any CPU 88 | {63FF7E44-2237-4C38-97F3-F06DA9567447}.Release|x86.Build.0 = Release|Any CPU 89 | EndGlobalSection 90 | EndGlobal 91 | -------------------------------------------------------------------------------- /src/stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 3 | "settings": { 4 | "documentationRules": { 5 | "companyName": "PlaceholderCompany", 6 | "copyrightText": "This file is part of Miunie.\n\n Miunie is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n Miunie is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU General Public License for more details.\n\n You should have received a copy of the GNU General Public License\n along with Miunie. If not, see .", 7 | "xmlHeader": false, 8 | "headerDecoration": "-----------------------------------------------------------------------", 9 | "documentExposedElements": false, 10 | "documentInternalElements": false, 11 | "documentPrivateElements": false, 12 | "documentInterfaces": false 13 | }, 14 | "orderingRules": { 15 | "usingDirectivesPlacement": "outsideNamespace", 16 | "systemUsingDirectivesFirst": false, 17 | "blankLinesBetweenUsingGroups": "omit" 18 | }, 19 | "layoutRules": { 20 | "newlineAtEndOfFile": "require" 21 | } 22 | } 23 | } 24 | --------------------------------------------------------------------------------