Добавлены новые функции для управления контактами и фотографиями сотрудников, улучшена логика обработки избранных контактов, добавлены уведомления о днях рождения сотрудников.
This commit is contained in:
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"cSpell.enabled": false
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ public class Employee
|
|||||||
public string Department { get; set; } = string.Empty; // Название отдела
|
public string Department { get; set; } = string.Empty; // Название отдела
|
||||||
public string DepartmentCode { get; set; } = string.Empty; // Код отдела
|
public string DepartmentCode { get; set; } = string.Empty; // Код отдела
|
||||||
public string Position { get; set; } = string.Empty; // Должность
|
public string Position { get; set; } = string.Empty; // Должность
|
||||||
|
public bool Birthday { get; set; } = false;
|
||||||
public string? Phone { get; set; } // Опциональное поле для телефона
|
public string? Phone { get; set; } // Опциональное поле для телефона
|
||||||
public string? Mobile { get; set; } // Опциональное поле для хранения номера мобильного телефона
|
public string? Mobile { get; set; } // Опциональное поле для хранения номера мобильного телефона
|
||||||
public string? Mail { get; set; } // Опциональное поле для электронной почты
|
public string? Mail { get; set; } // Опциональное поле для электронной почты
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ public class EmployeeContact
|
|||||||
{
|
{
|
||||||
LastName = nameParts[0];
|
LastName = nameParts[0];
|
||||||
FirstName = nameParts[1];
|
FirstName = nameParts[1];
|
||||||
|
ShortName = $"{LastName} {FirstName}";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FirstName = FullName;
|
FirstName = FullName;
|
||||||
|
ShortName = FullName;
|
||||||
LastName = string.Empty;
|
LastName = string.Empty;
|
||||||
}
|
}
|
||||||
Department = employee.Department;
|
Department = employee.Department;
|
||||||
@@ -60,6 +62,7 @@ public class EmployeeContact
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public string FullName { get; set; } // Полное имя сотрудника
|
public string FullName { get; set; } // Полное имя сотрудника
|
||||||
|
public string ShortName { get; set; }
|
||||||
public string FirstName { get; set; }
|
public string FirstName { get; set; }
|
||||||
public string LastName { get; set; }
|
public string LastName { get; set; }
|
||||||
public string Department { get; set; } // Название отдела
|
public string Department { get; set; } // Название отдела
|
||||||
|
|||||||
+26
-13
@@ -1,27 +1,30 @@
|
|||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace nsszcontactbot;
|
namespace nsszcontactbot;
|
||||||
public class FavoriteContactsManager
|
public class FavoriteContactsManager
|
||||||
{
|
{
|
||||||
private readonly IDatabase _redisDb;
|
private readonly IDatabase _redisDb;
|
||||||
private const string KeyPrefix = "user:favorites:";
|
|
||||||
|
|
||||||
public FavoriteContactsManager(ConnectionMultiplexer redis)
|
public FavoriteContactsManager(ConnectionMultiplexer redis)
|
||||||
{
|
{
|
||||||
_redisDb = redis.GetDatabase();
|
_redisDb = redis.GetDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetUserKey(long userId) => $"user:favorites:{userId}";
|
||||||
|
private static string GetContactKey(string contactId) => $"contact:favorites:{contactId}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Добавить контакт в избранное.
|
/// Добавить контакт в избранное.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task AddFavoriteAsync(long userId, string contactId)
|
public async Task AddFavoriteAsync(long userId, string contactId)
|
||||||
{
|
{
|
||||||
string key = GetRedisKey(userId);
|
string userKey = GetUserKey(userId);
|
||||||
await _redisDb.SetAddAsync(key, contactId);
|
string contactKey = GetContactKey(contactId);
|
||||||
|
await Task.WhenAll(
|
||||||
|
_redisDb.SetAddAsync(userKey, contactId),
|
||||||
|
_redisDb.SetAddAsync(contactKey, userId.ToString())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -29,8 +32,12 @@ public class FavoriteContactsManager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task RemoveFavoriteAsync(long userId, string contactId)
|
public async Task RemoveFavoriteAsync(long userId, string contactId)
|
||||||
{
|
{
|
||||||
string key = GetRedisKey(userId);
|
string userKey = GetUserKey(userId);
|
||||||
await _redisDb.SetRemoveAsync(key, contactId);
|
string contactKey = GetContactKey(contactId);
|
||||||
|
await Task.WhenAll(
|
||||||
|
_redisDb.SetRemoveAsync(userKey, contactId),
|
||||||
|
_redisDb.SetRemoveAsync(contactKey, userId.ToString())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -38,7 +45,7 @@ public class FavoriteContactsManager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<bool> IsFavoriteAsync(long userId, string contactId)
|
public async Task<bool> IsFavoriteAsync(long userId, string contactId)
|
||||||
{
|
{
|
||||||
string key = GetRedisKey(userId);
|
string key = GetUserKey(userId);
|
||||||
return await _redisDb.SetContainsAsync(key, contactId);
|
return await _redisDb.SetContainsAsync(key, contactId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,10 +54,16 @@ public class FavoriteContactsManager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<List<string>> GetAllFavoritesAsync(long userId)
|
public async Task<List<string>> GetAllFavoritesAsync(long userId)
|
||||||
{
|
{
|
||||||
string key = GetRedisKey(userId);
|
string key = GetUserKey(userId);
|
||||||
var members = await _redisDb.SetMembersAsync(key);
|
var members = await _redisDb.SetMembersAsync(key);
|
||||||
return members.Select(m => m.ToString()).ToList();
|
return [.. members.Select(m => m.ToString())];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<long>> GetUsersWithFavoriteAsync(string contactId)
|
||||||
|
{
|
||||||
|
string contactKey = GetContactKey(contactId);
|
||||||
|
var members = await _redisDb.SetMembersAsync(contactKey);
|
||||||
|
return [.. members.Select(m => long.Parse(m.ToString()))];
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetRedisKey(long userId) => $"{KeyPrefix}{userId}";
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
using System;
|
using Telegram.Bot.Types.ReplyMarkups;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Telegram.Bot.Types.ReplyMarkups;
|
|
||||||
|
|
||||||
namespace nsszcontactbot
|
namespace nsszcontactbot
|
||||||
{
|
{
|
||||||
@@ -14,5 +9,27 @@ namespace nsszcontactbot
|
|||||||
var buttonRow = newRow ? markup.AddNewRow() : markup;
|
var buttonRow = newRow ? markup.AddNewRow() : markup;
|
||||||
return buttonRow.AddButton("❌ Закрыть", "close");
|
return buttonRow.AddButton("❌ Закрыть", "close");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static InlineKeyboardMarkup AddPrevPageButton(this InlineKeyboardMarkup markup, int currentPage, string context = "", string text = "⬅️ Назад")
|
||||||
|
{
|
||||||
|
return markup.AddButton(text, $"page/{currentPage - 1}{(string.IsNullOrEmpty(context) ? "" : "/")}{context}");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InlineKeyboardMarkup AddNextPageButton(this InlineKeyboardMarkup markup, int currentPage, string context = "", string text = "Вперед ➡️")
|
||||||
|
{
|
||||||
|
return markup.AddButton(text, $"page/{currentPage + 1}{(string.IsNullOrEmpty(context) ? "" : "/")}{context}");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InlineKeyboardMarkup AddPaginator(this InlineKeyboardMarkup markup, int currentPage, int totalPages, string context = "", string textPrev = "⬅️ Назад", string textNext = "Вперед ➡️")
|
||||||
|
{
|
||||||
|
if (totalPages > 1)
|
||||||
|
{
|
||||||
|
if (currentPage > 1)
|
||||||
|
AddPrevPageButton(markup, currentPage, context, textPrev);
|
||||||
|
if (currentPage < totalPages)
|
||||||
|
AddNextPageButton(markup, currentPage, context, textNext);
|
||||||
|
}
|
||||||
|
return markup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "cp",
|
||||||
|
"fullName": "Центральная проходная",
|
||||||
|
"department": "Проходные",
|
||||||
|
"departmentCode": 8888,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8057",
|
||||||
|
"category": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "tp",
|
||||||
|
"fullName": "Транспортная проходная",
|
||||||
|
"department": "Проходные",
|
||||||
|
"departmentCode": 8888,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8059",
|
||||||
|
"category": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "po701",
|
||||||
|
"fullName": "Пост охраны проект 701",
|
||||||
|
"department": "Посты охраны",
|
||||||
|
"departmentCode": 9999,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8443",
|
||||||
|
"category": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "po702",
|
||||||
|
"fullName": "Пост охраны проект 702",
|
||||||
|
"department": "Посты охраны",
|
||||||
|
"departmentCode": 9999,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8168",
|
||||||
|
"category": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "po402",
|
||||||
|
"fullName": "Пост охраны проект 402",
|
||||||
|
"department": "Посты охраны",
|
||||||
|
"departmentCode": 9999,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8498",
|
||||||
|
"category": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "po703",
|
||||||
|
"fullName": "Пост охраны проект 703",
|
||||||
|
"department": "Посты охраны",
|
||||||
|
"departmentCode": 9999,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8169",
|
||||||
|
"category": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "pov",
|
||||||
|
"fullName": "Пост охраны видеонаблюдения",
|
||||||
|
"department": "Посты охраны",
|
||||||
|
"departmentCode": 9999,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8468",
|
||||||
|
"category": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mk",
|
||||||
|
"fullName": "Медицинский кабинет",
|
||||||
|
"department": "Дежурные службы",
|
||||||
|
"departmentCode": -1,
|
||||||
|
"position": "",
|
||||||
|
"mobile": "79312040016",
|
||||||
|
"phone": "8220",
|
||||||
|
"mail": "medkab@nssz.ru",
|
||||||
|
"category": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "de",
|
||||||
|
"fullName": "Дежурный электрик",
|
||||||
|
"department": "Дежурные службы",
|
||||||
|
"departmentCode": -1,
|
||||||
|
"position": "",
|
||||||
|
"mobile": "79213973747",
|
||||||
|
"phone": "8143",
|
||||||
|
"mail": "medkab2@nssz.ru",
|
||||||
|
"category": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dves",
|
||||||
|
"fullName": "Дежурный ВЭС",
|
||||||
|
"department": "Дежурные службы",
|
||||||
|
"departmentCode": -1,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8147",
|
||||||
|
"mobile": "79213279276",
|
||||||
|
"category": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dvtk",
|
||||||
|
"fullName": "Дежурный водоснабжения, теплоснабжения, канализации",
|
||||||
|
"department": "Дежурные службы",
|
||||||
|
"departmentCode": -1,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8129",
|
||||||
|
"category": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "durptm",
|
||||||
|
"fullName": "Дежурный по участку ремонта ПТМ",
|
||||||
|
"department": "Дежурные службы",
|
||||||
|
"departmentCode": -1,
|
||||||
|
"position": "",
|
||||||
|
"phone": "8142",
|
||||||
|
"category": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using StackExchange.Redis;
|
||||||
|
using Telegram.Bot.Types;
|
||||||
|
|
||||||
|
namespace nsszcontactbot;
|
||||||
|
|
||||||
|
public class PhotosManager(ConnectionMultiplexer redis, string PhotoBasePath)
|
||||||
|
{
|
||||||
|
private readonly IDatabase _redisDb = redis.GetDatabase();
|
||||||
|
private readonly string _basePath = PhotoBasePath;
|
||||||
|
private const string Key = "cache:photos";
|
||||||
|
private const string DefaultPhotoFileId = "AgACAgIAAxkDAAIDTWgtK4jsuoRTb7C4p0uhfVAOvWy2AAK1-TEb3cloSdmbxB-nuRFCAQADAgADcwADNgQ";
|
||||||
|
|
||||||
|
public async Task CacheEmployeePhotoAsync(Employee employee, string fileId, TimeSpan ttl = default)
|
||||||
|
{
|
||||||
|
string entryName = GetEntryName(employee);
|
||||||
|
_redisDb.HashSetAsync(Key, [new(entryName, fileId)]).ConfigureAwait(false);
|
||||||
|
ttl = ttl == default ? TimeSpan.FromDays(30) : ttl;
|
||||||
|
_redisDb.HashFieldExpireAsync(Key, [new(entryName)], ttl).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<InputFile?> GetEmployeePhotoAsync(Employee employee)
|
||||||
|
{
|
||||||
|
string entryName = GetEntryName(employee);
|
||||||
|
var val = await _redisDb.HashGetAsync(Key, entryName);
|
||||||
|
if (val != RedisValue.Null && val.HasValue)
|
||||||
|
{
|
||||||
|
return InputFile.FromFileId(val!);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string photoPath = Path.Combine(_basePath, $"{employee.Id}.jpg");
|
||||||
|
photoPath = File.Exists(photoPath) ? photoPath : Path.Combine(_basePath, $"{employee.FullName}.jpg");
|
||||||
|
|
||||||
|
if (File.Exists(photoPath))
|
||||||
|
{
|
||||||
|
var fileStream = new FileStream(
|
||||||
|
photoPath,
|
||||||
|
FileMode.Open,
|
||||||
|
FileAccess.Read
|
||||||
|
);
|
||||||
|
return InputFile.FromStream(fileStream);
|
||||||
|
}
|
||||||
|
return InputFile.FromFileId(DefaultPhotoFileId);;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetEntryName(Employee employee) => $"employee:{employee.Id}:fileid";
|
||||||
|
}
|
||||||
+278
-98
@@ -1,29 +1,25 @@
|
|||||||
using Newtonsoft.Json;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Serilog;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
using System.Timers;
|
||||||
using Telegram.Bot;
|
using Telegram.Bot;
|
||||||
using Telegram.Bot.Polling;
|
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 Timer = System.Timers.Timer;
|
||||||
using StackExchange.Redis;
|
|
||||||
|
|
||||||
namespace nsszcontactbot;
|
namespace nsszcontactbot;
|
||||||
|
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
private static ITelegramBotClient Bot;
|
private static ITelegramBotClient Bot;
|
||||||
private static List<Employee> Employees = new();
|
private static List<Employee> Employees = [];
|
||||||
private static List<string> Departments = new();
|
private static List<string> Departments = [];
|
||||||
private static IConfigurationRoot config;
|
private static IConfigurationRoot config;
|
||||||
private static FavoriteContactsManager FavoritesManager;
|
private static FavoriteContactsManager FavoritesManager;
|
||||||
|
private static PhotosManager PhotosManager;
|
||||||
//private static ILogger<Program> Logger;
|
//private static ILogger<Program> Logger;
|
||||||
|
|
||||||
public static async Task<int> Main(string[] args)
|
public static async Task<int> Main(string[] args)
|
||||||
@@ -49,14 +45,15 @@ public class Program
|
|||||||
});
|
});
|
||||||
|
|
||||||
FavoritesManager = new FavoriteContactsManager(redis);
|
FavoritesManager = new FavoriteContactsManager(redis);
|
||||||
|
PhotosManager = new PhotosManager(redis, config["Paths:PhotoBasePath"]!);
|
||||||
Bot = new TelegramBotClient(botToken);
|
Bot = new TelegramBotClient(botToken);
|
||||||
List<BotCommand> cmds = new();
|
List<BotCommand> cmds = [];
|
||||||
await Bot.SetMyCommands(cmds);
|
await Bot.SetMyCommands(cmds);
|
||||||
if (!LoadEmployees())
|
if (!LoadEmployees())
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
StartUpdatingEmployeesData();
|
StartUpdatingEmployeesData(15 * 60 * 1000); // обновлять данные каждые 15 минут
|
||||||
|
|
||||||
var me = await Bot.GetMe();
|
var me = await Bot.GetMe();
|
||||||
|
|
||||||
@@ -76,6 +73,8 @@ public class Program
|
|||||||
cancellationToken: cancellationToken
|
cancellationToken: cancellationToken
|
||||||
);
|
);
|
||||||
|
|
||||||
|
StartBirthdayNotifications();
|
||||||
|
|
||||||
Console.WriteLine("Нажмите Enter для выхода...");
|
Console.WriteLine("Нажмите Enter для выхода...");
|
||||||
Console.ReadLine();
|
Console.ReadLine();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -96,11 +95,11 @@ public class Program
|
|||||||
{
|
{
|
||||||
await StartCommand(message);
|
await StartCommand(message);
|
||||||
}
|
}
|
||||||
else if (message.Text.EndsWith("Список подразделений"))
|
else if (message.Text.EndsWith("Подразделения"))
|
||||||
{
|
{
|
||||||
await ChooseDepartment(message);
|
await ChooseDepartment(message);
|
||||||
}
|
}
|
||||||
else if (message.Text.EndsWith("Избранные контакты"))
|
else if (message.Text.EndsWith("Избранные"))
|
||||||
{
|
{
|
||||||
await HandleShowFavorites(message);
|
await HandleShowFavorites(message);
|
||||||
}
|
}
|
||||||
@@ -111,8 +110,7 @@ public class Program
|
|||||||
}
|
}
|
||||||
else if (update.Type == UpdateType.CallbackQuery)
|
else if (update.Type == UpdateType.CallbackQuery)
|
||||||
{
|
{
|
||||||
var message = update.CallbackQuery.Message;
|
string data = update.CallbackQuery!.Data ?? string.Empty;
|
||||||
string data = update.CallbackQuery.Data ?? string.Empty;
|
|
||||||
string[] dataParts = data.Split('/');
|
string[] dataParts = data.Split('/');
|
||||||
if (dataParts.Length > 0)
|
if (dataParts.Length > 0)
|
||||||
{
|
{
|
||||||
@@ -156,6 +154,15 @@ public class Program
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "page":
|
||||||
|
{
|
||||||
|
if (dataParts.Length < 3)
|
||||||
|
break;
|
||||||
|
var arg = dataParts.Length == 3 ? dataParts[2] : dataParts[2] + "/" + dataParts[3];
|
||||||
|
await HandlePageNavigation(update.CallbackQuery, int.Parse(dataParts[1]), arg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case "close":
|
case "close":
|
||||||
{
|
{
|
||||||
await HandleClose(
|
await HandleClose(
|
||||||
@@ -175,32 +182,80 @@ public class Program
|
|||||||
private static async Task StartCommand(Message message)
|
private static async Task StartCommand(Message message)
|
||||||
{
|
{
|
||||||
string text = "Привет! Я бот для поиска контактов сотрудников. Введите критерии поиска или воспользуйтесь кнопками внизу.\n";
|
string text = "Привет! Я бот для поиска контактов сотрудников. Введите критерии поиска или воспользуйтесь кнопками внизу.\n";
|
||||||
await Bot.SendMessage(message.Chat.Id, text, replyMarkup: new string[] { "⭐️ Избранные контакты", "🏢 Список подразделений" });
|
await Bot.SendMessage(message.Chat.Id, text, replyMarkup: new string[] { "❤️ Избранные", "🏢 Подразделения" });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ChooseDepartment(Message message)
|
private static async Task ChooseDepartment(Message message)
|
||||||
{
|
{
|
||||||
Departments = Employees.Select(e => e.Department).Distinct().ToList();
|
Departments = [.. Employees.OrderBy(e => e.DepartmentCode).Select(e => e.Department).Distinct()];
|
||||||
await ShowDepartments(message.Chat.Id);
|
await ShowDepartments(message.Chat.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ShowDepartments(long chatId)
|
private static async Task ShowDepartments(long chatId, int page = 1, int pageSize = 10)
|
||||||
{
|
{
|
||||||
string text = "Выберите подразделение:";
|
if (Departments.Count == 0)
|
||||||
|
{
|
||||||
|
await Bot.SendMessage(chatId, "Подразделения не найдены.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalPages = (int)Math.Ceiling((double)Departments.Count / pageSize);
|
||||||
|
var pagedDepartments = Departments.Skip((page - 1) * pageSize).Take(pageSize).ToList();
|
||||||
|
|
||||||
|
string text = $"Выберите подразделение (страница {page}/{totalPages}):";
|
||||||
var keyboardMarkup = new InlineKeyboardMarkup();
|
var keyboardMarkup = new InlineKeyboardMarkup();
|
||||||
|
|
||||||
var departmentIndex = 0;
|
var departmentIndex = (page - 1) * pageSize;
|
||||||
foreach (var department in Departments)
|
foreach (var department in pagedDepartments)
|
||||||
{
|
{
|
||||||
keyboardMarkup
|
keyboardMarkup
|
||||||
.AddNewRow()
|
.AddNewRow()
|
||||||
.AddButton($"{department}", $"showdepartment/{departmentIndex++}");
|
.AddButton($"{department}", $"showdepartment/{departmentIndex++}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (totalPages > 1)
|
||||||
|
{
|
||||||
|
var navigationRow = keyboardMarkup.AddNewRow();
|
||||||
|
navigationRow.AddPaginator(page, totalPages, "departments");
|
||||||
|
}
|
||||||
|
|
||||||
//keyboardMarkup.AddCloseButton();
|
//keyboardMarkup.AddCloseButton();
|
||||||
await Bot.SendMessage(chatId, text, replyMarkup: keyboardMarkup);
|
await Bot.SendMessage(chatId, text, replyMarkup: keyboardMarkup);
|
||||||
await Task.Delay(999);
|
await Task.Delay(999);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EmployeeComparer : IComparer<Employee>
|
||||||
|
{
|
||||||
|
public int Compare(Employee? a, Employee? b)
|
||||||
|
{
|
||||||
|
if (a == null || b == null) return 0;
|
||||||
|
|
||||||
|
// Сортировка по DepartmentCode
|
||||||
|
int cd = CompareDepartmentCode(a.DepartmentCode, b.DepartmentCode);
|
||||||
|
if (cd != 0) return cd;
|
||||||
|
|
||||||
|
// Сортировка по Category
|
||||||
|
int cc = a.Category.CompareTo(b.Category);
|
||||||
|
if (cc != 0) return cc;
|
||||||
|
|
||||||
|
// Сортировка по Position (с учетом пустых значений)
|
||||||
|
int cp = string.Compare(a.Position ?? "", b.Position ?? "", StringComparison.OrdinalIgnoreCase);
|
||||||
|
if (cp != 0) return cp;
|
||||||
|
|
||||||
|
// Сортировка по FullName
|
||||||
|
return string.Compare(a.FullName, b.FullName, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CompareDepartmentCode(string codeA, string codeB)
|
||||||
|
{
|
||||||
|
if (int.TryParse(codeA, out int a) && int.TryParse(codeB, out int b))
|
||||||
|
{
|
||||||
|
return a.CompareTo(b);
|
||||||
|
}
|
||||||
|
return string.Compare(codeA, codeB, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task HandleSearchInput(Message message)
|
private static async Task HandleSearchInput(Message message)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(message.Text))
|
if (!string.IsNullOrEmpty(message.Text))
|
||||||
@@ -216,18 +271,25 @@ public class Program
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Поиск сотрудников по полям
|
// Поиск сотрудников по полям
|
||||||
|
var queries = query.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||||
var results = Employees
|
var results = Employees
|
||||||
.Where(
|
.Where(e =>
|
||||||
e =>
|
queries.All(q =>
|
||||||
e.FullName.ToLower().Contains(query)
|
{
|
||||||
|| (e.Mail != null && e.Mail.ToLower().Contains(query))
|
var res = e.FullName.Contains(q, StringComparison.CurrentCultureIgnoreCase) ||
|
||||||
|| (e.Phone != null && e.Phone.Contains(query))
|
(e.Mail != null && e.Mail.Contains(q, StringComparison.CurrentCultureIgnoreCase)) ||
|
||||||
|| (e.Mobile != null && e.Mobile.Contains(query))
|
(e.Phone != null && e.Phone.Contains(q)) ||
|
||||||
|| (e.IP != null && e.IP.Contains(query))
|
(e.Mobile != null && e.Mobile.Contains(q)) ||
|
||||||
)
|
(e.IP != null && e.IP.Contains(q));
|
||||||
.OrderBy(e => e.FullName.ToLower().IndexOf(query))
|
if (queries.Length == 1) return res;
|
||||||
.ToList();
|
|
||||||
|
|
||||||
|
return res ||
|
||||||
|
(e.Department != null && e.Department.Contains(q, StringComparison.CurrentCultureIgnoreCase)) ||
|
||||||
|
(e.Position != null && e.Position.Contains(q, StringComparison.CurrentCultureIgnoreCase));
|
||||||
|
}
|
||||||
|
))
|
||||||
|
.Order(new EmployeeComparer())
|
||||||
|
.ToList();
|
||||||
// Отправка результатов поиска
|
// Отправка результатов поиска
|
||||||
await ShowEmployeeResults(message, results, null);
|
await ShowEmployeeResults(message, results, null);
|
||||||
}
|
}
|
||||||
@@ -237,13 +299,14 @@ public class Program
|
|||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(message.Text))
|
if (!string.IsNullOrEmpty(message.Text))
|
||||||
{
|
{
|
||||||
var ids = await FavoritesManager.GetAllFavoritesAsync(message.From.Id);
|
var ids = await FavoritesManager.GetAllFavoritesAsync(message.From!.Id);
|
||||||
// Поиск сотрудников по полям
|
// Поиск сотрудников по полям
|
||||||
var results = Employees
|
var results = Employees
|
||||||
.Where(
|
.Where(
|
||||||
e => ids.Contains(e.Id)
|
e => ids.Contains(e.Id)
|
||||||
)
|
)
|
||||||
.OrderBy(e => e.FullName)
|
.OrderBy(e => e.FullName)
|
||||||
|
//.Order(new EmployeeComparer())
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// Отправка результатов поиска
|
// Отправка результатов поиска
|
||||||
@@ -255,7 +318,7 @@ public class Program
|
|||||||
{
|
{
|
||||||
if (callbackQuery.Message != null)
|
if (callbackQuery.Message != null)
|
||||||
{
|
{
|
||||||
var employee = Employees.Where(e => e.Id == id).First();
|
var employee = Employees.First(e => e.Id == id);
|
||||||
if (employee != null)
|
if (employee != null)
|
||||||
{
|
{
|
||||||
EmployeeContact contact = new(employee);
|
EmployeeContact contact = new(employee);
|
||||||
@@ -279,7 +342,7 @@ public class Program
|
|||||||
vcard: contact.VCard,
|
vcard: contact.VCard,
|
||||||
replyParameters: replyParameters,
|
replyParameters: replyParameters,
|
||||||
replyMarkup: keyboardMarkup,
|
replyMarkup: keyboardMarkup,
|
||||||
protectContent: true
|
protectContent: false
|
||||||
);
|
);
|
||||||
await Task.Delay(999);
|
await Task.Delay(999);
|
||||||
}
|
}
|
||||||
@@ -291,14 +354,14 @@ public class Program
|
|||||||
{
|
{
|
||||||
if (callbackQuery.Message != null)
|
if (callbackQuery.Message != null)
|
||||||
{
|
{
|
||||||
var employee = Employees.Where(e => e.Id == contactId).First();
|
var employee = Employees.First(e => e.Id == contactId);
|
||||||
if (employee != null)
|
if (employee != null)
|
||||||
{
|
{
|
||||||
await FavoritesManager.AddFavoriteAsync(callbackQuery.From.Id, contactId);
|
await FavoritesManager.AddFavoriteAsync(callbackQuery.From.Id, contactId);
|
||||||
foreach (var row in callbackQuery.Message.ReplyMarkup.InlineKeyboard)
|
foreach (var row in callbackQuery.Message!.ReplyMarkup!.InlineKeyboard)
|
||||||
foreach (var cell in row)
|
foreach (var cell in row)
|
||||||
{
|
{
|
||||||
if (cell.CallbackData.Contains("addfavorite"))
|
if (cell.CallbackData!.Contains("addfavorite"))
|
||||||
{
|
{
|
||||||
cell.CallbackData = $"delfavorite/{contactId}";
|
cell.CallbackData = $"delfavorite/{contactId}";
|
||||||
cell.Text = "💔 Не избранный";
|
cell.Text = "💔 Не избранный";
|
||||||
@@ -315,7 +378,7 @@ public class Program
|
|||||||
{
|
{
|
||||||
if (callbackQuery.Message != null)
|
if (callbackQuery.Message != null)
|
||||||
{
|
{
|
||||||
var employee = Employees.Where(e => e.Id == contactId).First();
|
var employee = Employees.First(e => e.Id == contactId);
|
||||||
if (employee != null)
|
if (employee != null)
|
||||||
{
|
{
|
||||||
await FavoritesManager.RemoveFavoriteAsync(callbackQuery.From.Id, contactId);
|
await FavoritesManager.RemoveFavoriteAsync(callbackQuery.From.Id, contactId);
|
||||||
@@ -347,7 +410,8 @@ public class Program
|
|||||||
|
|
||||||
var employees = Employees
|
var employees = Employees
|
||||||
.Where(e => e.Department == Departments[departmentIndex])
|
.Where(e => e.Department == Departments[departmentIndex])
|
||||||
.OrderBy(e => e.FullName)
|
//.OrderBy(e => e.FullName)
|
||||||
|
.Order(new EmployeeComparer())
|
||||||
.ToList();
|
.ToList();
|
||||||
if (employees != null)
|
if (employees != null)
|
||||||
{
|
{
|
||||||
@@ -361,7 +425,7 @@ public class Program
|
|||||||
{
|
{
|
||||||
if (callbackQuery.Message != null)
|
if (callbackQuery.Message != null)
|
||||||
{
|
{
|
||||||
var employee = Employees.Where(e => e.Id == id).First();
|
var employee = Employees.First(e => e.Id == id);
|
||||||
if (employee != null)
|
if (employee != null)
|
||||||
{
|
{
|
||||||
var isFavorite = await FavoritesManager.IsFavoriteAsync(callbackQuery.From.Id, id);
|
var isFavorite = await FavoritesManager.IsFavoriteAsync(callbackQuery.From.Id, id);
|
||||||
@@ -371,6 +435,27 @@ public class Program
|
|||||||
await Bot.AnswerCallbackQuery(callbackQuery.Id);
|
await Bot.AnswerCallbackQuery(callbackQuery.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task HandlePageNavigation(CallbackQuery callbackQuery, int page, string context)
|
||||||
|
{
|
||||||
|
if (callbackQuery.Message != null)
|
||||||
|
{
|
||||||
|
await Bot.DeleteMessage(callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId);
|
||||||
|
var messageHash = (callbackQuery.Message.Chat.Id << 32) | (uint)callbackQuery.Message.Id;
|
||||||
|
|
||||||
|
if (context.Contains("employees"))
|
||||||
|
{
|
||||||
|
long hash = long.Parse(context.Split('/')[1]);
|
||||||
|
var results = _resultsCache[hash];
|
||||||
|
await ShowEmployeeResults(callbackQuery.Message, results, null, page);
|
||||||
|
//_resultsCache.Remove(messageHash);
|
||||||
|
}
|
||||||
|
else if (context == "departments")
|
||||||
|
{
|
||||||
|
await ShowDepartments(callbackQuery.Message.Chat.Id, page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Bot.AnswerCallbackQuery(callbackQuery.Id);
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task HandleClose(CallbackQuery callbackQuery, string? nextAction)
|
private static async Task HandleClose(CallbackQuery callbackQuery, string? nextAction)
|
||||||
{
|
{
|
||||||
@@ -410,65 +495,81 @@ public class Program
|
|||||||
|
|
||||||
var card = CreateEmployeeCard(employee);
|
var card = CreateEmployeeCard(employee);
|
||||||
|
|
||||||
string photoPath = Path.Combine(config["Paths:PhotoBasePath"]!, $"{employee.FullName}.jpg");
|
var photo = await PhotosManager.GetEmployeePhotoAsync(employee);
|
||||||
try
|
|
||||||
{
|
|
||||||
await using var fileStream = new FileStream(
|
|
||||||
photoPath,
|
|
||||||
FileMode.Open,
|
|
||||||
FileAccess.Read
|
|
||||||
);
|
|
||||||
|
|
||||||
await Bot.SendPhoto(
|
if (photo != null)
|
||||||
|
{
|
||||||
|
var msg = await Bot.SendPhoto(
|
||||||
chatId,
|
chatId,
|
||||||
fileStream,
|
photo,
|
||||||
caption: card,
|
caption: card,
|
||||||
parseMode: ParseMode.Html,
|
parseMode: ParseMode.Html,
|
||||||
replyMarkup: keyboardMarkup
|
replyMarkup: keyboardMarkup
|
||||||
);
|
);
|
||||||
|
if (photo.FileType == FileType.Stream)
|
||||||
|
{
|
||||||
|
FileStream? stream = (photo as InputFileStream)!.Content as FileStream;
|
||||||
|
stream?.Dispose();
|
||||||
|
await PhotosManager.CacheEmployeePhotoAsync(employee, msg.Photo!.FirstOrDefault()!.FileId); // TODO test !
|
||||||
|
//await PhotosManager.CacheEmployeePhotoAsync(employee, msg.Photo.FirstOrDefault().FileId);
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
await Bot.SendMessage(
|
await Bot.SendMessage(
|
||||||
chatId,
|
chatId,
|
||||||
card,
|
card,
|
||||||
ParseMode.Html,
|
ParseMode.Html,
|
||||||
replyMarkup: keyboardMarkup,
|
replyMarkup: keyboardMarkup,
|
||||||
protectContent: true
|
protectContent: false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
await Task.Delay(999);
|
await Task.Delay(999);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ShowEmployeeResults(Message message, List<Employee> results, bool? isFavorite = false)
|
private static Dictionary<long, List<Employee>> _resultsCache = [];
|
||||||
|
|
||||||
|
private static async Task ShowEmployeeResults(Message message, List<Employee> results, bool? isFavorite = false, int page = 1, int pageSize = 10)
|
||||||
{
|
{
|
||||||
if (results.Any())
|
if (results.Any())
|
||||||
{
|
{
|
||||||
if (results.Count < 10)
|
if (results.Count <= pageSize)
|
||||||
{
|
{
|
||||||
foreach (var employee in results)
|
foreach (var employee in results)
|
||||||
{
|
{
|
||||||
bool bFavorite = isFavorite.HasValue ? isFavorite == true : await FavoritesManager.IsFavoriteAsync(message.From.Id, employee.Id);
|
bool bFavorite = isFavorite.HasValue ? isFavorite == true : await FavoritesManager.IsFavoriteAsync(message.Chat.Id, employee.Id);
|
||||||
await ShowEmployeeCard(message.Chat.Id, employee, bFavorite);
|
await ShowEmployeeCard(message.Chat.Id, employee, bFavorite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string text = "Вот, что удалось найти:";
|
var totalPages = (int)Math.Ceiling((double)results.Count / pageSize);
|
||||||
|
var pagedResults = results.Skip((page - 1) * pageSize).Take(pageSize).ToList();
|
||||||
|
|
||||||
|
string text = $"Найдено {results.Count} сотрудников (страница {page}/{totalPages}):";
|
||||||
var keyboardMarkup = new InlineKeyboardMarkup();
|
var keyboardMarkup = new InlineKeyboardMarkup();
|
||||||
|
|
||||||
foreach (var employee in results)
|
foreach (var employee in pagedResults)
|
||||||
{
|
{
|
||||||
|
var title = CreateEmployeeTitle(employee);
|
||||||
keyboardMarkup
|
keyboardMarkup
|
||||||
.AddNewRow()
|
.AddNewRow()
|
||||||
.AddButton(employee.FullName, $"showemployee/{employee.Id}");
|
.AddButton(title, $"showemployee/{employee.Id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
await Bot.SendMessage(message.Chat.Id, text, replyMarkup: keyboardMarkup, protectContent: true);
|
if (totalPages > 1)
|
||||||
|
{
|
||||||
|
var messageHash = results.GetHashCode();// (message.Chat.Id << 32) | (uint)message.Id;
|
||||||
|
_resultsCache[messageHash] = results;
|
||||||
|
|
||||||
|
var navigationRow = keyboardMarkup.AddNewRow();
|
||||||
|
navigationRow.AddPaginator(page, totalPages, $"employees/{messageHash}");
|
||||||
|
}
|
||||||
|
|
||||||
|
//keyboardMarkup.AddCloseButton();
|
||||||
|
await Bot.SendMessage(message.Chat.Id, text, replyMarkup: keyboardMarkup, protectContent: false);
|
||||||
await Task.Delay(999);
|
await Task.Delay(999);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -481,9 +582,14 @@ public class Program
|
|||||||
|
|
||||||
static string GetEventStatus(Employee employee)
|
static string GetEventStatus(Employee employee)
|
||||||
{
|
{
|
||||||
|
string result = "";
|
||||||
|
if (employee.Birthday)
|
||||||
|
{
|
||||||
|
result += "🎂 Празднует день рождения\n";
|
||||||
|
}
|
||||||
if (employee.StartDate == null || employee.EndDate == null)
|
if (employee.StartDate == null || employee.EndDate == null)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return result;
|
||||||
}
|
}
|
||||||
DateTime today = DateTime.Now;
|
DateTime today = DateTime.Now;
|
||||||
TimeSpan oneWeekBeforeEvent = (DateTime)employee.StartDate - today;
|
TimeSpan oneWeekBeforeEvent = (DateTime)employee.StartDate - today;
|
||||||
@@ -491,16 +597,58 @@ public class Program
|
|||||||
if (employee.StartDate <= today && today <= employee.EndDate)
|
if (employee.StartDate <= today && today <= employee.EndDate)
|
||||||
{
|
{
|
||||||
// Сотрудник участвует в событии
|
// Сотрудник участвует в событии
|
||||||
return $"🟥 {employee.State} с {employee.StartDate:dd.MM.yyyy} по {employee.EndDate:dd.MM.yyyy}";
|
result += $"🟥 {employee.State} с {employee.StartDate:dd.MM.yyyy} по {employee.EndDate:dd.MM.yyyy}";
|
||||||
}
|
}
|
||||||
else if (oneWeekBeforeEvent.TotalDays <= 7 && oneWeekBeforeEvent.TotalDays > 0)
|
else if (oneWeekBeforeEvent.TotalDays <= 7 && oneWeekBeforeEvent.TotalDays > 0)
|
||||||
{
|
{
|
||||||
// Событие начнется через неделю
|
// Событие начнется через неделю
|
||||||
return $"🟩 {employee.State} с {employee.StartDate:dd.MM.yyyy} по {employee.EndDate:dd.MM.yyyy}";
|
result += $"🟩 {employee.State} с {employee.StartDate:dd.MM.yyyy} по {employee.EndDate:dd.MM.yyyy}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
// Если событие не указано или неактуально
|
// Если событие не указано или неактуально
|
||||||
return string.Empty;
|
//return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string CreateEmployeeTitle(Employee employee)
|
||||||
|
{
|
||||||
|
EmployeeContact contact = new(employee);
|
||||||
|
|
||||||
|
string prefix = string.Empty;
|
||||||
|
|
||||||
|
if (employee.StartDate != null || employee.EndDate != null)
|
||||||
|
{
|
||||||
|
DateTime today = DateTime.Now;
|
||||||
|
TimeSpan oneWeekBeforeEvent = (DateTime)employee.StartDate! - today;
|
||||||
|
|
||||||
|
if (employee.StartDate <= today && today <= employee.EndDate)
|
||||||
|
{
|
||||||
|
// Сотрудник участвует в событии
|
||||||
|
prefix += "🟥";
|
||||||
|
}
|
||||||
|
else if (oneWeekBeforeEvent.TotalDays <= 7 && oneWeekBeforeEvent.TotalDays > 0)
|
||||||
|
{
|
||||||
|
// Событие начнется через неделю
|
||||||
|
prefix += "🟩";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (employee.Birthday)
|
||||||
|
{
|
||||||
|
prefix += "🎂";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(prefix))
|
||||||
|
{
|
||||||
|
//prefix = "👤 ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prefix += " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{prefix}{contact.ShortName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string CreateEmployeeCard(Employee employee)
|
private static string CreateEmployeeCard(Employee employee)
|
||||||
@@ -508,8 +656,10 @@ public class Program
|
|||||||
EmployeeContact contact = new(employee);
|
EmployeeContact contact = new(employee);
|
||||||
string card =
|
string card =
|
||||||
$"👤 <b>{contact.FullName}</b>\n"
|
$"👤 <b>{contact.FullName}</b>\n"
|
||||||
+ $"🏢 {contact.Department}\n"
|
+ $"🏢 {contact.Department}\n";
|
||||||
+ $"🎓 {contact.Position}\n";
|
|
||||||
|
if (!string.IsNullOrEmpty(contact.Position))
|
||||||
|
card += $"🎓 {contact.Position}\n";
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(contact.Mail))
|
if (!string.IsNullOrEmpty(contact.Mail))
|
||||||
card += $"✉️ {contact.Mail}\n";
|
card += $"✉️ {contact.Mail}\n";
|
||||||
@@ -527,31 +677,6 @@ public class Program
|
|||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string CreateEmployeeCard2(Employee employee)
|
|
||||||
{
|
|
||||||
string photoUrl =
|
|
||||||
$"https://contacts.int.nssz.ru/data/photos/{employee.FullName.Replace(" ", "%20")}.jpg"; // Формирование пути к фотографии
|
|
||||||
|
|
||||||
string card =
|
|
||||||
$"👤 <b>{employee.FullName}</b>\n"
|
|
||||||
+ $"🏢 Отдел: {employee.Department}\n"
|
|
||||||
+ $"🎓 Должность: {employee.Position}\n"
|
|
||||||
+ $"📸 Фото: <a href='{photoUrl}'>Посмотреть фото</a>\n"; // Добавление ссылки на фото
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(employee.Mail))
|
|
||||||
card += $"✉️ Почта: {employee.Mail}\n";
|
|
||||||
if (!string.IsNullOrEmpty(employee.Phone))
|
|
||||||
card += $"📞 Телефон: {employee.Phone}\n";
|
|
||||||
if (!string.IsNullOrEmpty(employee.Mobile))
|
|
||||||
card += $"📱 Мобильный: +{employee.Mobile}\n";
|
|
||||||
if (!string.IsNullOrEmpty(employee.IP))
|
|
||||||
card += $"🌐 IP: {employee.IP}\n";
|
|
||||||
|
|
||||||
card += GetEventStatus(employee);
|
|
||||||
|
|
||||||
return card;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Timer? updateTimer = null;
|
private static Timer? updateTimer = null;
|
||||||
private static void StartUpdatingEmployeesData(int intervalMs = 1 * 60 * 60 * 1000)
|
private static void StartUpdatingEmployeesData(int intervalMs = 1 * 60 * 60 * 1000)
|
||||||
{
|
{
|
||||||
@@ -572,8 +697,22 @@ public class Program
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
string filePath = config["Paths:ContactsJsonPath"] ?? string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(filePath))
|
||||||
|
{
|
||||||
|
string json;
|
||||||
|
if (filePath.StartsWith("http", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
using var client = new HttpClient();
|
||||||
|
using HttpResponseMessage response = client.GetAsync(filePath).Result;
|
||||||
|
using HttpContent content = response.Content;
|
||||||
|
json = content.ReadAsStringAsync().Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json = File.ReadAllText(filePath);
|
||||||
|
}
|
||||||
// Загрузка данных сотрудников из JSON файла при наличии изменений
|
// Загрузка данных сотрудников из JSON файла при наличии изменений
|
||||||
var json = System.IO.File.ReadAllText(config["Paths:ContactsJsonPath"]!);
|
|
||||||
int newHash = json.GetHashCode();
|
int newHash = json.GetHashCode();
|
||||||
if (prevHash == newHash)
|
if (prevHash == newHash)
|
||||||
{
|
{
|
||||||
@@ -581,14 +720,55 @@ public class Program
|
|||||||
}
|
}
|
||||||
prevHash = newHash;
|
prevHash = newHash;
|
||||||
Employees = JsonConvert.DeserializeObject<List<Employee>>(json)!;
|
Employees = JsonConvert.DeserializeObject<List<Employee>>(json)!;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Employees.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath = config["Paths:PersistentContactsJsonPath"] ?? string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(filePath))
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(filePath);
|
||||||
|
Employees.AddRange(JsonConvert.DeserializeObject<List<Employee>>(json)!);
|
||||||
|
}
|
||||||
|
if (Employees.Count > 0)
|
||||||
|
{
|
||||||
Log.Information("Загружены данные о {Count} сотрудниках", Employees.Count);
|
Log.Information("Загружены данные о {Count} сотрудниках", Employees.Count);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception ex) {
|
}
|
||||||
|
Log.Error("Нет данных о сотрудниках");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
Log.Error(ex, "Ошибка при загрузке списка сотрудников");
|
Log.Error(ex, "Ошибка при загрузке списка сотрудников");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void StartBirthdayNotifications()
|
||||||
|
{
|
||||||
|
var timer = new Timer(TimeSpan.FromHours(24).TotalMilliseconds);
|
||||||
|
timer.Elapsed += async (sender, e) =>
|
||||||
|
{
|
||||||
|
var today = DateTime.Today;
|
||||||
|
var birthdayEmployees = Employees.Where(e => e.Birthday).ToList();
|
||||||
|
foreach (var employee in birthdayEmployees)
|
||||||
|
{
|
||||||
|
var users = await FavoritesManager.GetUsersWithFavoriteAsync(employee.Id);
|
||||||
|
foreach (var userId in users)
|
||||||
|
{
|
||||||
|
await Bot.SendMessage(userId, $"🎂 Сегодня день рождения у {employee.FullName}!");
|
||||||
|
await Task.Delay(999);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timer.AutoReset = true;
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
private static Task HandleErrorAsync(
|
private static Task HandleErrorAsync(
|
||||||
ITelegramBotClient botClient,
|
ITelegramBotClient botClient,
|
||||||
Exception exception,
|
Exception exception,
|
||||||
|
|||||||
+13
-7
@@ -1,21 +1,27 @@
|
|||||||
{
|
{
|
||||||
"Paths": {
|
"Paths": {
|
||||||
"ContactsJsonPath": "data/contacts.json",
|
"ContactsJsonPath": "http://contacts.nssz.local/data/contacts.json",
|
||||||
"PhotoBasePath": "data/photos"
|
"PersistentContactsJsonPath": "PersistentContacts.json",
|
||||||
|
"PhotoBasePath": "photos"
|
||||||
},
|
},
|
||||||
"Telegram": {
|
"Telegram": {
|
||||||
"BotToken": "8155021946:AAGbfJnLa0sTWxqFB9yjbXhbTedBw4wvcQE"
|
"BotToken": "8155021946:AAGbfJnLa0sTWxqFB9yjbXhbTedBw4wvcQE"
|
||||||
},
|
},
|
||||||
"Redis": {
|
"Redis": {
|
||||||
"Configuration": "redis-15840.crce198.eu-central-1-3.ec2.redns.redis-cloud.com:15840",
|
"Configuration": "contacts.nssz.local:6379",
|
||||||
"User": "tgbot",
|
"User": "default",
|
||||||
"Password": "0aCKMee9Ocq88KzfjWyC9AmB25tLiY93%"
|
"Password": ""
|
||||||
},
|
},
|
||||||
"Serilog": {
|
"Serilog": {
|
||||||
"Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
|
"Using": [
|
||||||
|
"Serilog.Sinks.Console",
|
||||||
|
"Serilog.Sinks.File"
|
||||||
|
],
|
||||||
"MinimumLevel": "Debug",
|
"MinimumLevel": "Debug",
|
||||||
"WriteTo": [
|
"WriteTo": [
|
||||||
{ "Name": "Console" },
|
{
|
||||||
|
"Name": "Console"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Name": "File",
|
"Name": "File",
|
||||||
"Args": {
|
"Args": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -20,6 +20,9 @@
|
|||||||
<None Update="appsettings.json">
|
<None Update="appsettings.json">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="PersistentContacts.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user