TelegramBot: add method to work with the database

This commit is contained in:
Slavasil 2025-04-20 22:22:07 +03:00
parent 330abb90ff
commit a457ea1a19
7 changed files with 227 additions and 7 deletions

View File

@ -5,7 +5,8 @@ namespace SimpleTGBot;
internal class Config
{
public const string DEFAULT_BOT_TOKEN_FILENAME = "telegram_token.txt";
public const string DEFAULT_DATABASE_FILENAME = "demotivatorbot.db";
public static string? TryReadBotTokenFile()
{
try

View File

@ -1,4 +1,5 @@
using Telegram.Bot.Types.ReplyMarkups;
using System.Text;
using Telegram.Bot.Types.ReplyMarkups;
namespace SimpleTGBot;
@ -28,6 +29,8 @@ internal static class Interactions
public static readonly IReplyMarkup resultActionReplyMarkup = new ReplyKeyboardMarkup([new KeyboardButton(doneButtonText)]);
public static readonly IReplyMarkup settingsReplyMarkup = new ReplyKeyboardMarkup([[new KeyboardButton(gotoPresetsButtonText)], [new KeyboardButton(backButtonText)]]);
static readonly string[] digitEmojis = ["0⃣", "1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣"];
public static bool IsStartCommand(string message)
{
return message.Split(' ').FirstOrDefault() == "/start";
@ -55,4 +58,33 @@ internal static class Interactions
{
return message == backButtonText;
}
public static string MakePresetListMessage(string[] presetNames)
{
StringBuilder msg = new StringBuilder();
msg.Append("Твои сохранённые стили:\n");
for (int i = 0; i < presetNames.Length; i++)
{
msg.Append(DigitsToEmoji((i + 1).ToString()));
msg.Append(' ');
msg.Append(presetNames[i]);
msg.Append('\n');
}
if (presetNames.Length == 0)
{
msg.Append("<пусто>");
}
msg.Append("\n");
return msg.ToString();
}
public static string DigitsToEmoji(string s)
{
StringBuilder sb = new StringBuilder(s.Length * 4);
foreach (char digit in s)
{
sb.Append(digitEmojis[digit - '0']);
}
return sb.ToString();
}
}

View File

@ -13,7 +13,7 @@ public record DemotivatorStyle
public float Padding { get; set; }
public float OuterMargin { get; set; }
public float CaptionSpacing { get; set; }
public float Wtf1 { get; set; }
public float AdditionalTextWidth { get; set; }
public Color OutlineColor { get; set; }
public Color TitleColor { get; set; }
public Color SubtitleColor { get; set; }

View File

@ -1,4 +1,5 @@
using System.Text;
using Microsoft.Data.Sqlite;
using SimpleTGBot.Logging;
namespace SimpleTGBot;
@ -16,6 +17,11 @@ public static class Program
// Православная кодировка
Console.OutputEncoding = Encoding.UTF8;
using SqliteConnection db = new("Data Source=" + Config.DEFAULT_DATABASE_FILENAME);
db.Open();
PrepareDatabaseTables(db);
string? botToken = Config.TryReadBotTokenFile();
if (botToken == null)
@ -33,10 +39,29 @@ public static class Program
using (Logger logger = new Logger())
{
logger.Sinks.Add(new StdoutSink());
TelegramBot telegramBot = new TelegramBot(botToken, logger);
TelegramBot telegramBot = new TelegramBot(botToken, logger, db);
await telegramBot.Run();
}
db.Close();
return 0;
}
static void PrepareDatabaseTables(SqliteConnection db)
{
var cmd = db.CreateCommand();
cmd.CommandText = "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, selected_preset INTEGER)";
cmd.ExecuteNonQuery();
cmd = db.CreateCommand();
cmd.CommandText = @"CREATE TABLE IF NOT EXISTS user_presets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
name TEXT,
outline_color INTEGER,
title_color INTEGER,
subtitle_color INTEGER)";
cmd.ExecuteNonQuery();
}
}

View File

