Fix: Refactor TeleBot messaging to use database queue

This commit is contained in:
SysAdmin 2025-10-06 17:22:06 +01:00
parent 6c95ed3145
commit b265c89a72
3 changed files with 35 additions and 63 deletions

View File

@ -41,7 +41,8 @@
"Bash(/tmp/fix-celery-beat.sh:*)", "Bash(/tmp/fix-celery-beat.sh:*)",
"Bash(/tmp/bypass-hdwallet-unlock.sh:*)", "Bash(/tmp/bypass-hdwallet-unlock.sh:*)",
"Bash(/tmp/fix-db-initialization.sh:*)", "Bash(/tmp/fix-db-initialization.sh:*)",
"SlashCommand(/code-review)" "SlashCommand(/code-review)",
"Read(//mnt/c/Production/Source/SilverLABS/SilverPAY.NET/**)"
], ],
"deny": [], "deny": [],
"ask": [] "ask": []

View File

@ -223,7 +223,7 @@ builder.Services.AddScoped<IMessageDeliveryService, MessageDeliveryService>();
builder.Services.AddScoped<ICustomerService, CustomerService>(); builder.Services.AddScoped<ICustomerService, CustomerService>();
builder.Services.AddScoped<ICustomerMessageService, CustomerMessageService>(); builder.Services.AddScoped<ICustomerMessageService, CustomerMessageService>();
builder.Services.AddScoped<IPushNotificationService, PushNotificationService>(); builder.Services.AddScoped<IPushNotificationService, PushNotificationService>();
builder.Services.AddHttpClient<ITeleBotMessagingService, TeleBotMessagingService>(); builder.Services.AddScoped<ITeleBotMessagingService, TeleBotMessagingService>();
builder.Services.AddScoped<IProductImportService, ProductImportService>(); builder.Services.AddScoped<IProductImportService, ProductImportService>();
builder.Services.AddSingleton<ITelegramBotManagerService, TelegramBotManagerService>(); builder.Services.AddSingleton<ITelegramBotManagerService, TelegramBotManagerService>();
builder.Services.AddScoped<IBotActivityService, BotActivityService>(); builder.Services.AddScoped<IBotActivityService, BotActivityService>();

View File

