Сильно переделанная версия, добавлены избранные контакты, отправка фото и т.п.
This commit is contained in:
+6
-2
@@ -3,6 +3,7 @@
|
|||||||
public class EmployeeContact
|
public class EmployeeContact
|
||||||
{
|
{
|
||||||
public static string GeneralPhoneNumber => "+78123352577";
|
public static string GeneralPhoneNumber => "+78123352577";
|
||||||
|
|
||||||
public EmployeeContact(Employee employee)
|
public EmployeeContact(Employee employee)
|
||||||
{
|
{
|
||||||
FullName = employee.FullName;
|
FullName = employee.FullName;
|
||||||
@@ -20,7 +21,9 @@ public class EmployeeContact
|
|||||||
Department = employee.Department;
|
Department = employee.Department;
|
||||||
Position = employee.Position;
|
Position = employee.Position;
|
||||||
ExtensionNumber = employee.Phone ?? null; //string.IsNullOrEmpty(employee.Phone) ? null : employee.Phone;
|
ExtensionNumber = employee.Phone ?? null; //string.IsNullOrEmpty(employee.Phone) ? null : employee.Phone;
|
||||||
Phone = string.IsNullOrEmpty(ExtensionNumber) ? GeneralPhoneNumber : $"{GeneralPhoneNumber},{ExtensionNumber}";
|
Phone = string.IsNullOrEmpty(ExtensionNumber)
|
||||||
|
? GeneralPhoneNumber
|
||||||
|
: $"{GeneralPhoneNumber},{ExtensionNumber}";
|
||||||
if (!string.IsNullOrEmpty(employee.Mobile))
|
if (!string.IsNullOrEmpty(employee.Mobile))
|
||||||
{
|
{
|
||||||
Mobile = employee.Mobile;
|
Mobile = employee.Mobile;
|
||||||
@@ -34,7 +37,8 @@ public class EmployeeContact
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
string text = "BEGIN:VCARD\n"
|
string text =
|
||||||
|
"BEGIN:VCARD\n"
|
||||||
+ "VERSION:2.1\n"
|
+ "VERSION:2.1\n"
|
||||||
+ $"N:{LastName};{FirstName}\n"
|
+ $"N:{LastName};{FirstName}\n"
|
||||||
+ $"FN:{FullName}\n"
|
+ $"FN:{FullName}\n"
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using StackExchange.Redis;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace nsszcontactbot;
|
||||||
|
public class FavoriteContactsManager
|
||||||
|
{
|
||||||
|
private readonly IDatabase _redisDb;
|
||||||
|
private const string KeyPrefix = "user:favorites:";
|
||||||
|
|
||||||
|
public FavoriteContactsManager(ConnectionMultiplexer redis)
|
||||||
|
{
|
||||||
|
_redisDb = redis.GetDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавить контакт в избранное.
|
||||||
|
/// </summary>
|
||||||
|
public async Task AddFavoriteAsync(long userId, string contactId)
|
||||||
|
{
|
||||||
|
string key = GetRedisKey(userId);
|
||||||
|
await _redisDb.SetAddAsync(key, contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удалить контакт из избранного.
|
||||||
|
/// </summary>
|
||||||
|
public async Task RemoveFavoriteAsync(long userId, string contactId)
|
||||||
|
{
|
||||||
|
string key = GetRedisKey(userId);
|
||||||
|
await _redisDb.SetRemoveAsync(key, contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Проверить, является ли контакт избранным.
|
||||||
|
/// </summary>
|
||||||
|
public async Task<bool> IsFavoriteAsync(long userId, string contactId)
|
||||||
|
{
|
||||||
|
string key = GetRedisKey(userId);
|
||||||
|
return await _redisDb.SetContainsAsync(key, contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить список всех избранных контактов пользователя.
|
||||||
|
/// </summary>
|
||||||
|
public async Task<List<string>> GetAllFavoritesAsync(long userId)
|
||||||
|
{
|
||||||
|
string key = GetRedisKey(userId);
|
||||||
|
var members = await _redisDb.SetMembersAsync(key);
|
||||||
|
return members.Select(m => m.ToString()).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRedisKey(long userId) => $"{KeyPrefix}{userId}";
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Telegram.Bot.Types.ReplyMarkups;
|
||||||
|
|
||||||
|
namespace nsszcontactbot
|
||||||
|
{
|
||||||
|
internal static class InlineKeyboardMarkupExtensions
|
||||||
|
{
|
||||||
|
internal static InlineKeyboardMarkup AddCloseButton(this InlineKeyboardMarkup markup, bool newRow = true)
|
||||||
|
{
|
||||||
|
var buttonRow = newRow ? markup.AddNewRow() : markup;
|
||||||
|
return buttonRow.AddButton("❌ Закрыть", "close");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+388
-108
@@ -4,6 +4,16 @@ using Telegram.Bot.Polling;
|
|||||||
using Telegram.Bot.Types;
|
using Telegram.Bot.Types;
|
||||||
using Telegram.Bot.Types.Enums;
|
using Telegram.Bot.Types.Enums;
|
||||||
using Telegram.Bot.Types.ReplyMarkups;
|
using Telegram.Bot.Types.ReplyMarkups;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog;
|
||||||
|
using System.Timers;
|
||||||
|
using Serilog.Core;
|
||||||
|
using NRedisStack;
|
||||||
|
using NRedisStack.RedisStackCommands;
|
||||||
|
|
||||||
|
using Timer = System.Timers.Timer;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
namespace nsszcontactbot;
|
namespace nsszcontactbot;
|
||||||
|
|
||||||
@@ -12,17 +22,45 @@ public class Program
|
|||||||
private static ITelegramBotClient Bot;
|
private static ITelegramBotClient Bot;
|
||||||
private static List<Employee> Employees = new();
|
private static List<Employee> Employees = new();
|
||||||
private static List<string> Departments = new();
|
private static List<string> Departments = new();
|
||||||
private static int CurrentPage = 0; // Текущая страница для пагинации
|
private static IConfigurationRoot config;
|
||||||
private static int PageSize = 5; // Количество подразделений на странице
|
private static FavoriteContactsManager FavoritesManager;
|
||||||
|
//private static ILogger<Program> Logger;
|
||||||
|
|
||||||
public static async Task Main(string[] args)
|
public static async Task<int> Main(string[] args)
|
||||||
{
|
{
|
||||||
Bot = new TelegramBotClient("6237449447:AAEGMmpx-1hUEApFZZS_ySAMZErseKJ8dHo"); // Укажите ваш токен
|
config = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(config).CreateLogger();
|
||||||
|
|
||||||
|
var botToken = config["Telegram:BotToken"];
|
||||||
|
if (botToken == null)
|
||||||
|
{
|
||||||
|
Log.Error("Токен Telegram-бота не указан в конфигурации.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(config["Redis:Configuration"]!, (conf) =>
|
||||||
|
{
|
||||||
|
conf.User = config["Redis:User"];
|
||||||
|
conf.Password = config["Redis:Password"];
|
||||||
|
});
|
||||||
|
|
||||||
|
FavoritesManager = new FavoriteContactsManager(redis);
|
||||||
|
Bot = new TelegramBotClient(botToken);
|
||||||
List<BotCommand> cmds = new();
|
List<BotCommand> cmds = new();
|
||||||
await Bot.SetMyCommandsAsync(cmds);
|
await Bot.SetMyCommands(cmds);
|
||||||
LoadEmployees();
|
if(!LoadEmployees())
|
||||||
var me = await Bot.GetMeAsync();
|
{
|
||||||
Console.WriteLine($"Бот запущен: @{me.Username}");
|
return 1;
|
||||||
|
}
|
||||||
|
StartUpdatingEmployeesData();
|
||||||
|
|
||||||
|
var me = await Bot.GetMe();
|
||||||
|
|
||||||
|
Log.Information($"Бот запущен: @{me.Username}");
|
||||||
|
|
||||||
// Запуск обработки обновлений
|
// Запуск обработки обновлений
|
||||||
var cancellationToken = new CancellationTokenSource().Token;
|
var cancellationToken = new CancellationTokenSource().Token;
|
||||||
@@ -31,29 +69,40 @@ public class Program
|
|||||||
{
|
{
|
||||||
AllowedUpdates = Array.Empty<UpdateType>() // receive all update types except ChatMember related updates
|
AllowedUpdates = Array.Empty<UpdateType>() // receive all update types except ChatMember related updates
|
||||||
};
|
};
|
||||||
Bot.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions: receiverOptions, cancellationToken: cancellationToken);
|
Bot.StartReceiving(
|
||||||
|
HandleUpdateAsync,
|
||||||
|
HandleErrorAsync,
|
||||||
|
receiverOptions: receiverOptions,
|
||||||
|
cancellationToken: cancellationToken
|
||||||
|
);
|
||||||
|
|
||||||
Console.WriteLine("Нажмите Enter для выхода...");
|
Console.WriteLine("Нажмите Enter для выхода...");
|
||||||
Console.ReadLine();
|
Console.ReadLine();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
|
private static async Task HandleUpdateAsync(
|
||||||
|
ITelegramBotClient botClient,
|
||||||
|
Update update,
|
||||||
|
CancellationToken cancellationToken
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (update.Type == UpdateType.Message && update.Message?.Text != null)
|
if (update.Type == UpdateType.Message && update.Message?.Text != null)
|
||||||
{
|
{
|
||||||
var message = update.Message;
|
var message = update.Message;
|
||||||
|
Log.Debug($"INPUT: from={message.From?.Username} text={message.Text}");
|
||||||
|
|
||||||
if (message.Text.StartsWith("/start"))
|
if (message.Text.StartsWith("/start"))
|
||||||
{
|
{
|
||||||
await StartCommand(message);
|
await StartCommand(message);
|
||||||
}
|
}
|
||||||
else if (message.Text.StartsWith("/choose_department"))
|
else if (message.Text.EndsWith("Список подразделений"))
|
||||||
{
|
{
|
||||||
await ChooseDepartment(message);
|
await ChooseDepartment(message);
|
||||||
}
|
}
|
||||||
else if (message.ReplyToMessage != null && message.ReplyToMessage.Text!.StartsWith("Выберите подразделение"))
|
else if (message.Text.EndsWith("Избранные контакты"))
|
||||||
{
|
{
|
||||||
await HandleDepartmentSelection(message);
|
await HandleShowFavorites(message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -74,57 +123,82 @@ public class Program
|
|||||||
await HandleAddContact(update.CallbackQuery, dataParts[1]);
|
await HandleAddContact(update.CallbackQuery, dataParts[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "addfavorite":
|
||||||
|
{
|
||||||
|
if (dataParts.Length != 2)
|
||||||
|
break;
|
||||||
|
await HandleAddFavorite(update.CallbackQuery, dataParts[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "delfavorite":
|
||||||
|
{
|
||||||
|
if (dataParts.Length != 2)
|
||||||
|
break;
|
||||||
|
await HandleDelFavorite(update.CallbackQuery, dataParts[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "showdepartment":
|
||||||
|
{
|
||||||
|
if (dataParts.Length != 2)
|
||||||
|
break;
|
||||||
|
await HandleShowDepartment(update.CallbackQuery, int.Parse(dataParts[1]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "showemployee":
|
||||||
|
{
|
||||||
|
if (dataParts.Length != 2)
|
||||||
|
break;
|
||||||
|
await HandleShowEmployee(update.CallbackQuery, dataParts[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "close":
|
||||||
|
{
|
||||||
|
await HandleClose(
|
||||||
|
update.CallbackQuery,
|
||||||
|
dataParts.Length > 1 ? dataParts[1] : null
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task StartCommand(Message message)
|
private static async Task StartCommand(Message message)
|
||||||
{
|
{
|
||||||
string text = "Привет! Я бот для поиска контактов сотрудников. Введите запрос.\n";
|
string text = "Привет! Я бот для поиска контактов сотрудников. Введите критерии поиска или воспользуйтесь кнопками внизу.\n";
|
||||||
//text += "/choose_department - Выбрать подразделение\n";
|
await Bot.SendMessage(message.Chat.Id, text, replyMarkup: new string[] { "⭐️ Избранные контакты", "🏢 Список подразделений" });
|
||||||
await Bot.SendTextMessageAsync(message.Chat.Id, text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ChooseDepartment(Message message)
|
private static async Task ChooseDepartment(Message message)
|
||||||
{
|
{
|
||||||
Departments = Employees.Select(e => e.Department).Distinct().ToList();
|
Departments = Employees.Select(e => e.Department).Distinct().ToList();
|
||||||
CurrentPage = 0; // Сброс страницы
|
|
||||||
await ShowDepartments(message.Chat.Id);
|
await ShowDepartments(message.Chat.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ShowDepartments(long chatId)
|
private static async Task ShowDepartments(long chatId)
|
||||||
{
|
{
|
||||||
var totalDepartments = Departments.Count;
|
string text = "Выберите подразделение:";
|
||||||
var totalPages = (int)Math.Ceiling((double)totalDepartments / PageSize);
|
var keyboardMarkup = new InlineKeyboardMarkup();
|
||||||
var departmentsToShow = Departments.Skip(CurrentPage * PageSize).Take(PageSize).ToList();
|
|
||||||
|
|
||||||
string text = "Выберите подразделение:\n";
|
var departmentIndex = 0;
|
||||||
text += string.Join("\n", departmentsToShow.Select((d, i) => $"{i + 1 + CurrentPage * PageSize}. {d}"));
|
foreach (var department in Departments)
|
||||||
|
|
||||||
// Создание кнопок
|
|
||||||
var inlineKeyboard = new List<List<InlineKeyboardButton>>();
|
|
||||||
if (CurrentPage > 0)
|
|
||||||
{
|
{
|
||||||
inlineKeyboard.Add(new List<InlineKeyboardButton>
|
keyboardMarkup
|
||||||
{
|
.AddNewRow()
|
||||||
InlineKeyboardButton.WithCallbackData("◀️ Назад", "prev")
|
.AddButton($"{department}", $"showdepartment/{departmentIndex++}");
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (CurrentPage < totalPages - 1)
|
//keyboardMarkup.AddCloseButton();
|
||||||
{
|
await Bot.SendMessage(chatId, text, replyMarkup: keyboardMarkup);
|
||||||
inlineKeyboard.Add(new List<InlineKeyboardButton>
|
await Task.Delay(999);
|
||||||
{
|
|
||||||
InlineKeyboardButton.WithCallbackData("Вперед ▶️", "next")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var keyboardMarkup = new InlineKeyboardMarkup(inlineKeyboard);
|
|
||||||
|
|
||||||
await Bot.SendTextMessageAsync(chatId, text, replyMarkup: keyboardMarkup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task HandleSearchInput(Message message)
|
private static async Task HandleSearchInput(Message message)
|
||||||
@@ -132,23 +206,48 @@ public class Program
|
|||||||
if (!string.IsNullOrEmpty(message.Text))
|
if (!string.IsNullOrEmpty(message.Text))
|
||||||
{
|
{
|
||||||
string query = message.Text.Trim().ToLower();
|
string query = message.Text.Trim().ToLower();
|
||||||
if (query.Length < 3)
|
if (query.Length < 4)
|
||||||
{
|
{
|
||||||
await Bot.SendTextMessageAsync(message.Chat.Id, "Минимальная длина строки поиска - 3 символа.");
|
await Bot.SendMessage(
|
||||||
|
message.Chat.Id,
|
||||||
|
"Минимальная длина строки поиска - 4 символа."
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Поиск сотрудников по полям
|
// Поиск сотрудников по полям
|
||||||
var results = Employees.Where(e =>
|
var results = Employees
|
||||||
e.FullName.ToLower().Contains(query) ||
|
.Where(
|
||||||
(e.Mail != null && e.Mail.ToLower().Contains(query)) ||
|
e =>
|
||||||
(e.Phone != null && e.Phone.Contains(query)) ||
|
e.FullName.ToLower().Contains(query)
|
||||||
(e.Mobile != null && e.Mobile.Contains(query)) ||
|
|| (e.Mail != null && e.Mail.ToLower().Contains(query))
|
||||||
(e.IP != null && e.IP.Contains(query))
|
|| (e.Phone != null && e.Phone.Contains(query))
|
||||||
).OrderBy(e => e.FullName.ToLower().IndexOf(query)).ToList();
|
|| (e.Mobile != null && e.Mobile.Contains(query))
|
||||||
|
|| (e.IP != null && e.IP.Contains(query))
|
||||||
|
)
|
||||||
|
.OrderBy(e => e.FullName.ToLower().IndexOf(query))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
// Отправка результатов поиска
|
// Отправка результатов поиска
|
||||||
await ShowEmployeeResults(message.Chat.Id, results);
|
await ShowEmployeeResults(message, results, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task HandleShowFavorites(Message message)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(message.Text))
|
||||||
|
{
|
||||||
|
var ids = await FavoritesManager.GetAllFavoritesAsync(message.From.Id);
|
||||||
|
// Поиск сотрудников по полям
|
||||||
|
var results = Employees
|
||||||
|
.Where(
|
||||||
|
e => ids.Contains(e.Id)
|
||||||
|
)
|
||||||
|
.OrderBy(e => e.FullName)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Отправка результатов поиска
|
||||||
|
await ShowEmployeeResults(message, results, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,69 +259,183 @@ public class Program
|
|||||||
if (employee != null)
|
if (employee != null)
|
||||||
{
|
{
|
||||||
EmployeeContact contact = new(employee);
|
EmployeeContact contact = new(employee);
|
||||||
string phoneNumber = !string.IsNullOrEmpty(contact.Mobile) ? contact.Mobile : contact.Phone;
|
string phoneNumber = !string.IsNullOrEmpty(contact.Mobile)
|
||||||
var replyParameters = new ReplyParameters() { MessageId = callbackQuery.Message.MessageId, QuoteParseMode = ParseMode.Html, Quote = $"<b>{contact.FullName}</b>" };
|
? contact.Mobile
|
||||||
await Bot.SendContactAsync(callbackQuery.Message.Chat.Id, phoneNumber, contact.FirstName, lastName: contact.LastName, vcard: contact.VCard, replyParameters: replyParameters);
|
: contact.Phone;
|
||||||
|
var replyParameters = new ReplyParameters()
|
||||||
|
{
|
||||||
|
MessageId = callbackQuery.Message.MessageId,
|
||||||
|
QuoteParseMode = ParseMode.Html,
|
||||||
|
Quote = $"<b>{contact.FullName}</b>"
|
||||||
|
};
|
||||||
|
var keyboardMarkup = new InlineKeyboardMarkup()
|
||||||
|
//.AddNewRow()
|
||||||
|
.AddCloseButton();
|
||||||
|
await Bot.SendContact(
|
||||||
|
callbackQuery.Message.Chat.Id,
|
||||||
|
phoneNumber,
|
||||||
|
contact.FirstName,
|
||||||
|
lastName: contact.LastName,
|
||||||
|
vcard: contact.VCard,
|
||||||
|
replyParameters: replyParameters,
|
||||||
|
replyMarkup: keyboardMarkup,
|
||||||
|
protectContent: true
|
||||||
|
);
|
||||||
await Task.Delay(999);
|
await Task.Delay(999);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Bot.AnswerCallbackQueryAsync(callbackQuery.Id);
|
await Bot.AnswerCallbackQuery(callbackQuery.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task HandleDepartmentSelection(Message message)
|
private static async Task HandleAddFavorite(CallbackQuery callbackQuery, string contactId)
|
||||||
{
|
{
|
||||||
if (message.Text.StartsWith("◀️ Назад"))
|
if (callbackQuery.Message != null)
|
||||||
{
|
{
|
||||||
if (CurrentPage > 0)
|
var employee = Employees.Where(e => e.Id == contactId).First();
|
||||||
|
if (employee != null)
|
||||||
{
|
{
|
||||||
CurrentPage--;
|
await FavoritesManager.AddFavoriteAsync(callbackQuery.From.Id, contactId);
|
||||||
await ShowDepartments(message.Chat.Id);
|
foreach (var row in callbackQuery.Message.ReplyMarkup.InlineKeyboard)
|
||||||
|
foreach (var cell in row)
|
||||||
|
{
|
||||||
|
if (cell.CallbackData.Contains("addfavorite"))
|
||||||
|
{
|
||||||
|
cell.CallbackData = $"delfavorite/{contactId}";
|
||||||
|
cell.Text = "💔 Не избранный";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (message.Text.StartsWith("Вперед ▶️"))
|
await Bot.EditMessageReplyMarkup(callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId, callbackQuery.Message.ReplyMarkup);
|
||||||
{
|
await Bot.AnswerCallbackQuery(callbackQuery.Id, "✔️ Контакт добавлен в избранные");
|
||||||
CurrentPage++;
|
|
||||||
await ShowDepartments(message.Chat.Id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int selectedIndex = int.Parse(message.Text) - 1;
|
|
||||||
if (selectedIndex >= 0 && selectedIndex < Departments.Count)
|
|
||||||
{
|
|
||||||
string selectedDepartment = Departments[selectedIndex];
|
|
||||||
var results = Employees.Where(e => e.Department == selectedDepartment).ToList();
|
|
||||||
await ShowEmployeeResults(message.Chat.Id, results);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Bot.SendTextMessageAsync(message.Chat.Id, "Некорректный выбор.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ShowEmployeeResults(long chatId, List<Employee> results)
|
private static async Task HandleDelFavorite(CallbackQuery callbackQuery, string contactId)
|
||||||
{
|
{
|
||||||
if (results.Any())
|
if (callbackQuery.Message != null)
|
||||||
{
|
{
|
||||||
foreach (var employee in results)
|
var employee = Employees.Where(e => e.Id == contactId).First();
|
||||||
|
if (employee != null)
|
||||||
{
|
{
|
||||||
var keyboardMarkup = new InlineKeyboardMarkup()
|
await FavoritesManager.RemoveFavoriteAsync(callbackQuery.From.Id, contactId);
|
||||||
//.AddNewRow("1.1", "1.2", "1.3")
|
foreach (var row in callbackQuery.Message.ReplyMarkup.InlineKeyboard)
|
||||||
.AddNewRow()
|
foreach (var cell in row)
|
||||||
.AddButton("👤 Контакт", $"addcontact/{employee.Id}");
|
{
|
||||||
//.AddButton("В избранные", $"addfavorite/{employee.Id}");
|
if (cell.CallbackData.Contains("delfavorite"))
|
||||||
//.AddButton(InlineKeyboardButton.WithUrl("Написать письмо", $"mailto:{employee.Mail}"));
|
{
|
||||||
|
cell.CallbackData = $"addfavorite/{contactId}";
|
||||||
|
cell.Text = "❤️ В избранные";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
await Bot.EditMessageReplyMarkup(callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId, callbackQuery.Message.ReplyMarkup);
|
||||||
|
await Bot.AnswerCallbackQuery(callbackQuery.Id, "✔️ Контакт удален из избранных");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task HandleShowDepartment(CallbackQuery callbackQuery, int departmentIndex)
|
||||||
|
{
|
||||||
|
await Bot.AnswerCallbackQuery(callbackQuery.Id);
|
||||||
|
if (callbackQuery.Message != null)
|
||||||
|
{
|
||||||
|
await Bot.DeleteMessage(
|
||||||
|
callbackQuery.Message.Chat.Id,
|
||||||
|
callbackQuery.Message.MessageId
|
||||||
|
);
|
||||||
|
|
||||||
|
var employees = Employees
|
||||||
|
.Where(e => e.Department == Departments[departmentIndex])
|
||||||
|
.OrderBy(e => e.FullName)
|
||||||
|
.ToList();
|
||||||
|
if (employees != null)
|
||||||
|
{
|
||||||
|
await ShowEmployeeResults(callbackQuery.Message, employees, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//await Bot.AnswerCallbackQueryAsync(callbackQuery.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task HandleShowEmployee(CallbackQuery callbackQuery, string id)
|
||||||
|
{
|
||||||
|
if (callbackQuery.Message != null)
|
||||||
|
{
|
||||||
|
var employee = Employees.Where(e => e.Id == id).First();
|
||||||
|
if (employee != null)
|
||||||
|
{
|
||||||
|
var isFavorite = await FavoritesManager.IsFavoriteAsync(callbackQuery.From.Id, id);
|
||||||
|
await ShowEmployeeCard(callbackQuery.Message.Chat.Id, employee, isFavorite, closeButton: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Bot.AnswerCallbackQuery(callbackQuery.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static async Task HandleClose(CallbackQuery callbackQuery, string? nextAction)
|
||||||
|
{
|
||||||
|
if (callbackQuery.Message != null)
|
||||||
|
{
|
||||||
|
await Bot.DeleteMessage(
|
||||||
|
callbackQuery.Message.Chat.Id,
|
||||||
|
callbackQuery.Message.MessageId
|
||||||
|
);
|
||||||
|
await Task.Delay(500);
|
||||||
|
}
|
||||||
|
await Bot.AnswerCallbackQuery(callbackQuery.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task ShowEmployeeCard(long chatId, Employee employee, bool isFavorite = false, bool contactButton = true, bool favoriteButton = true, bool closeButton = false)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
var keyboardMarkup = new InlineKeyboardMarkup();
|
||||||
|
var keyboardRow = keyboardMarkup.AddNewRow();
|
||||||
|
if (contactButton)
|
||||||
|
keyboardRow.AddButton("👤 Контакт", $"addcontact/{employee.Id}");
|
||||||
|
|
||||||
|
if (favoriteButton)
|
||||||
|
{
|
||||||
|
if (isFavorite)
|
||||||
|
{
|
||||||
|
keyboardRow.AddButton("💔 Не избранный", $"delfavorite/{employee.Id}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keyboardRow.AddButton("❤️ В избранные", $"addfavorite/{employee.Id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closeButton)
|
||||||
|
keyboardRow.AddCloseButton();
|
||||||
|
|
||||||
var card = CreateEmployeeCard(employee);
|
var card = CreateEmployeeCard(employee);
|
||||||
string photoPath = $"data/photos/{employee.FullName}.jpg";
|
|
||||||
|
string photoPath = Path.Combine(config["Paths:PhotoBasePath"]!, $"{employee.FullName}.jpg");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await using var fileStream = new FileStream(photoPath, FileMode.Open, FileAccess.Read);
|
await using var fileStream = new FileStream(
|
||||||
await Bot.SendPhotoAsync(chatId, fileStream, caption: card, parseMode: ParseMode.Html, replyMarkup: keyboardMarkup);
|
photoPath,
|
||||||
|
FileMode.Open,
|
||||||
|
FileAccess.Read
|
||||||
|
);
|
||||||
|
|
||||||
|
await Bot.SendPhoto(
|
||||||
|
chatId,
|
||||||
|
fileStream,
|
||||||
|
caption: card,
|
||||||
|
parseMode: ParseMode.Html,
|
||||||
|
replyMarkup: keyboardMarkup
|
||||||
|
);
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException)
|
catch (FileNotFoundException)
|
||||||
{
|
{
|
||||||
await Bot.SendTextMessageAsync(chatId, card, null, ParseMode.Html, replyMarkup: keyboardMarkup);
|
await Bot.SendMessage(
|
||||||
|
chatId,
|
||||||
|
card,
|
||||||
|
ParseMode.Html,
|
||||||
|
replyMarkup: keyboardMarkup,
|
||||||
|
protectContent: true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -230,9 +443,39 @@ public class Program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task ShowEmployeeResults(Message message, List<Employee> results, bool? isFavorite = false)
|
||||||
|
{
|
||||||
|
if (results.Any())
|
||||||
|
{
|
||||||
|
if (results.Count < 10)
|
||||||
|
{
|
||||||
|
foreach (var employee in results)
|
||||||
|
{
|
||||||
|
bool bFavorite = isFavorite.HasValue ? isFavorite == true : await FavoritesManager.IsFavoriteAsync(message.From.Id, employee.Id);
|
||||||
|
await ShowEmployeeCard(message.Chat.Id, employee, bFavorite);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await Bot.SendTextMessageAsync(chatId, "Сотрудники не найдены.");
|
string text = "Вот, что удалось найти:";
|
||||||
|
var keyboardMarkup = new InlineKeyboardMarkup();
|
||||||
|
|
||||||
|
foreach (var employee in results)
|
||||||
|
{
|
||||||
|
keyboardMarkup
|
||||||
|
.AddNewRow()
|
||||||
|
.AddButton(employee.FullName, $"showemployee/{employee.Id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
await Bot.SendMessage(message.Chat.Id, text, replyMarkup: keyboardMarkup, protectContent: true);
|
||||||
|
await Task.Delay(999);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Bot.SendMessage(message.Chat.Id, "🔍 Извините, мы ничего не нашли.");
|
||||||
|
await Task.Delay(999);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,9 +506,10 @@ public class Program
|
|||||||
private static string CreateEmployeeCard(Employee employee)
|
private static string CreateEmployeeCard(Employee employee)
|
||||||
{
|
{
|
||||||
EmployeeContact contact = new(employee);
|
EmployeeContact contact = new(employee);
|
||||||
string card = $"👤 <b>{contact.FullName}</b>\n" +
|
string card =
|
||||||
$"🏢 {contact.Department}\n" +
|
$"👤 <b>{contact.FullName}</b>\n"
|
||||||
$"🎓 {contact.Position}\n";
|
+ $"🏢 {contact.Department}\n"
|
||||||
|
+ $"🎓 {contact.Position}\n";
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(contact.Mail))
|
if (!string.IsNullOrEmpty(contact.Mail))
|
||||||
card += $"✉️ {contact.Mail}\n";
|
card += $"✉️ {contact.Mail}\n";
|
||||||
@@ -275,8 +519,8 @@ public class Program
|
|||||||
if (!string.IsNullOrEmpty(contact.ExtensionNumber))
|
if (!string.IsNullOrEmpty(contact.ExtensionNumber))
|
||||||
card += $"📞 {contact.ExtensionNumber}\n";
|
card += $"📞 {contact.ExtensionNumber}\n";
|
||||||
|
|
||||||
//if (!string.IsNullOrEmpty(employee.IP))
|
if (!string.IsNullOrEmpty(employee.IP))
|
||||||
// card += $"🌐 {employee.IP}\n";
|
card += $"🌐 {employee.IP}\n";
|
||||||
|
|
||||||
card += GetEventStatus(employee);
|
card += GetEventStatus(employee);
|
||||||
|
|
||||||
@@ -285,12 +529,14 @@ public class Program
|
|||||||
|
|
||||||
private static string CreateEmployeeCard2(Employee employee)
|
private static string CreateEmployeeCard2(Employee employee)
|
||||||
{
|
{
|
||||||
string photoUrl = $"https://contacts.int.nssz.ru/data/photos/{employee.FullName.Replace(" ", "%20")}.jpg"; // Формирование пути к фотографии
|
string photoUrl =
|
||||||
|
$"https://contacts.int.nssz.ru/data/photos/{employee.FullName.Replace(" ", "%20")}.jpg"; // Формирование пути к фотографии
|
||||||
|
|
||||||
string card = $"👤 <b>{employee.FullName}</b>\n" +
|
string card =
|
||||||
$"🏢 Отдел: {employee.Department}\n" +
|
$"👤 <b>{employee.FullName}</b>\n"
|
||||||
$"🎓 Должность: {employee.Position}\n" +
|
+ $"🏢 Отдел: {employee.Department}\n"
|
||||||
$"📸 Фото: <a href='{photoUrl}'>Посмотреть фото</a>\n"; // Добавление ссылки на фото
|
+ $"🎓 Должность: {employee.Position}\n"
|
||||||
|
+ $"📸 Фото: <a href='{photoUrl}'>Посмотреть фото</a>\n"; // Добавление ссылки на фото
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(employee.Mail))
|
if (!string.IsNullOrEmpty(employee.Mail))
|
||||||
card += $"✉️ Почта: {employee.Mail}\n";
|
card += $"✉️ Почта: {employee.Mail}\n";
|
||||||
@@ -306,16 +552,50 @@ public class Program
|
|||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LoadEmployees()
|
private static Timer? updateTimer = null;
|
||||||
|
private static void StartUpdatingEmployeesData(int intervalMs = 1 * 60 * 60 * 1000)
|
||||||
{
|
{
|
||||||
// Загрузка данных сотрудников из JSON файла
|
if (updateTimer != null) return;
|
||||||
var json = System.IO.File.ReadAllText("data/contacts.json");
|
updateTimer = new Timer(intervalMs);
|
||||||
Employees = JsonConvert.DeserializeObject<List<Employee>>(json)!;
|
updateTimer.Elapsed += UpdateTimer_Elapsed;
|
||||||
|
updateTimer.AutoReset = true; // Запускать снова после завершения
|
||||||
|
updateTimer.Enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
|
private static void UpdateTimer_Elapsed(object? sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Произошла ошибка: {exception.Message}");
|
LoadEmployees();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int prevHash = 0;
|
||||||
|
private static bool LoadEmployees()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Загрузка данных сотрудников из JSON файла при наличии изменений
|
||||||
|
var json = System.IO.File.ReadAllText(config["Paths:ContactsJsonPath"]!);
|
||||||
|
int newHash = json.GetHashCode();
|
||||||
|
if (prevHash == newHash)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
prevHash = newHash;
|
||||||
|
Employees = JsonConvert.DeserializeObject<List<Employee>>(json)!;
|
||||||
|
Log.Information("Загружены данные о {Count} сотрудниках", Employees.Count);
|
||||||
|
return true;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.Error(ex, "Ошибка при загрузке списка сотрудников");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task HandleErrorAsync(
|
||||||
|
ITelegramBotClient botClient,
|
||||||
|
Exception exception,
|
||||||
|
CancellationToken cancellationToken
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Log.Error(exception, "Произошла ошибка");
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"Paths": {
|
||||||
|
"ContactsJsonPath": "data/contacts.json",
|
||||||
|
"PhotoBasePath": "data/photos"
|
||||||
|
},
|
||||||
|
"Telegram": {
|
||||||
|
"BotToken": "8155021946:AAGbfJnLa0sTWxqFB9yjbXhbTedBw4wvcQE"
|
||||||
|
},
|
||||||
|
"Redis": {
|
||||||
|
"Configuration": "redis-15840.crce198.eu-central-1-3.ec2.redns.redis-cloud.com:15840",
|
||||||
|
"User": "tgbot",
|
||||||
|
"Password": "0aCKMee9Ocq88KzfjWyC9AmB25tLiY93%"
|
||||||
|
},
|
||||||
|
"Serilog": {
|
||||||
|
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
||||||
|
"MinimumLevel": "Debug",
|
||||||
|
"WriteTo": [
|
||||||
|
{ "Name": "Console" },
|
||||||
|
{
|
||||||
|
"Name": "File",
|
||||||
|
"Args": {
|
||||||
|
"path": "nsszcontactbot.log",
|
||||||
|
"rollingInterval": "Day"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-1
@@ -7,8 +7,19 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.3" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Telegram.Bot" Version="21.11.0" />
|
<PackageReference Include="NRedisStack" Version="0.13.2" />
|
||||||
|
<PackageReference Include="Serilog.Extensions.Logging" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Telegram.Bot" Version="22.4.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user