From 9a8a4cad5d0a764e4e22c1df32121a1964885320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=A8=D0=B8?= =?UTF-8?q?=D0=BC=D0=B0=D0=BD=D1=81=D0=BA=D0=B8=D0=B9?= Date: Thu, 26 Oct 2023 11:35:42 +0300 Subject: [PATCH] add discord bot change net6.0 net7.0 --- Auth/ApiKeyTypes.cs | 8 + Auth/AuthanticationByBearerToken.cs | 60 +++++++ Controllers/WeatherForecastController.cs | 33 ++++ Database/AppDbContext.cs | 18 ++ Database/Tables/Autobranches.cs | 14 ++ Database/Tables/Autoreactions.cs | 14 ++ Database/Tables/Passport.cs | 20 +++ Database/Tables/Patents.cs | 20 +++ Discord.cs | 40 +++++ DiscordApp - Backup.csproj | 18 ++ DiscordApp.csproj | 13 +- DiscordApp.sln | 12 +- Dockerfile | 4 +- Dockerfile.original | 22 +++ Enums/NitroSubscription.cs | 13 ++ Enums/Supporter.cs | 11 ++ Enums/TransactionType.cs | 14 ++ Enums/UserFlags.cs | 15 ++ Enums/UserType.cs | 11 ++ InteractionHandler.cs | 70 ++++++++ Justice.cs | 41 +++++ Justice/Commands/Passports.cs | 27 +++ Justice/Commands/Settings.cs | 94 ++++++++++ Justice/Events/Events.cs | 57 ++++++ Justice/Interactions/PassportInteraction.cs | 162 ++++++++++++++++++ Justice/Interactions/VerificateInteraction.cs | 33 ++++ Justice/SelfBot.cs | 44 +++++ JusticeHandler.cs | 69 ++++++++ Program.cs | 57 +++--- Properties/launchSettings.json | 23 ++- Startup.cs | 91 ++++++++++ Types/DiscordUserType.cs | 18 ++ Types/PaymentData.cs | 9 + WeatherForecast.cs | 13 ++ appsettings.Development.json | 1 - 35 files changed, 1132 insertions(+), 37 deletions(-) create mode 100644 Auth/ApiKeyTypes.cs create mode 100644 Auth/AuthanticationByBearerToken.cs create mode 100644 Controllers/WeatherForecastController.cs create mode 100644 Database/AppDbContext.cs create mode 100644 Database/Tables/Autobranches.cs create mode 100644 Database/Tables/Autoreactions.cs create mode 100644 Database/Tables/Passport.cs create mode 100644 Database/Tables/Patents.cs create mode 100644 Discord.cs create mode 100644 DiscordApp - Backup.csproj create mode 100644 Dockerfile.original create mode 100644 Enums/NitroSubscription.cs create mode 100644 Enums/Supporter.cs create mode 100644 Enums/TransactionType.cs create mode 100644 Enums/UserFlags.cs create mode 100644 Enums/UserType.cs create mode 100644 InteractionHandler.cs create mode 100644 Justice.cs create mode 100644 Justice/Commands/Passports.cs create mode 100644 Justice/Commands/Settings.cs create mode 100644 Justice/Events/Events.cs create mode 100644 Justice/Interactions/PassportInteraction.cs create mode 100644 Justice/Interactions/VerificateInteraction.cs create mode 100644 Justice/SelfBot.cs create mode 100644 JusticeHandler.cs create mode 100644 Startup.cs create mode 100644 Types/DiscordUserType.cs create mode 100644 Types/PaymentData.cs create mode 100644 WeatherForecast.cs diff --git a/Auth/ApiKeyTypes.cs b/Auth/ApiKeyTypes.cs new file mode 100644 index 0000000..660201f --- /dev/null +++ b/Auth/ApiKeyTypes.cs @@ -0,0 +1,8 @@ +namespace DiscordApp.Auth +{ + public enum ApiKeyTypes + { + Public, + Private + } +} \ No newline at end of file diff --git a/Auth/AuthanticationByBearerToken.cs b/Auth/AuthanticationByBearerToken.cs new file mode 100644 index 0000000..cdff743 --- /dev/null +++ b/Auth/AuthanticationByBearerToken.cs @@ -0,0 +1,60 @@ +using DiscordApp.Database; +using DiscordApp.Database.Tables; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Options; +using System.Collections.Specialized; +using System.Security.Claims; +using System.Text.Encodings.Web; + +namespace DiscordApp.Auth +{ + public class AuthanticationByBearerToken : AuthenticationHandler + { + private AppDbContext dbContext; + + public AuthanticationByBearerToken( + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + ISystemClock clock, + AppDbContext dbContext) : base(options, logger, encoder, clock) + { + this.dbContext = dbContext; + } + + protected override async Task HandleAuthenticateAsync() + { + if (!Request.Headers.TryGetValue("Authorization", out var apiKeyHeaderValues)) + { + return AuthenticateResult.Fail("API Key was not provided."); + } + +#pragma warning disable CS8602 // . + string providedApiKey = apiKeyHeaderValues + .FirstOrDefault().Replace("'", ""); + if (CheckForInvalidCharacters(apiKeyHeaderValues)) return AuthenticateResult.Fail("Don`t use SQL injections, dog`s son"); +#pragma warning restore CS8602 // . + + if (IsValidApiKey(providedApiKey)) + { + var claims = new[] { new Claim("Bearer", providedApiKey) }; + var identity = new ClaimsIdentity(claims, Scheme.Name); + var principal = new ClaimsPrincipal(identity); + var ticket = new AuthenticationTicket(principal, Scheme.Name); + + return AuthenticateResult.Success(ticket); + } + + return AuthenticateResult.Fail("Invalid API Key provided."); + } + + private bool IsValidApiKey(string apiKey) + { + return true; + } + private bool CheckForInvalidCharacters(string value) + { + return value.IndexOfAny(";".ToCharArray()) != -1; + } + } +} \ No newline at end of file diff --git a/Controllers/WeatherForecastController.cs b/Controllers/WeatherForecastController.cs new file mode 100644 index 0000000..b389f4d --- /dev/null +++ b/Controllers/WeatherForecastController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Mvc; + +namespace DiscordApp.Controllers +{ + [ApiController] + [Route("[controller]")] + public class WeatherForecastController : ControllerBase + { + private static readonly string[] Summaries = new[] + { + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + }; + + private readonly ILogger _logger; + + public WeatherForecastController(ILogger logger) + { + _logger = logger; + } + + [HttpGet(Name = "GetWeatherForecast")] + public IEnumerable Get() + { + return Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = Summaries[Random.Shared.Next(Summaries.Length)] + }) + .ToArray(); + } + } +} \ No newline at end of file diff --git a/Database/AppDbContext.cs b/Database/AppDbContext.cs new file mode 100644 index 0000000..8cdfa2d --- /dev/null +++ b/Database/AppDbContext.cs @@ -0,0 +1,18 @@ +using DiscordApp.Database.Tables; +using Microsoft.EntityFrameworkCore; + +namespace DiscordApp.Database +{ + public class AppDbContext : DbContext + { + public AppDbContext(DbContextOptions options) : base(options) { } + + public DbSet Passport { get; set; } + public DbSet Autobranches { get; set; } + public DbSet Autoreactions { get; set; } + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + } + } +} \ No newline at end of file diff --git a/Database/Tables/Autobranches.cs b/Database/Tables/Autobranches.cs new file mode 100644 index 0000000..8006ad8 --- /dev/null +++ b/Database/Tables/Autobranches.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DiscordApp.Database.Tables +{ + [Table("Autobranches", Schema = "public")] + public class Autobranches + { + [Key] + public ulong ChannelId { get; set; } + public string BranchName { get; set; } + + } +} \ No newline at end of file diff --git a/Database/Tables/Autoreactions.cs b/Database/Tables/Autoreactions.cs new file mode 100644 index 0000000..2ff6818 --- /dev/null +++ b/Database/Tables/Autoreactions.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DiscordApp.Database.Tables +{ + [Table("Autoreactions", Schema = "public")] + public class Autoreactions + { + [Key] + public ulong ChannelId { get; set; } + public string EmoteId { get; set; } + + } +} \ No newline at end of file diff --git a/Database/Tables/Passport.cs b/Database/Tables/Passport.cs new file mode 100644 index 0000000..c06666f --- /dev/null +++ b/Database/Tables/Passport.cs @@ -0,0 +1,20 @@ +using DiscordApp.Enums; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DiscordApp.Database.Tables +{ + [Table("Passport", Schema = "public")] + public class Passport + { + [Key] + public int Id { get; set; } + public ulong Employee { get; set; } + public string Applicant { get; set; } + public long Date { get; set; } + public Supporter Support { get; set; } + public string Gender { get; set; } + public string RpName { get; set; } + + } +} \ No newline at end of file diff --git a/Database/Tables/Patents.cs b/Database/Tables/Patents.cs new file mode 100644 index 0000000..fda7d5b --- /dev/null +++ b/Database/Tables/Patents.cs @@ -0,0 +1,20 @@ +using DiscordApp.Enums; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace DiscordApp.Database.Tables +{ + [Table("Patents", Schema = "public")] + public class Patents + { + public string Employee { get; set; } + public string Applicant { get; set; } + public int Date { get; set; } + [Key] + public int[] Number { get; set; } + public Supporter Support { get; set; } + public string Gender { get; set; } + public string Name { get; set; } + + } +} \ No newline at end of file diff --git a/Discord.cs b/Discord.cs new file mode 100644 index 0000000..48e190e --- /dev/null +++ b/Discord.cs @@ -0,0 +1,40 @@ +using Discord; +using Discord.WebSocket; + + +namespace DiscordApp +{ + public class DiscordBotService : BackgroundService + { + private readonly IHostApplicationLifetime hostApplicationLifetime; + private readonly DiscordSocketClient client; + private readonly IConfiguration configuration; + private readonly InteractionHandler interactionHandler; + + public DiscordBotService( + IHostApplicationLifetime hostApplicationLifetime, + DiscordSocketClient client, + IConfiguration configuration, + InteractionHandler interactionHandler) + { + this.interactionHandler = interactionHandler; + this.configuration = configuration; + this.client = client; + this.hostApplicationLifetime = hostApplicationLifetime; + } + + protected async override Task ExecuteAsync(CancellationToken stoppingToken) + { + client.Log += LogAsync; + + await client.LoginAsync(TokenType.Bot, "MTE1Mjk0Njg2NTMwNjg4MjExOA.GBp_Wv.MacxgnAz_idgNj7du8hrkOxuWfoyuVpj9zPsM4"); + await client.StartAsync(); + await interactionHandler.InitializeAsync(); + + await Task.Delay(Timeout.Infinite); + } + + private async Task LogAsync(LogMessage message) + => Console.WriteLine(message.ToString()); + } +} diff --git a/DiscordApp - Backup.csproj b/DiscordApp - Backup.csproj new file mode 100644 index 0000000..f156702 --- /dev/null +++ b/DiscordApp - Backup.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + enable + enable + cff49f3b-b209-4bd8-b471-d297aaa3822e + Linux + . + + + + + + + + + diff --git a/DiscordApp.csproj b/DiscordApp.csproj index 8d6a087..192fca8 100644 --- a/DiscordApp.csproj +++ b/DiscordApp.csproj @@ -1,16 +1,25 @@ - net6.0 + net7.0 enable enable - 9e418d7f-fd52-4ff9-9673-969c3f62c78d + 392a6656-544a-410a-9be8-214215cd1cc8 Linux . + + + + + + + + + diff --git a/DiscordApp.sln b/DiscordApp.sln index 3483042..36850ac 100644 --- a/DiscordApp.sln +++ b/DiscordApp.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.6.33723.286 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordApp", "DiscordApp.csproj", "{CDCCF9AF-D015-4E3A-8E1E-8151BB1C865B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiscordApp", "DiscordApp.csproj", "{950F9F70-ACDF-459E-8013-8E9E5B3B410A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,15 +11,15 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CDCCF9AF-D015-4E3A-8E1E-8151BB1C865B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CDCCF9AF-D015-4E3A-8E1E-8151BB1C865B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CDCCF9AF-D015-4E3A-8E1E-8151BB1C865B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CDCCF9AF-D015-4E3A-8E1E-8151BB1C865B}.Release|Any CPU.Build.0 = Release|Any CPU + {950F9F70-ACDF-459E-8013-8E9E5B3B410A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {950F9F70-ACDF-459E-8013-8E9E5B3B410A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {950F9F70-ACDF-459E-8013-8E9E5B3B410A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {950F9F70-ACDF-459E-8013-8E9E5B3B410A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {B6798D09-E12C-4F92-A0BE-CC5D14187AB8} + SolutionGuid = {B1D04319-BFE6-4F69-9951-AA4AD2AE4E30} EndGlobalSection EndGlobal diff --git a/Dockerfile b/Dockerfile index 4eb1df8..10318f4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,11 @@ #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 -FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build WORKDIR /src COPY ["DiscordApp.csproj", "."] RUN dotnet restore "./DiscordApp.csproj" diff --git a/Dockerfile.original b/Dockerfile.original new file mode 100644 index 0000000..4eb1df8 --- /dev/null +++ b/Dockerfile.original @@ -0,0 +1,22 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["DiscordApp.csproj", "."] +RUN dotnet restore "./DiscordApp.csproj" +COPY . . +WORKDIR "/src/." +RUN dotnet build "DiscordApp.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "DiscordApp.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "DiscordApp.dll"] \ No newline at end of file diff --git a/Enums/NitroSubscription.cs b/Enums/NitroSubscription.cs new file mode 100644 index 0000000..0ffb9da --- /dev/null +++ b/Enums/NitroSubscription.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DiscordApp.Enums +{ + public enum NitroSubscription + { + None = 0, + Classic = 1, + Regular = 2 + } +} diff --git a/Enums/Supporter.cs b/Enums/Supporter.cs new file mode 100644 index 0000000..27f7844 --- /dev/null +++ b/Enums/Supporter.cs @@ -0,0 +1,11 @@ +namespace DiscordApp.Enums +{ + public enum Supporter + { + None = 0, + FirstLvl = 1, + SecondLvl = 2, + ThirdLvl = 3 + } + +} diff --git a/Enums/TransactionType.cs b/Enums/TransactionType.cs new file mode 100644 index 0000000..f708711 --- /dev/null +++ b/Enums/TransactionType.cs @@ -0,0 +1,14 @@ +namespace DiscordApp.Enums +{ + public enum TransactionType + { + Refill = 0, + UserDelivery = 1, + CourierDelivery = 2, + Withdraw = 3, + Order = 4, + Buy = 5, + Sell = 6, + Refund = 7 + } +} \ No newline at end of file diff --git a/Enums/UserFlags.cs b/Enums/UserFlags.cs new file mode 100644 index 0000000..ccb6418 --- /dev/null +++ b/Enums/UserFlags.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DiscordApp.Enums +{ + public enum UserFlags + { + None = 0, + HypeSquadEvents = 4, + HouseBravery = 64, + HouseBrilliance = 128, + HouseBalance = 256 + } +} diff --git a/Enums/UserType.cs b/Enums/UserType.cs new file mode 100644 index 0000000..bf4b30b --- /dev/null +++ b/Enums/UserType.cs @@ -0,0 +1,11 @@ +namespace DiscordApp.Enums +{ + public enum UserType + { + Player = 0, + Banned = 1, + Courier = 2, + Moderator = 3, + Admin = 4, + } +} \ No newline at end of file diff --git a/InteractionHandler.cs b/InteractionHandler.cs new file mode 100644 index 0000000..67fc68d --- /dev/null +++ b/InteractionHandler.cs @@ -0,0 +1,70 @@ +using Discord; +using Discord.Interactions; +using Discord.WebSocket; +using DiscordApp.Database; +using System.Reflection; + + +namespace DiscordApp +{ + public class InteractionHandler + { + private readonly DiscordSocketClient client; + private readonly InteractionService handler; + private readonly IServiceProvider services; + private readonly IConfiguration configuration; + + public InteractionHandler(DiscordSocketClient client, InteractionService handler, IConfiguration config) + { + this.client = client; + this.handler = handler; + this.services = Startup.serviceProvider; + this.configuration = config; + } + + public async Task InitializeAsync() + { + client.Ready += ReadyAsync; + handler.Log += LogAsync; + + await handler.AddModulesAsync(Assembly.GetEntryAssembly(), services); + var guildCommand = new SlashCommandBuilder(); + + client.InteractionCreated += HandleInteraction; + } + + private async Task LogAsync(LogMessage log) + => Console.WriteLine(log); + + private async Task ReadyAsync() + { + + await handler.RegisterCommandsGloballyAsync(true); + + } + + private async Task HandleInteraction(SocketInteraction interaction) + { + try + { + var context = new SocketInteractionContext(client, interaction); + + var result = await handler.ExecuteCommandAsync(context, services); + + if (!result.IsSuccess) + switch (result.Error) + { + case InteractionCommandError.UnmetPrecondition: + break; + default: + break; + } + } + catch + { + if (interaction.Type is InteractionType.ApplicationCommand) + await interaction.GetOriginalResponseAsync().ContinueWith(async (msg) => await msg.Result.DeleteAsync()); + } + } + } +} diff --git a/Justice.cs b/Justice.cs new file mode 100644 index 0000000..3fb8a24 --- /dev/null +++ b/Justice.cs @@ -0,0 +1,41 @@ +using Discord; +using Discord.WebSocket; +using DiscordApp; + +namespace DiscordApp +{ + public class JusticeBotService : BackgroundService + { + private readonly IHostApplicationLifetime hostApplicationLifetime; + private readonly DiscordSocketClient client; + private readonly IConfiguration configuration; + private readonly JusticeHandler interactionHandler; + + public JusticeBotService( + IHostApplicationLifetime hostApplicationLifetime, + DiscordSocketClient client, + IConfiguration configuration, + JusticeHandler interactionHandler) + { + this.interactionHandler = interactionHandler; + this.configuration = configuration; + this.client = client; + this.hostApplicationLifetime = hostApplicationLifetime; + } + + protected async override Task ExecuteAsync(CancellationToken stoppingToken) + { + client.Log += LogAsync; + client.UserJoined += Justice.Events.Events.onJoinGuild; + client.MessageReceived += Justice.Events.Events.onMessageCreate; + await client.LoginAsync(TokenType.Bot, "MTE2NjA3OTk3NjQ0NjEwMzYwMg.GAKOIo.4af972Wh11G0EF4O5tNYb7l-vt5OwMc4HPRnjE"); + await client.StartAsync(); + await interactionHandler.InitializeAsync(); + + await Task.Delay(Timeout.Infinite); + } + + private async Task LogAsync(LogMessage message) + => Console.WriteLine(message.ToString()); + } +} diff --git a/Justice/Commands/Passports.cs b/Justice/Commands/Passports.cs new file mode 100644 index 0000000..46d7ac6 --- /dev/null +++ b/Justice/Commands/Passports.cs @@ -0,0 +1,27 @@ +using Discord; +using Discord.Interactions; + +namespace DiscordApp.Justice.Commands +{ + public class Passports : InteractionModuleBase + { + public InteractionService Commands { get; set; } + [SlashCommand("send_passport_embed", description: "Отправляет сообщение для регистрации паспортов")] + public async Task sendPassportBuilerEmbed() + { + await DeferAsync(true); + var Embed = new EmbedBuilder() + .WithTitle("**Регистрация паспорта!**") + .WithDescription("Ниже вы можете нажать на кнопку для создания темплейта паспорта!") + .WithColor(Color.Blue) + .Build(); + var Components = new ComponentBuilder() + .WithButton(new ButtonBuilder() { CustomId = "newPassport", Label = "Новый паспорт", Style = ButtonStyle.Primary }) + .WithButton(new ButtonBuilder() { CustomId = "reworkPassport", Label = "Замена паспорта", Style = ButtonStyle.Primary }) + .Build(); + await Context.Channel.SendMessageAsync(embed: Embed, components: Components); + await FollowupAsync("OK!");//, ephemeral: true); + } + + } +} diff --git a/Justice/Commands/Settings.cs b/Justice/Commands/Settings.cs new file mode 100644 index 0000000..b393899 --- /dev/null +++ b/Justice/Commands/Settings.cs @@ -0,0 +1,94 @@ +using Discord; +using Discord.Interactions; +using Discord.WebSocket; +using DiscordApp.Database; +using DiscordApp.Database.Tables; +using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; + +namespace DiscordApp.Discord.Commands +{ + public class AdminCommands : InteractionModuleBase + { + public InteractionService Commands { get; set; } + + [SlashCommand("branches", "Настройка автоветок")] + [DefaultMemberPermissions(GuildPermission.Administrator)] + public async Task addAutoBranches(IChannel channel, string branchName = "Обсуждение") + { + + await RespondAsync($"Автоветки для канала {channel.Name} настроены", ephemeral: true); + Autobranches autobranches = new() + { + ChannelId = channel.Id, + BranchName = branchName + }; + Startup.appDbContext.Autobranches.Add(autobranches); + } + + [SlashCommand("emotes", "Настройка автоэмоций")] + [DefaultMemberPermissions(GuildPermission.Administrator)] + public async Task addAutoReact(string emote, IChannel channel) + { + var emotes = Emote.Parse(emote); + await RespondAsync($"Автореакция {emotes.Url} для канала {channel.Name} настроены", ephemeral: true); + + Autoreactions autoreactions = new() + { + ChannelId = channel.Id, + EmoteId = emotes.ToString() + }; + Startup.appDbContext.Autoreactions.Add(autoreactions); + } + + [SlashCommand("embed", "Отправить эмбед")] + [DefaultMemberPermissions(GuildPermission.Administrator)] + public async Task sendAsEmbed(string description, string? title = null, string? footer = null, IAttachment? attachment = null) + { + var author = new EmbedAuthorBuilder() + .WithName(Context.User.GlobalName) + .WithIconUrl(Context.User.GetAvatarUrl()) + .WithUrl("https://yaflay.ru/"); + + var embed = new EmbedBuilder() + .WithTitle(title) + .WithDescription(description) + .WithFooter(footer) + .WithColor(5793266) + .WithAuthor(author) + .WithImageUrl(attachment?.Url) + .Build(); + + await DeferAsync(true); + await FollowupAsync("Готово!", ephemeral: true); + + await Context.Channel.SendMessageAsync(embed: embed); + + } + + [SlashCommand("verification", "Отправляет сообщение верификации")] + [DefaultMemberPermissions(GuildPermission.Administrator)] + public async Task sendVerificationEmbed() + { + await DeferAsync(true); + var embed = new EmbedBuilder() + .WithTitle("**Верификация игроков**") + .WithDescription($"Если что-то случилось, и вам не выдается роль <@&1165687128366268511>, то нажмите на кнопку ниже!") + .WithImageUrl("") + .WithColor(Color.Blue) + .Build(); + var components = new ComponentBuilder() + .WithButton( + new ButtonBuilder() + .WithLabel("Верификация") + .WithCustomId("UserVerification") + .WithStyle(ButtonStyle.Success) + ) + .Build(); + await Context.Channel.SendMessageAsync(embed: embed, components: components); + await FollowupAsync("Ok", ephemeral: true); + } + + + // ReplyAsync is a method on ModuleBase + } +} diff --git a/Justice/Events/Events.cs b/Justice/Events/Events.cs new file mode 100644 index 0000000..5cc9bd6 --- /dev/null +++ b/Justice/Events/Events.cs @@ -0,0 +1,57 @@ +using Discord; +using Discord.Commands; +using Discord.Interactions; +using Discord.WebSocket; +using DiscordApp; +using DiscordApp.Database.Tables; +using Microsoft.EntityFrameworkCore; +using spworlds; +using spworlds.Types; +using System.Runtime.InteropServices; + +namespace DiscordApp.Justice.Events +{ + public class Events + { + public static async Task onJoinGuild(SocketGuildUser socketUser) + { + try + { + User SpwUser = await Startup.sp.GetUser(socketUser.Id.ToString()); + if (SpwUser.IsPlayer()) + { + IRole role; + if (socketUser.Guild.Id == 1165687128366268506) { role = socketUser.Guild.GetRole(1165687128366268511); } + else if (socketUser.Guild.Id == 1107742957458685985) { role = socketUser.Guild.GetRole(1136564585420304444); } + else { return; } + await socketUser.AddRoleAsync(role); + await socketUser.ModifyAsync(func => + { + func.Nickname = SpwUser.Name; + }); + } + } + catch (Exception e) { await Console.Out.WriteLineAsync($"User {socketUser.DisplayName} not found as player!"); } + } + + public static async Task onMessageCreate(SocketMessage message) + { + /** + var autoBranchesDatabase = await Startup.appDbContext.Autobranches.FindAsync(message.Channel.Id); + var autoReactDatabase = await Startup.appDbContext.Autoreactions.ForEachAsync(s => s.ChannelId == message.Channel.Id); + if (autoBranchesDatabase != null) + { + await ((ITextChannel)message.Channel).CreateThreadAsync(autoBranchesDatabase.BranchName); + } + if (autoReactDatabase != false) + { + foreach (Autoreactions autoreaction in autoReactDatabase) + { + var Emoji = Emote.Parse(autoreaction.EmoteId); + await message.AddReactionAsync(Emoji); + } + } + **/ + } + } +} diff --git a/Justice/Interactions/PassportInteraction.cs b/Justice/Interactions/PassportInteraction.cs new file mode 100644 index 0000000..e322355 --- /dev/null +++ b/Justice/Interactions/PassportInteraction.cs @@ -0,0 +1,162 @@ +using Discord; +using Discord.Interactions; +using Discord.Rest; +using Discord.WebSocket; +using DiscordApp.Database.Tables; +using DiscordApp.Enums; +using Microsoft.EntityFrameworkCore; +using spworlds.Types; +using System.Globalization; +using System.IO; +using System.Xml; + +namespace DiscordApp.Justice.Interactions +{ + public class PassportInteraction : InteractionModuleBase + { + + [ComponentInteraction("newPassport")] + public async Task AplyWork() + => await Context.Interaction.RespondWithModalAsync("passportModal"); + + [ModalInteraction("passportModal")] + public async Task createPassportInteraction(NewPassportModal modal) + { + await DeferAsync(true); + string name = modal.NickName; + string RpName = modal.RPName; + int supporterInt = modal.Supporter; + string birthday = modal.Birthday; + string gender = modal.Gender; + + SocketGuildUser user = Context.Guild.GetUser(Context.User.Id); + Supporter supporter; + Random random = new(); + spworlds.Types.User spUser = await spworlds.Types.User.CreateUser(name); + + DateTimeOffset toTime = DateTime.Now.AddDays(14); + DateTime birthDate; + int id = random.Next(00001, 99999); + long unixTime; + + try + { + birthDate = DateTime.Parse(birthday); + unixTime = ((DateTimeOffset)birthDate).ToUnixTimeSeconds(); + if (birthDate.AddDays(14) < DateTime.Now) + { + await FollowupAsync($"Возможно, игрок {name} больше не новичек, и бесплатный паспорт ему не положен!", ephemeral: true); + } + } + catch + { + await FollowupAsync($"Возможно, с датой {modal.Birthday} какая-то ошибка, попробуйте такой тип: 14.02.2023", ephemeral: true); + return; + } + + switch (supporterInt) + { + case 0: + supporter = Supporter.None; + break; + case 1: + supporter = Supporter.FirstLvl; + break; + case 2: + supporter = Supporter.SecondLvl; + break; + case 3: + supporter = Supporter.ThirdLvl; + break; + + default: + await FollowupAsync("Неправильно указан уровень благотворителя. Используйте числа от 0 до 3(в зависимости от уровня)", ephemeral: true); + return; + } + + var passportData = new EmbedFieldBuilder() + .WithName("Данные паспорта:") + .WithValue($"```\nИмя: {name}\nРП Имя: {RpName}\nАйди: {id}\nБлаготворитель: {supporter}\nГендер: {gender}\nДата рождения: {birthDate.ToShortDateString()}```") + .WithIsInline(true); + + var author = new EmbedAuthorBuilder() + .WithName(user.DisplayName) + .WithIconUrl(user.GetDisplayAvatarUrl()); + + var faceUrl = "https://visage.surgeplay.com/face/64/" + spUser.Uuid; + Console.WriteLine(faceUrl); + + var embed = new EmbedBuilder() + .WithTitle("**Новый паспорт**") + .AddField(passportData) + .AddField(new EmbedFieldBuilder().WithName("Составитель: ").WithValue(user.GlobalName).WithIsInline(true)) + .AddField(new EmbedFieldBuilder().WithName("Доступен до: ").WithValue($"").WithIsInline(true)) + .WithThumbnailUrl(faceUrl) + .WithColor(Color.DarkBlue) + .WithAuthor(author) + .WithTimestamp(toTime) + .Build(); + + Passport passport = new() + { + Employee = user.Id, + RpName = RpName, + Gender = gender, + Date = unixTime, + Applicant = name, + Id = id, + Support = supporter + }; + + if (Startup.appDbContext.Passport.FindAsync(passport.Id).Result != null) + { + bool isUnical = false; + while (!isUnical) + { + + id = random.Next(00001, 99999); + passport.Id = id; + Console.WriteLine(passport.Id); + if (Startup.appDbContext.Passport.FindAsync(passport.Id).Result == null) { break; } + } + } + + + + + await Startup.appDbContext.Passport.AddAsync(passport); + await Startup.appDbContext.SaveChangesAsync(); + await FollowupAsync($"ID для паспорта: {id}", embed: embed, ephemeral: true); + + var channel = Context.Guild.GetChannel(1108006685626355733) as ITextChannel; + + var message = await channel.SendMessageAsync(embed: embed); + } + } + + public class NewPassportModal : IModal + { + public string Title => "Создание паспорта"; + + [InputLabel("Ник игрока")] + [ModalTextInput("nickname", TextInputStyle.Short, placeholder: "YaFlay", maxLength: 90)] + public string NickName { get; set; } + + [InputLabel("Благотворитель")] + [ModalTextInput("Supporter", TextInputStyle.Short, placeholder: "1", maxLength: 5)] + public int Supporter { get; set; } + + [InputLabel("РП Имя")] + [ModalTextInput("rolePlayName", TextInputStyle.Short, placeholder: "Олег Бебров", maxLength: 200)] + public string RPName { get; set; } + + [InputLabel("Пол")] + [ModalTextInput("gender", TextInputStyle.Short, maxLength: 200)] + public string Gender { get; set; } + [InputLabel("Дата рождения")] + [ModalTextInput("BirthDay", TextInputStyle.Short, placeholder: "16.02.2023", maxLength: 100)] + public string Birthday { get; set; } + + } + +} diff --git a/Justice/Interactions/VerificateInteraction.cs b/Justice/Interactions/VerificateInteraction.cs new file mode 100644 index 0000000..fb194c4 --- /dev/null +++ b/Justice/Interactions/VerificateInteraction.cs @@ -0,0 +1,33 @@ +using Discord.Interactions; + +namespace DiscordApp.Justice.Interactions +{ + public class VerificateInteraction : InteractionModuleBase + { + [ComponentInteraction("UserVerification")] + public async Task userVerificationInteraction() + { + await DeferAsync(true); + try + { + var user = await Startup.sp.GetUser(Context.User.Id.ToString()); + if (user.IsPlayer()) + { + await FollowupAsync("Готово!", ephemeral: true); + var guildUser = Context.Guild.GetUser(Context.User.Id); + await guildUser.AddRoleAsync(1165687128366268511); + await guildUser.ModifyAsync(func => + { + func.Nickname = user.Name; + }); + + } + } + catch (Exception ex) + { + await Console.Out.WriteLineAsync($"User {Context.User.GlobalName} not found! Error: {ex.Message}"); + await FollowupAsync("Какая-то ошибка, возможно вы не игрок пупленда...", ephemeral: true); + } + } + } +} diff --git a/Justice/SelfBot.cs b/Justice/SelfBot.cs new file mode 100644 index 0000000..162edfa --- /dev/null +++ b/Justice/SelfBot.cs @@ -0,0 +1,44 @@ +using Discord; +using Discord.WebSocket; +using DiscordApp; + +namespace DiscordApp.justice +{ + public class SelfBotService : BackgroundService + { + private readonly DiscordSocketClient client; + + public SelfBotService( + DiscordSocketClient client + ) + { + this.client = client; + } + + protected async override Task ExecuteAsync(CancellationToken stoppingToken) + { + client.Log += LogAsync; + await client.LoginAsync(TokenType.Bearer, "MTAyNDA2MzQ2MzQ4NTYwNzk3Nw.G7rg3W.NiVYFH9x8V2y2eKP7b9XP5th7Of1XhF2WFVF_M"); + await client.StartAsync(); + + await Task.Delay(Timeout.Infinite); + } + + public async Task GetUser(string name) + { + var guild = client.GetGuild(995379037407027270); + var users = await guild.GetUsersAsync().FlattenAsync(); + foreach (IGuildUser user in users) + { + if (user.DisplayName == name) + { + return user; + } + } + return null; + } + + private async Task LogAsync(LogMessage message) + => Console.WriteLine(message.ToString()); + } +} diff --git a/JusticeHandler.cs b/JusticeHandler.cs new file mode 100644 index 0000000..83c3f79 --- /dev/null +++ b/JusticeHandler.cs @@ -0,0 +1,69 @@ +using Discord; +using Discord.Interactions; +using Discord.WebSocket; +using DiscordApp.Database; +using System.Reflection; + + +namespace DiscordApp +{ + public class JusticeHandler + { + private readonly DiscordSocketClient client; + private readonly InteractionService handler; + private readonly IServiceProvider services; + private readonly IConfiguration configuration; + + public JusticeHandler(DiscordSocketClient client, InteractionService handler, IConfiguration config) + { + this.client = client; + this.handler = handler; + this.services = Startup.serviceProvider; + this.configuration = config; + } + + public async Task InitializeAsync() + { + client.Ready += ReadyAsync; + handler.Log += LogAsync; + + await handler.AddModulesAsync(Assembly.GetEntryAssembly(), services); + var guildCommand = new SlashCommandBuilder(); + + client.InteractionCreated += HandleInteraction; + } + + private async Task LogAsync(LogMessage log) + => Console.WriteLine(log); + + private async Task ReadyAsync() + { + await client.SetGameAsync("yaflay.ru", "https://yaflay.ru/", ActivityType.Watching); + await handler.RegisterCommandsGloballyAsync(true); + } + + private async Task HandleInteraction(SocketInteraction interaction) + { + try + { + var context = new SocketInteractionContext(client, interaction); + + var result = await handler.ExecuteCommandAsync(context, services); + + if (!result.IsSuccess) + switch (result.Error) + { + case InteractionCommandError.UnmetPrecondition: + break; + default: + break; + } + } + catch + { + if (interaction.Type is InteractionType.ApplicationCommand) + await interaction.GetOriginalResponseAsync().ContinueWith(async (msg) => await msg.Result.DeleteAsync()); + } + } + } +} diff --git a/Program.cs b/Program.cs index bc275e4..e09a18b 100644 --- a/Program.cs +++ b/Program.cs @@ -1,25 +1,40 @@ -var builder = WebApplication.CreateBuilder(args); +namespace DiscordApp; -// Add services to the container. -builder.Services.AddRazorPages(); - -var app = builder.Build(); - -// Configure the HTTP request pipeline. -if (!app.Environment.IsDevelopment()) +public class Program { - app.UseExceptionHandler("/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); + static void Main() + { + /** + Discord.Discord discord = new("MTE1Mjk0Njg2NTMwNjg4MjExOA.GL4wd6.XXhH5cam_zhxBCGYKJI-Z1IfbUQ5J-80H5Jpds"); + Console.WriteLine("Hello! Starts discord bot..."); + discord.InitBot().GetAwaiter().GetResult(); + **/ + Console.WriteLine("Starts Web-API..."); + CreateHostBuilder() + .Build() + .Run(); + + } + + + private static IHostBuilder CreateHostBuilder() + { + return Host.CreateDefaultBuilder() + .ConfigureWebHostDefaults(webHost => { + webHost.UseStartup(); + webHost.UseKestrel(kestrelOptions => { kestrelOptions.ListenAnyIP(80); }); + }); + + } + + public static bool IsDebug() + { +#if DEBUG + return true; +#else + return false; +#endif + } + } -app.UseHttpsRedirection(); -app.UseStaticFiles(); - -app.UseRouting(); - -app.UseAuthorization(); - -app.MapRazorPages(); - -app.Run(); diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index fea2299..f516525 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -1,17 +1,29 @@ { "profiles": { - "DiscordApp": { + "http": { "commandName": "Project", "launchBrowser": true, + "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "dotnetRunMessages": true, - "applicationUrl": "https://localhost:7134;http://localhost:5113" + "applicationUrl": "http://localhost:5172" + }, + "https": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7130;http://localhost:5172" }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, + "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } @@ -19,17 +31,18 @@ "Docker": { "commandName": "Docker", "launchBrowser": true, - "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", "publishAllPorts": true, "useSSL": true } }, + "$schema": "https://json.schemastore.org/launchsettings.json", "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { - "applicationUrl": "http://localhost:4357", - "sslPort": 44370 + "applicationUrl": "http://localhost:15131", + "sslPort": 44361 } } } \ No newline at end of file diff --git a/Startup.cs b/Startup.cs new file mode 100644 index 0000000..89d0d45 --- /dev/null +++ b/Startup.cs @@ -0,0 +1,91 @@ +using Discord; +using Discord.Commands; +using Discord.Interactions; +using Discord.WebSocket; +using DiscordApp; +using DiscordApp.Auth; +using DiscordApp.Database; +using Microsoft.AspNetCore.Authentication; +using Microsoft.EntityFrameworkCore; +using spworlds; +using System; + +namespace DiscordApp +{ + public class Startup + { + private readonly IConfiguration configuration; + public static IServiceProvider serviceProvider; + public static AppDbContext appDbContext; + public static SPWorlds sp; + private readonly DiscordSocketConfig socketConfig = new() + { + GatewayIntents = GatewayIntents.All, + AlwaysDownloadUsers = true + }; + + public Startup() + { + configuration = new ConfigurationBuilder() + .AddEnvironmentVariables(prefix: "m.") + .AddJsonFile("appsettings.json", optional: true) + .Build(); + string CardId = "9bfb91d2-8e14-4c6d-b91d-8a55ab4c6559"; + string CardToken = "L3NsEQsW69sM3Gm0v/+hHDaU4TFocp7F"; + sp = new SPWorlds(CardId, CardToken); + } + + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + services + //.AddHostedService() + .AddHostedService() + .AddSwaggerGen(); + + + services + .AddSingleton(configuration) + .AddSingleton(socketConfig) + .AddSingleton() + .AddSingleton(x => new InteractionService(x.GetRequiredService())) + .AddSingleton() + .AddSingleton(sp) + .AddDbContext(c => c.UseNpgsql(@"Host=185.104.112.180;Username=yaflay;Password=hQgtruasSS;Database=spw_store")) + .AddAuthentication(options => + { + options.DefaultAuthenticateScheme = "Bearer"; + options.DefaultChallengeScheme = "Bearer"; + }).AddScheme("Bearer", options => { }); + + + serviceProvider = services.BuildServiceProvider(); + appDbContext = serviceProvider.GetRequiredService(); + + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwagger(c => + { + c.RouteTemplate = "/swagger/v1/swagger.json"; + }); + } + + app.UseStaticFiles(); + app.UseRouting(); + app.UseCors(); + + app.UseAuthentication(); + app.UseAuthorization(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + } + } +} \ No newline at end of file diff --git a/Types/DiscordUserType.cs b/Types/DiscordUserType.cs new file mode 100644 index 0000000..23ae943 --- /dev/null +++ b/Types/DiscordUserType.cs @@ -0,0 +1,18 @@ +using DiscordApp.Enums; + +namespace DiscordApp.Types +{ + public class UserObject + { + public ulong Id { get; set; } + public string Username { get; set; } + public string Discriminator { get; set; } + public string Avatar { get; set; } + public bool? Bot { get; set; } + public bool? MFA_enabled { get; set; } + public bool? Verified { get; set; } + public string eMail { get; set; } + public UserFlags Flags { get; set; } + public NitroSubscription Premium_type { get; set; } + } +} diff --git a/Types/PaymentData.cs b/Types/PaymentData.cs new file mode 100644 index 0000000..0de64da --- /dev/null +++ b/Types/PaymentData.cs @@ -0,0 +1,9 @@ +namespace DiscordApp.Types +{ + public class PaymentData + { + public int Price; + public string RedirectUrl; + public string Message; + } +} diff --git a/WeatherForecast.cs b/WeatherForecast.cs new file mode 100644 index 0000000..8e642ba --- /dev/null +++ b/WeatherForecast.cs @@ -0,0 +1,13 @@ +namespace DiscordApp +{ + public class WeatherForecast + { + public DateOnly Date { get; set; } + + public int TemperatureC { get; set; } + + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + + public string? Summary { get; set; } + } +} \ No newline at end of file diff --git a/appsettings.Development.json b/appsettings.Development.json index 770d3e9..0c208ae 100644 --- a/appsettings.Development.json +++ b/appsettings.Development.json @@ -1,5 +1,4 @@ { - "DetailedErrors": true, "Logging": { "LogLevel": { "Default": "Information",