@ -1,9 +1,7 @@
using System.Text;
using System.Text.Json;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using LittleShop.Data; using LittleShop.Data;
using LittleShop.DTOs;
using LittleShop.Enums; using LittleShop.Enums;
using LittleShop.Models; using LittleShop.Models;
@ -12,25 +10,17 @@ namespace LittleShop.Services;
public class TeleBotMessagingService : ITeleBotMessagingService public class TeleBotMessagingService : ITeleBotMessagingService
{ {
private readonly LittleShopContext _context; private readonly LittleShopContext _context;
private readonly IConfiguration _configuration; private readonly ICustomerMessageService _customerMessageService;
private readonly ILogger<TeleBotMessagingService> _logger; private readonly ILogger<TeleBotMessagingService> _logger;
private readonly HttpClient _httpClient;
private readonly string? _teleBotApiUrl;
private readonly string? _teleBotApiKey;
public TeleBotMessagingService( public TeleBotMessagingService(
LittleShopContext context, LittleShopContext context,
IConfiguration configuration, ICustomerMessageService customerMessageService,
ILogger<TeleBotMessagingService> logger, ILogger<TeleBotMessagingService> logger)
HttpClient httpClient)
{ {
_context = context; _context = context;
_configuration = configuration; _customerMessageService = customerMessageService;
_logger = logger; _logger = logger;
_httpClient = httpClient;
_teleBotApiUrl = _configuration["TeleBot:ApiUrl"];
_teleBotApiKey = _configuration["TeleBot:ApiKey"];
} }
public async Task<bool> SendOrderStatusUpdateAsync(Guid orderId, OrderStatus newStatus) public async Task<bool> SendOrderStatusUpdateAsync(Guid orderId, OrderStatus newStatus)
@ -58,7 +48,7 @@ public class TeleBotMessagingService : ITeleBotMessagingService
$"📦 Total: £{order.TotalAmount:F2}\n" + $"📦 Total: £{order.TotalAmount:F2}\n" +
$"⏱️ Expected processing: Within 24 hours"; $"⏱️ Expected processing: Within 24 hours";
return await SendTeleBotMessageAsync(order.Customer.TelegramUserId, message); return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Payment Confirmed", message);
} }
public async Task<bool> SendOrderAcceptedAsync(Guid orderId) public async Task<bool> SendOrderAcceptedAsync(Guid orderId)
@ -72,7 +62,7 @@ public class TeleBotMessagingService : ITeleBotMessagingService
$"⏱️ Expected packing: Within 24 hours\n" + $"⏱️ Expected packing: Within 24 hours\n" +
$"🚚 We'll notify you when it's dispatched"; $"🚚 We'll notify you when it's dispatched";
return await SendTeleBotMessageAsync(order.Customer.TelegramUserId, message); return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Order Accepted", message);
} }
public async Task<bool> SendOrderPackingAsync(Guid orderId) public async Task<bool> SendOrderPackingAsync(Guid orderId)
@ -85,7 +75,7 @@ public class TeleBotMessagingService : ITeleBotMessagingService
$"🚚 We'll send tracking details once dispatched.\n" + $"🚚 We'll send tracking details once dispatched.\n" +
$"⏱️ Expected dispatch: Later today"; $"⏱️ Expected dispatch: Later today";
return await SendTeleBotMessageAsync(order.Customer.TelegramUserId, message); return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Order Packing", message);
} }
public async Task<bool> SendOrderDispatchedAsync(Guid orderId, string? trackingNumber = null) public async Task<bool> SendOrderDispatchedAsync(Guid orderId, string? trackingNumber = null)
@ -103,7 +93,7 @@ public class TeleBotMessagingService : ITeleBotMessagingService
$"⏱️ Estimated delivery: 1-3 working days\n" + $"⏱️ Estimated delivery: 1-3 working days\n" +
$"📍 Track your package for real-time updates"; $"📍 Track your package for real-time updates";
return await SendTeleBotMessageAsync(order.Customer.TelegramUserId, message); return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.ShippingInfo, "Order Dispatched", message);
} }
public async Task<bool> SendOrderDeliveredAsync(Guid orderId) public async Task<bool> SendOrderDeliveredAsync(Guid orderId)
@ -116,7 +106,7 @@ public class TeleBotMessagingService : ITeleBotMessagingService
$"⭐ Please consider leaving a review using the /review command.\n" + $"⭐ Please consider leaving a review using the /review command.\n" +
$"🛒 Thank you for choosing us for your order!"; $"🛒 Thank you for choosing us for your order!";
return await SendTeleBotMessageAsync(order.Customer.TelegramUserId, message); return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Order Delivered", message);
} }
public async Task<bool> SendOrderOnHoldAsync(Guid orderId, string? reason = null) public async Task<bool> SendOrderOnHoldAsync(Guid orderId, string? reason = null)
@ -133,7 +123,7 @@ public class TeleBotMessagingService : ITeleBotMessagingService
$"💬 Please contact support if you have any questions.\n" + $"💬 Please contact support if you have any questions.\n" +
$"⏱️ We'll resolve this as quickly as possible"; $"⏱️ We'll resolve this as quickly as possible";
return await SendTeleBotMessageAsync(order.Customer.TelegramUserId, message); return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Order On Hold", message);
} }
public async Task<bool> SendTestMessageAsync(Guid customerId, string message) public async Task<bool> SendTestMessageAsync(Guid customerId, string message)
@ -142,25 +132,14 @@ public class TeleBotMessagingService : ITeleBotMessagingService
if (customer == null) return false; if (customer == null) return false;
var testMessage = $"🧪 *Test Message*\n\n{message}"; var testMessage = $"🧪 *Test Message*\n\n{message}";
return await SendTeleBotMessageAsync(customer.TelegramUserId, testMessage); return await QueueMessageAsync(customerId, null, MessageType.CustomerService, "Test Message", testMessage);
} }
public async Task<bool> IsAvailableAsync() public async Task<bool> IsAvailableAsync()
{ {
if (string.IsNullOrEmpty(_teleBotApiUrl) || string.IsNullOrEmpty(_teleBotApiKey)) // TeleBot is always "available" since it polls for messages from the database queue
{ // No need to check HTTP endpoint availability
return false; return true;
}
try
{
var response = await _httpClient.GetAsync($"{_teleBotApiUrl}/health");
return response.IsSuccessStatusCode;
}
catch
{
return false;
}
} }
private async Task<Order?> GetOrderWithCustomerAsync(Guid orderId) private async Task<Order?> GetOrderWithCustomerAsync(Guid orderId)
@ -170,48 +149,40 @@ public class TeleBotMessagingService : ITeleBotMessagingService
.FirstOrDefaultAsync(o => o.Id == orderId); .FirstOrDefaultAsync(o => o.Id == orderId);
} }
private async Task<bool> SendTeleBotMessageAsync(long telegramUserId, string message) private async Task<bool> QueueMessageAsync(Guid customerId, Guid? orderId, MessageType type, string subject, string content)
{ {
if (!await IsAvailableAsync())
{
_logger.LogWarning("TeleBot API not available, skipping message to user {UserId}", telegramUserId);
return false;
}
try try
{ {
var requestData = new var createMessageDto = new CreateCustomerMessageDto
{ {
userId = telegramUserId, CustomerId = customerId,
message = message, OrderId = orderId,
parseMode = "Markdown" Type = type,
Subject = subject,
Content = content,
Priority = 5, // Normal priority
IsUrgent = false
}; };
var json = JsonSerializer.Serialize(requestData); var result = await _customerMessageService.CreateMessageAsync(createMessageDto);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// Add API key header if (result != null)
_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Add("X-API-Key", _teleBotApiKey);
var response = await _httpClient.PostAsync($"{_teleBotApiUrl}/api/messages/send", content);
if (response.IsSuccessStatusCode)
{ {
_logger.LogInformation("Successfully sent TeleBot message to user {UserId}", telegramUserId); _logger.LogInformation("Queued message {MessageId} for customer {CustomerId} - {Subject}",
result.Id, customerId, subject);
return true; return true;
} }
else else
{ {
var responseContent = await response.Content.ReadAsStringAsync(); _logger.LogWarning("Failed to queue message for customer {CustomerId} - {Subject}",
_logger.LogWarning("Failed to send TeleBot message to user {UserId}: {StatusCode} - {Response}", customerId, subject);
telegramUserId, response.StatusCode, responseContent);
return false; return false;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Error sending TeleBot message to user {UserId}", telegramUserId); _logger.LogError(ex, "Error queuing message for customer {CustomerId} - {Subject}",
customerId, subject);
return false; return false;
} }
} }