@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.4" />
<PackageReference Include="System.Drawing.Common" Version="9.0.4" />
<PackageReference Include="Telegram.Bot" Version="19.0.0-preview.2" />
</ItemGroup>

View File

@ -1,4 +1,6 @@
using SimpleTGBot.Logging;
using System.Drawing;
using Microsoft.Data.Sqlite;
using SimpleTGBot.Logging;
using SimpleTGBot.MemeGen;
using Telegram.Bot;
using Telegram.Bot.Exceptions;
@ -12,17 +14,19 @@ internal class TelegramBot
{
private string token;
private Logger logger;
private SqliteConnection database;
private Dictionary<long, DialogData> dialogs;
private TempStorage temp;
private HttpClient httpClient;
public TelegramBot(string token, Logger logger)
public TelegramBot(string token, Logger logger, SqliteConnection db)
{
this.token = token;
this.logger = logger;
dialogs = new Dictionary<long, DialogData>();
temp = new TempStorage();
httpClient = new HttpClient();
database = db;
}
/// <summary>
@ -72,12 +76,17 @@ internal class TelegramBot
{
if (update.Message is not { } message) return;
if (message.Chat.Type != ChatType.Private) return;
if (message.From is not { } user) return;
DialogData dialogData;
if (!dialogs.ContainsKey(message.Chat.Id))
{
dialogData = new DialogData() { state = DialogState.Initial };
dialogs[message.Chat.Id] = dialogData;
if (!await IsUserInDatabase(user))
{
await AddUserToDatabase(user);
}
} else
{
dialogData = dialogs[message.Chat.Id];
@ -203,7 +212,7 @@ internal class TelegramBot
{
replied = true;
dialogData.state = DialogState.ViewingPresets;
await botClient.SendTextMessageAsync(message.Chat.Id, "<заглушка>", replyMarkup: Interactions.backButtonReplyMarkup);
await botClient.SendTextMessageAsync(message.Chat.Id, Interactions.MakePresetListMessage((await GetUserPresets(user)).Select(preset => preset.Name).ToArray()), replyMarkup: Interactions.backButtonReplyMarkup);
}
else if (messageText == Interactions.backButtonText)
{
@ -330,6 +339,135 @@ internal class TelegramBot
temp.deleteTemporaryFile(dialogData.inputPictureFilename);
}
async Task AddUserToDatabase(User u)
{
var cmd = database.CreateCommand();
cmd.CommandText = "INSERT INTO users (id) VALUES ($1)";
cmd.Parameters.AddWithValue("$1", u.Id);
await cmd.ExecuteNonQueryAsync();
cmd = database.CreateCommand();
UserPreset defaultPreset = UserPreset.Default();
defaultPreset.OwnerId = u.Id;
await AddPresetToDatabase(defaultPreset);
}
async Task AddPresetToDatabase(UserPreset p)
{
var cmd = database.CreateCommand();
cmd.CommandText = "INSERT INTO user_presets (user_id, name, outline_color, title_color, subtitle_color) VALUES ($1, $2, $3, $4, $5)";
cmd.Parameters.AddWithValue("$1", p.OwnerId);
cmd.Parameters.AddWithValue("$2", p.Name);
cmd.Parameters.AddWithValue("$3", (long)p.OutlineColor.ToArgb() & 0xFFFFFFL);
cmd.Parameters.AddWithValue("$4", (long)p.TitleColor.ToArgb() & 0xFFFFFFL);
cmd.Parameters.AddWithValue("$5", (long)p.SubtitleColor.ToArgb() & 0xFFFFFFL);
await cmd.ExecuteNonQueryAsync();
}
async Task<bool> IsUserInDatabase(User u)
{
var cmd = database.CreateCommand();
cmd.CommandText = "SELECT id FROM users WHERE id = $1";
cmd.Parameters.AddWithValue("$1", u.Id);
using var reader = await cmd.ExecuteReaderAsync();
return await reader.ReadAsync();
}
async Task<UserPreset[]> GetUserPresets(User u)
{
var cmd = database.CreateCommand();
cmd.CommandText = "SELECT id, user_id, name, outline_color, title_color, subtitle_color FROM user_presets WHERE id = $1";
cmd.Parameters.AddWithValue("$1", u.Id);
using var reader = await cmd.ExecuteReaderAsync();
List<UserPreset> result = new List<UserPreset>();
while (reader.Read())
{
result.Add(new UserPreset()
{
Id = reader.GetInt64(0),
OwnerId = reader.GetInt64(1),
Name = reader.GetString(2),
OutlineColor = System.Drawing.Color.FromArgb((int)(0xff000000L | reader.GetInt64(3))),
TitleColor = System.Drawing.Color.FromArgb((int)(0xff000000L | reader.GetInt64(4))),
SubtitleColor = System.Drawing.Color.FromArgb((int)(0xff000000L | reader.GetInt64(5))),
});
}
return result.ToArray();
}
async Task<UserPreset?> GetUserPresetByName(User u, string name)
{
var cmd = database.CreateCommand();
cmd.CommandText = "SELECT id, outline_color, title_color, subtitle_color FROM user_presets WHERE name = $1";
cmd.Parameters.AddWithValue("$1", name);
using (var reader = await cmd.ExecuteReaderAsync())
{
if (reader.Read())
{
return new UserPreset()
{
Id = reader.GetInt64(0),
OwnerId = u.Id,
Name = name,
OutlineColor = System.Drawing.Color.FromArgb((int)(0xff000000L | reader.GetInt64(1))),
TitleColor = System.Drawing.Color.FromArgb((int)(0xff000000L | reader.GetInt64(2))),
SubtitleColor = System.Drawing.Color.FromArgb((int)(0xff000000L | reader.GetInt64(3))),
};
}
else
{
return null;
}
}
}
async Task DeleteUserPreset(long id)
{
var cmd = database.CreateCommand();
cmd.CommandText = "DELETE FROM user_presets WHERE id = $1";
cmd.Parameters.AddWithValue("$1", id);
cmd.ExecuteNonQuery();
}
async Task<UserPreset> GetActiveUserPreset(User u)
{
var cmd = database.CreateCommand();
cmd.CommandText = "SELECT selected_preset FROM users WHERE id = $1";
cmd.Parameters.AddWithValue("$1", u.Id);
int activePreset = -1;
using (var reader = await cmd.ExecuteReaderAsync()) {
if (reader.Read())
{
activePreset = reader.GetInt32(0);
} else
{
throw new Exception("пользователь не найден");
}
}
cmd = database.CreateCommand();
cmd.CommandText = "SELECT name, outline_color, title_color, subtitle_color FROM user_presets WHERE id = $1";
cmd.Parameters.AddWithValue("$1", activePreset);
using (var reader = await cmd.ExecuteReaderAsync())
{
if (reader.Read())
{
return new UserPreset()
{
Id = activePreset,
OwnerId = u.Id,
Name = reader.GetString(0),
OutlineColor = System.Drawing.Color.FromArgb((int)(0xff000000L | reader.GetInt64(1))),
TitleColor = System.Drawing.Color.FromArgb((int)(0xff000000L | reader.GetInt64(2))),
SubtitleColor = System.Drawing.Color.FromArgb((int)(0xff000000L | reader.GetInt64(3))),
};
} else
{
throw new Exception("выбранный пресет пользователя " + u.Id + " не найден");
}
}
}
/// <summary>
/// Обработчик исключений, возникших при работе бота
/// </summary>

23
SimpleTGBot/UserPreset.cs Normal file
View File

@ -0,0 +1,23 @@
using System.Drawing;
namespace SimpleTGBot;
internal struct UserPreset
{
public long Id;
public long OwnerId;
public string Name;
public Color OutlineColor;
public Color TitleColor;
public Color SubtitleColor;
public static UserPreset Default() => new UserPreset()
{
Id = 0,
OwnerId = 0,
Name = "По умолчанию",
OutlineColor = Color.FromArgb(255, 255, 255, 255),
TitleColor = Color.FromArgb(255, 255, 255, 255),
SubtitleColor = Color.FromArgb(255, 255, 255, 255),
};
}