Добавил фичи
All checks were successful
Local Deploy with Docker / build-and-deploy (push) Successful in 4s
All checks were successful
Local Deploy with Docker / build-and-deploy (push) Successful in 4s
This commit is contained in:
parent
931e01fcd6
commit
99df15fb31
@ -35,5 +35,5 @@ jobs:
|
|||||||
-e DATABASE_NAME=telegram_bot \
|
-e DATABASE_NAME=telegram_bot \
|
||||||
-e DATABASE_USER=postgres \
|
-e DATABASE_USER=postgres \
|
||||||
-e DATABASE_PASSWORD=${{ secrets.DB_PASSWORD }} \
|
-e DATABASE_PASSWORD=${{ secrets.DB_PASSWORD }} \
|
||||||
-e BOT_TOKEN=${{ secrets.BOT_TOKEN }} \
|
-e BotSettings_BotToken=${{ secrets.BOT_TOKEN }} \
|
||||||
telegram-bot:latest
|
telegram-bot:latest
|
||||||
|
72
Data/UserOfTheDayRepository.cs
Normal file
72
Data/UserOfTheDayRepository.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using System.Data;
|
||||||
|
using Dapper;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Npgsql;
|
||||||
|
using UserOfTheDayBot.Model;
|
||||||
|
|
||||||
|
namespace UserOfTheDayBot.Data;
|
||||||
|
|
||||||
|
public interface IUserOfTheDayRepository
|
||||||
|
{
|
||||||
|
Task RecordUserOfTheDayAsync(long chatId, long userId, DateTime date, UserOfTheDayType type);
|
||||||
|
Task<bool> IsUserOfTheDaySelectedAsync(long chatId, DateTime date, UserOfTheDayType type);
|
||||||
|
Task<bool> IsUserAlreadySelectedAsync(long chatId, DateTime date, long userId);
|
||||||
|
Task<Dictionary<(long userId, string userName), (int userOfTheDayCount, int loserOfTheDayCount)>> GetUserStatisticsAsync(long chatId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UserOfTheDayRepository : IUserOfTheDayRepository
|
||||||
|
{
|
||||||
|
private readonly string _connectionString;
|
||||||
|
|
||||||
|
public UserOfTheDayRepository(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_connectionString = configuration["DatabaseSettings:ConnectionString"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RecordUserOfTheDayAsync(long chatId, long userId, DateTime date, UserOfTheDayType type)
|
||||||
|
{
|
||||||
|
using (IDbConnection db = new NpgsqlConnection(_connectionString))
|
||||||
|
{
|
||||||
|
string query = "INSERT INTO user_of_the_day (chat_id, user_id, date, type) VALUES (@ChatId, @UserId, @Date, @Type)";
|
||||||
|
await db.ExecuteAsync(query, new { ChatId = chatId, UserId = userId, Date = date, Type = type });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IsUserOfTheDaySelectedAsync(long chatId, DateTime date, UserOfTheDayType type)
|
||||||
|
{
|
||||||
|
using (IDbConnection db = new NpgsqlConnection(_connectionString))
|
||||||
|
{
|
||||||
|
string query = "SELECT COUNT(1) FROM user_of_the_day WHERE chat_id = @ChatId AND date = @Date AND type = @Type";
|
||||||
|
return await db.ExecuteScalarAsync<bool>(query, new { ChatId = chatId, Date = date, Type = type });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> IsUserAlreadySelectedAsync(long chatId, DateTime date, long userId)
|
||||||
|
{
|
||||||
|
using (IDbConnection db = new NpgsqlConnection(_connectionString))
|
||||||
|
{
|
||||||
|
string query = "SELECT COUNT(1) FROM user_of_the_day WHERE chat_id = @ChatId AND date = @Date AND user_id = @UserId";
|
||||||
|
return await db.ExecuteScalarAsync<bool>(query, new { ChatId = chatId, Date = date, UserId = userId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<(long userId, string userName), (int userOfTheDayCount, int loserOfTheDayCount)>> GetUserStatisticsAsync(long chatId)
|
||||||
|
{
|
||||||
|
using (IDbConnection db = new NpgsqlConnection(_connectionString))
|
||||||
|
{
|
||||||
|
string query = @"SELECT u.user_id, u.user_name,
|
||||||
|
SUM(CASE WHEN ud.type = 0 THEN 1 ELSE 0 END) AS user_of_the_day_count,
|
||||||
|
SUM(CASE WHEN ud.type = 1 THEN 1 ELSE 0 END) AS loser_of_the_day_count
|
||||||
|
FROM user_of_the_day ud
|
||||||
|
JOIN users u ON ud.user_id = u.user_id AND ud.chat_id = u.chat_id
|
||||||
|
WHERE ud.chat_id = @ChatId
|
||||||
|
GROUP BY u.user_id, u.user_name";
|
||||||
|
|
||||||
|
var results = await db.QueryAsync<(long userId, string userName, int userOfTheDayCount, int loserOfTheDayCount)>(query, new { ChatId = chatId });
|
||||||
|
return results.ToDictionary(
|
||||||
|
row => (row.userId, row.userName),
|
||||||
|
row => (row.userOfTheDayCount, row.loserOfTheDayCount)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
Data/UserRepository.cs
Normal file
41
Data/UserRepository.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System.Data;
|
||||||
|
using Dapper;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Npgsql;
|
||||||
|
|
||||||
|
namespace UserOfTheDayBot.Data;
|
||||||
|
|
||||||
|
public interface IUserRepository
|
||||||
|
{
|
||||||
|
Task<int> RegisterUserAsync(long chatId, long userId, string userName);
|
||||||
|
Task<IEnumerable<(long userId, string userName)>> GetUsersWithNamesAsync(long chatId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UserRepository : IUserRepository
|
||||||
|
{
|
||||||
|
private readonly string _connectionString;
|
||||||
|
|
||||||
|
public UserRepository(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_connectionString = configuration["DatabaseSettings:ConnectionString"];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<int> RegisterUserAsync(long chatId, long userId, string userName)
|
||||||
|
{
|
||||||
|
using (IDbConnection db = new NpgsqlConnection(_connectionString))
|
||||||
|
{
|
||||||
|
string query = "INSERT INTO users (chat_id, user_id, user_name) VALUES (@ChatId, @UserId, @UserName) ON CONFLICT (chat_id, user_id) DO NOTHING";
|
||||||
|
return await db.ExecuteAsync(query, new { ChatId = chatId, UserId = userId, UserName = userName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<(long userId, string userName)>> GetUsersWithNamesAsync(long chatId)
|
||||||
|
{
|
||||||
|
using (IDbConnection db = new NpgsqlConnection(_connectionString))
|
||||||
|
{
|
||||||
|
string query = "SELECT user_id, user_name FROM users WHERE chat_id = @ChatId";
|
||||||
|
return await db.QueryAsync<(long, string)>(query, new { ChatId = chatId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Model/UserOfTheDayType.cs
Normal file
7
Model/UserOfTheDayType.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace UserOfTheDayBot.Model;
|
||||||
|
|
||||||
|
public enum UserOfTheDayType
|
||||||
|
{
|
||||||
|
UserOfTheDay = 0,
|
||||||
|
LoserOfTheDay = 1
|
||||||
|
}
|
100
Program.cs
100
Program.cs
@ -6,89 +6,37 @@ using Telegram.Bot;
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
using Dapper;
|
using Dapper;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
using Npgsql;
|
using Npgsql;
|
||||||
|
using UserOfTheDayBot.Data;
|
||||||
|
using UserOfTheDayBot.Services;
|
||||||
|
|
||||||
class Program
|
public class Program
|
||||||
{
|
{
|
||||||
private static string botToken = "7814259349:AAEasTnDpX5s5PrQcR5ihI9pOsmp2Ocv-m0"; // Укажите токен вашего бота
|
public static async Task Main(string[] args)
|
||||||
private static string connectionString = "Host=host.docker.internal;Port=5432;Database=telegram_bot;Username=postgres;Password=postgres";
|
|
||||||
|
|
||||||
private static readonly TelegramBotClient botClient = new TelegramBotClient(botToken);
|
|
||||||
|
|
||||||
static async Task Main(string[] args)
|
|
||||||
{
|
{
|
||||||
Console.WriteLine("Bot is running...");
|
var host = Host.CreateDefaultBuilder(args)
|
||||||
|
.ConfigureAppConfiguration((context, config) =>
|
||||||
// Управление токеном завершения
|
|
||||||
var cts = new CancellationTokenSource();
|
|
||||||
Console.CancelKeyPress += (_, _) => cts.Cancel();
|
|
||||||
|
|
||||||
botClient.StartReceiving(UpdateHandler, ErrorHandler, cancellationToken: cts.Token);
|
|
||||||
|
|
||||||
Console.WriteLine("Press Ctrl+C to exit...");
|
|
||||||
await Task.Delay(Timeout.Infinite, cts.Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task UpdateHandler(ITelegramBotClient bot, Update update, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Received an message");
|
|
||||||
|
|
||||||
if (update.Type == UpdateType.Message && update.Message?.Text != null)
|
|
||||||
{
|
|
||||||
var message = update.Message;
|
|
||||||
|
|
||||||
if (message.Text.StartsWith("/help"))
|
|
||||||
{
|
{
|
||||||
await bot.SendTextMessageAsync(message.Chat.Id, "Уйди. Попробуйте /reg", cancellationToken: cancellationToken);
|
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
|
||||||
}
|
config.AddEnvironmentVariables(); // Добавление переменных среды
|
||||||
else if (message.Text.StartsWith("/reg"))
|
})
|
||||||
|
.ConfigureServices((context, services) =>
|
||||||
{
|
{
|
||||||
await RegisterUser(message, cancellationToken);
|
services.AddSingleton<IUserRepository, UserRepository>();
|
||||||
}
|
services.AddSingleton<IUserOfTheDayRepository, UserOfTheDayRepository>();
|
||||||
else
|
services.AddSingleton<BotService>();
|
||||||
{
|
|
||||||
await bot.SendTextMessageAsync(message.Chat.Id, "Неизвестная команда. Попробуйте /reg", cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task RegisterUser(Message message, CancellationToken cancellationToken)
|
// TelegramBotClient зависит от IConfiguration для получения токена
|
||||||
{
|
services.AddSingleton<ITelegramBotClient>(provider =>
|
||||||
try
|
|
||||||
{
|
|
||||||
using (IDbConnection db = new NpgsqlConnection(connectionString))
|
|
||||||
{
|
|
||||||
string query = "INSERT INTO users (chat_id, user_id, user_name) VALUES (@ChatId, @UserId, @UserName) ON CONFLICT (chat_id, user_id) DO NOTHING";
|
|
||||||
|
|
||||||
var parameters = new
|
|
||||||
{
|
{
|
||||||
ChatId = message.Chat.Id,
|
var configuration = provider.GetRequiredService<IConfiguration>();
|
||||||
UserId = message.From.Id,
|
var botToken = configuration["BotSettings:BotToken"];
|
||||||
UserName = message.From.FirstName
|
return new TelegramBotClient(botToken);
|
||||||
};
|
});
|
||||||
|
})
|
||||||
int rowsAffected = await db.ExecuteAsync(query, parameters);
|
.Build();
|
||||||
|
|
||||||
if (rowsAffected > 0)
|
|
||||||
{
|
|
||||||
await botClient.SendTextMessageAsync(message.Chat.Id, "Вы успешно зарегистрированы!", cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await botClient.SendTextMessageAsync(message.Chat.Id, "Вы уже зарегистрированы.", cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
|
||||||
await botClient.SendTextMessageAsync(message.Chat.Id, "Произошла ошибка при регистрации. Попробуйте позже.", cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Task ErrorHandler(ITelegramBotClient bot, Exception exception, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: {exception.Message}");
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
187
Services/BotService.cs
Normal file
187
Services/BotService.cs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Telegram.Bot;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
|
using Telegram.Bot.Types.Enums;
|
||||||
|
using UserOfTheDayBot.Data;
|
||||||
|
using UserOfTheDayBot.Model;
|
||||||
|
|
||||||
|
namespace UserOfTheDayBot.Services;
|
||||||
|
|
||||||
|
public class BotService
|
||||||
|
{
|
||||||
|
private readonly ITelegramBotClient _botClient;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
private readonly IUserOfTheDayRepository _userOfTheDayRepository;
|
||||||
|
|
||||||
|
public BotService(IConfiguration configuration, IUserRepository userRepository, IUserOfTheDayRepository userOfTheDayRepository)
|
||||||
|
{
|
||||||
|
_botClient = new TelegramBotClient(configuration["BotSettings:BotToken"] ?? Environment.GetEnvironmentVariable("BotSettings_BotToken"));
|
||||||
|
_userRepository = userRepository;
|
||||||
|
_userOfTheDayRepository = userOfTheDayRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleUpdateAsync(Update update, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (update.Type == UpdateType.Message && update.Message?.Text != null)
|
||||||
|
{
|
||||||
|
var message = update.Message;
|
||||||
|
|
||||||
|
if (message.Text.StartsWith("/help"))
|
||||||
|
{
|
||||||
|
await _botClient.SendTextMessageAsync(message.Chat.Id, "Уйди. Попробуйте /reg", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
else if (message.Text.StartsWith("/reg"))
|
||||||
|
{
|
||||||
|
await RegisterUserAsync(message, cancellationToken);
|
||||||
|
}
|
||||||
|
else if (message.Text.StartsWith("/useroftheday"))
|
||||||
|
{
|
||||||
|
await HandleUserOfTheDayCommandAsync(message, UserOfTheDayType.UserOfTheDay, cancellationToken);
|
||||||
|
}
|
||||||
|
else if (message.Text.StartsWith("/loser"))
|
||||||
|
{
|
||||||
|
await HandleUserOfTheDayCommandAsync(message, UserOfTheDayType.LoserOfTheDay, cancellationToken);
|
||||||
|
}
|
||||||
|
else if (message.Text.StartsWith("/stat"))
|
||||||
|
{
|
||||||
|
await HandleStatCommandAsync(message, cancellationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _botClient.SendTextMessageAsync(message.Chat.Id, "Неизвестная команда. Попробуйте /reg", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RegisterUserAsync(Message message, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int rowsAffected = await _userRepository.RegisterUserAsync(message.Chat.Id, message.From.Id, message.From.FirstName);
|
||||||
|
|
||||||
|
if (rowsAffected > 0)
|
||||||
|
{
|
||||||
|
await _botClient.SendTextMessageAsync(message.Chat.Id, "Вы успешно зарегистрированы!", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _botClient.SendTextMessageAsync(message.Chat.Id, "Вы уже зарегистрированы.", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error: {ex.Message}");
|
||||||
|
await _botClient.SendTextMessageAsync(message.Chat.Id, "Произошла ошибка при регистрации. Попробуйте позже.", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleUserOfTheDayCommandAsync(Message message, UserOfTheDayType type, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var today = DateTime.UtcNow.Date;
|
||||||
|
var chatId = message.Chat.Id;
|
||||||
|
|
||||||
|
if (await _userOfTheDayRepository.IsUserOfTheDaySelectedAsync(chatId, today, type))
|
||||||
|
{
|
||||||
|
var responseMessage = type == UserOfTheDayType.UserOfTheDay ? "Пользователь дня уже выбран." : "Неудачник дня уже выбран.";
|
||||||
|
await _botClient.SendTextMessageAsync(chatId, responseMessage, cancellationToken: cancellationToken);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedUser = await SelectUserOfTheDayAsync(chatId, today, type);
|
||||||
|
|
||||||
|
if (selectedUser.HasValue)
|
||||||
|
{
|
||||||
|
var responseMessage = type == UserOfTheDayType.UserOfTheDay ? "Пользователь дня" : "Неудачник дня";
|
||||||
|
await _botClient.SendTextMessageAsync(chatId, $"{responseMessage}: {selectedUser.Value}", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _botClient.SendTextMessageAsync(chatId, "В чате нет зарегистрированных пользователей.", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error: {ex.Message}");
|
||||||
|
await _botClient.SendTextMessageAsync(message.Chat.Id, "Произошла ошибка при выборе пользователя дня. Попробуйте позже.", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<long?> SelectUserOfTheDayAsync(long chatId, DateTime date, UserOfTheDayType type)
|
||||||
|
{
|
||||||
|
var users = (await _userRepository.GetUsersWithNamesAsync(chatId)).ToList();
|
||||||
|
|
||||||
|
if (users.Any())
|
||||||
|
{
|
||||||
|
using (var rng = RandomNumberGenerator.Create())
|
||||||
|
{
|
||||||
|
while (users.Count > 0)
|
||||||
|
{
|
||||||
|
var randomIndex = GetRandomIndex(users.Count, rng);
|
||||||
|
var selectedUser = users[randomIndex];
|
||||||
|
|
||||||
|
if (!await _userOfTheDayRepository.IsUserAlreadySelectedAsync(chatId, date, selectedUser.userId))
|
||||||
|
{
|
||||||
|
await _userOfTheDayRepository.RecordUserOfTheDayAsync(chatId, selectedUser.userId, date, type);
|
||||||
|
return selectedUser.userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
users.RemoveAt(randomIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleStatCommandAsync(Message message, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var chatId = message.Chat.Id;
|
||||||
|
var stats = await _userOfTheDayRepository.GetUserStatisticsAsync(chatId);
|
||||||
|
|
||||||
|
if (stats.Any())
|
||||||
|
{
|
||||||
|
var userOfTheDaySection = "Пользователь дня:\n";
|
||||||
|
var loserOfTheDaySection = "Неудачник дня:\n";
|
||||||
|
|
||||||
|
var sortedUserOfTheDay = stats.OrderByDescending(x => x.Value.userOfTheDayCount);
|
||||||
|
var sortedLoserOfTheDay = stats.OrderByDescending(x => x.Value.loserOfTheDayCount);
|
||||||
|
|
||||||
|
foreach (var stat in sortedUserOfTheDay)
|
||||||
|
{
|
||||||
|
userOfTheDaySection += $"{stat.Key.userName}: {stat.Value.userOfTheDayCount} раз(а)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var stat in sortedLoserOfTheDay)
|
||||||
|
{
|
||||||
|
loserOfTheDaySection += $"{stat.Key.userName}: {stat.Value.loserOfTheDayCount} раз(а)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = userOfTheDaySection + "\n" + loserOfTheDaySection;
|
||||||
|
|
||||||
|
await _botClient.SendTextMessageAsync(chatId, response, cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _botClient.SendTextMessageAsync(chatId, "Нет данных о пользователях.", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error: {ex.Message}");
|
||||||
|
await _botClient.SendTextMessageAsync(message.Chat.Id, "Произошла ошибка при получении статистики. Попробуйте позже.", cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetRandomIndex(int max, RandomNumberGenerator rng)
|
||||||
|
{
|
||||||
|
var buffer = new byte[4];
|
||||||
|
rng.GetBytes(buffer);
|
||||||
|
var randomValue = BitConverter.ToUInt32(buffer, 0);
|
||||||
|
return (int)(randomValue % max);
|
||||||
|
}
|
||||||
|
}
|
8
appsettings.json
Normal file
8
appsettings.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"BotSettings": {
|
||||||
|
"BotToken": "7571336725:AAGkzgAricQPWWsAinDCDKZivomXXy36Qpo"
|
||||||
|
},
|
||||||
|
"DatabaseSettings": {
|
||||||
|
"ConnectionString": "Host=host.docker.internal;Port=5432;Database=telegram_bot;Username=postgres;Password=postgres"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user