add discord bot

change net6.0 net7.0
This commit is contained in:
Дмитрий Шиманский
2023-10-26 11:35:42 +03:00
parent 7c6fafa9e6
commit 9a8a4cad5d
35 changed files with 1132 additions and 37 deletions

8
Auth/ApiKeyTypes.cs Normal file
View File

@@ -0,0 +1,8 @@
namespace DiscordApp.Auth
{
public enum ApiKeyTypes
{
Public,
Private
}
}

View File

@@ -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<AuthenticationSchemeOptions>
{
private AppDbContext dbContext;
public AuthanticationByBearerToken(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
AppDbContext dbContext) : base(options, logger, encoder, clock)
{
this.dbContext = dbContext;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.TryGetValue("Authorization", out var apiKeyHeaderValues))
{
return AuthenticateResult.Fail("API Key was not provided.");
}
#pragma warning disable CS8602 // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
string providedApiKey = apiKeyHeaderValues
.FirstOrDefault().Replace("'", "");
if (CheckForInvalidCharacters(apiKeyHeaderValues)) return AuthenticateResult.Fail("Don`t use SQL injections, dog`s son");
#pragma warning restore CS8602 // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
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;
}
}
}

View File

@@ -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<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> 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();
}
}
}

18
Database/AppDbContext.cs Normal file
View File

@@ -0,0 +1,18 @@
using DiscordApp.Database.Tables;
using Microsoft.EntityFrameworkCore;
namespace DiscordApp.Database
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Passport> Passport { get; set; }
public DbSet<Autobranches> Autobranches { get; set; }
public DbSet<Autoreactions> Autoreactions { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

View File

@@ -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; }
}
}

40
Discord.cs Normal file
View File

@@ -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());
}
}

View File

@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>cff49f3b-b209-4bd8-b471-d297aaa3822e</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0-rc.2.23480.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
</Project>

View File

@@ -1,16 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>9e418d7f-fd52-4ff9-9673-969c3f62c78d</UserSecretsId> <UserSecretsId>392a6656-544a-410a-9be8-214215cd1cc8</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext> <DockerfileContext>.</DockerfileContext>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Discord.Net" Version="3.12.0" />
<PackageReference Include="Discord.Net.Commands" Version="3.12.0" />
<PackageReference Include="Discord.Net.Core" Version="3.12.0" />
<PackageReference Include="Discord.Net.Interactions" Version="3.12.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.13" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.18.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.11" />
<PackageReference Include="spworlds" Version="1.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.6.33723.286 VisualStudioVersion = 17.6.33723.286
MinimumVisualStudioVersion = 10.0.40219.1 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 EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -11,15 +11,15 @@ Global
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CDCCF9AF-D015-4E3A-8E1E-8151BB1C865B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {950F9F70-ACDF-459E-8013-8E9E5B3B410A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CDCCF9AF-D015-4E3A-8E1E-8151BB1C865B}.Debug|Any CPU.Build.0 = Debug|Any CPU {950F9F70-ACDF-459E-8013-8E9E5B3B410A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CDCCF9AF-D015-4E3A-8E1E-8151BB1C865B}.Release|Any CPU.ActiveCfg = Release|Any CPU {950F9F70-ACDF-459E-8013-8E9E5B3B410A}.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}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B6798D09-E12C-4F92-A0BE-CC5D14187AB8} SolutionGuid = {B1D04319-BFE6-4F69-9951-AA4AD2AE4E30}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -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. #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 WORKDIR /app
EXPOSE 80 EXPOSE 80
EXPOSE 443 EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src WORKDIR /src
COPY ["DiscordApp.csproj", "."] COPY ["DiscordApp.csproj", "."]
RUN dotnet restore "./DiscordApp.csproj" RUN dotnet restore "./DiscordApp.csproj"

22
Dockerfile.original Normal file
View File

@@ -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"]

View File

@@ -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
}
}

11
Enums/Supporter.cs Normal file
View File

@@ -0,0 +1,11 @@
namespace DiscordApp.Enums
{
public enum Supporter
{
None = 0,
FirstLvl = 1,
SecondLvl = 2,
ThirdLvl = 3
}
}

14
Enums/TransactionType.cs Normal file
View File

@@ -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
}
}

15
Enums/UserFlags.cs Normal file
View File

@@ -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
}
}

11
Enums/UserType.cs Normal file
View File

@@ -0,0 +1,11 @@
namespace DiscordApp.Enums
{
public enum UserType
{
Player = 0,
Banned = 1,
Courier = 2,
Moderator = 3,
Admin = 4,
}
}

70
InteractionHandler.cs Normal file
View File

@@ -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());
}
}
}
}

41
Justice.cs Normal file
View File

@@ -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());
}
}

View File

@@ -0,0 +1,27 @@
using Discord;
using Discord.Interactions;
namespace DiscordApp.Justice.Commands
{
public class Passports : InteractionModuleBase<SocketInteractionContext>
{
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);
}
}
}

View File

@@ -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<SocketInteractionContext>
{
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
}
}

57
Justice/Events/Events.cs Normal file
View File

@@ -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);
}
}
**/
}
}
}

View File

@@ -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<SocketInteractionContext>
{
[ComponentInteraction("newPassport")]
public async Task AplyWork()
=> await Context.Interaction.RespondWithModalAsync<NewPassportModal>("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($"<t:{toTime.ToUnixTimeSeconds()}:D>").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; }
}
}

View File

@@ -0,0 +1,33 @@
using Discord.Interactions;
namespace DiscordApp.Justice.Interactions
{
public class VerificateInteraction : InteractionModuleBase<SocketInteractionContext>
{
[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);
}
}
}
}

44
Justice/SelfBot.cs Normal file
View File

@@ -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<IGuildUser> 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());
}
}

69
JusticeHandler.cs Normal file
View File

@@ -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());
}
}
}
}

View File

@@ -1,25 +1,40 @@
var builder = WebApplication.CreateBuilder(args); namespace DiscordApp;
// Add services to the container. public class Program
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{ {
app.UseExceptionHandler("/Error"); static void Main()
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. {
app.UseHsts(); /**
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<Startup>();
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();

View File

@@ -1,17 +1,29 @@
{ {
"profiles": { "profiles": {
"DiscordApp": { "http": {
"commandName": "Project", "commandName": "Project",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}, },
"dotnetRunMessages": true, "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": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} }
@@ -19,17 +31,18 @@
"Docker": { "Docker": {
"commandName": "Docker", "commandName": "Docker",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"publishAllPorts": true, "publishAllPorts": true,
"useSSL": true "useSSL": true
} }
}, },
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": { "iisSettings": {
"windowsAuthentication": false, "windowsAuthentication": false,
"anonymousAuthentication": true, "anonymousAuthentication": true,
"iisExpress": { "iisExpress": {
"applicationUrl": "http://localhost:4357", "applicationUrl": "http://localhost:15131",
"sslPort": 44370 "sslPort": 44361
} }
} }
} }

91
Startup.cs Normal file
View File

@@ -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<DiscordBotService>()
.AddHostedService<JusticeBotService>()
.AddSwaggerGen();
services
.AddSingleton(configuration)
.AddSingleton(socketConfig)
.AddSingleton<DiscordSocketClient>()
.AddSingleton(x => new InteractionService(x.GetRequiredService<DiscordSocketClient>()))
.AddSingleton<JusticeHandler>()
.AddSingleton(sp)
.AddDbContext<AppDbContext>(c => c.UseNpgsql(@"Host=185.104.112.180;Username=yaflay;Password=hQgtruasSS;Database=spw_store"))
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Bearer";
options.DefaultChallengeScheme = "Bearer";
}).AddScheme<AuthenticationSchemeOptions, AuthanticationByBearerToken>("Bearer", options => { });
serviceProvider = services.BuildServiceProvider();
appDbContext = serviceProvider.GetRequiredService<AppDbContext>();
}
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();
});
}
}
}

18
Types/DiscordUserType.cs Normal file
View File

@@ -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; }
}
}

9
Types/PaymentData.cs Normal file
View File

@@ -0,0 +1,9 @@
namespace DiscordApp.Types
{
public class PaymentData
{
public int Price;
public string RedirectUrl;
public string Message;
}
}

13
WeatherForecast.cs Normal file
View File

@@ -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; }
}
}

View File

@@ -1,5 +1,4 @@
{ {
"DetailedErrors": true,
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",