feat: Bot management improvements with wallet configuration and duplicate detection
This commit is contained in:
parent
91000035f5
commit
7008a95df3
@ -42,10 +42,12 @@
|
|||||||
"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/**)"
|
"Read(//mnt/c/Production/Source/SilverLABS/SilverPAY.NET/**)",
|
||||||
|
"Bash(sqlite3:*)",
|
||||||
|
"Bash(git checkout:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
},
|
},
|
||||||
"outputStyle": "enterprise-full-stack-developer"
|
"outputStyle": "enterprise-full-stack-developer"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -307,6 +307,47 @@ public class BotsController : Controller
|
|||||||
return RedirectToAction(nameof(Details), new { id });
|
return RedirectToAction(nameof(Details), new { id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST: Admin/Bots/UpdateWallets/5
|
||||||
|
[HttpPost]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
|
public async Task<IActionResult> UpdateWallets(Guid id, Dictionary<string, string> wallets)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bot = await _botService.GetBotByIdAsync(id);
|
||||||
|
if (bot == null)
|
||||||
|
{
|
||||||
|
TempData["Error"] = "Bot not found";
|
||||||
|
return RedirectToAction(nameof(Index));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current settings
|
||||||
|
var settings = bot.Settings ?? new Dictionary<string, object>();
|
||||||
|
|
||||||
|
// Filter out empty wallet addresses
|
||||||
|
var validWallets = wallets
|
||||||
|
.Where(w => !string.IsNullOrWhiteSpace(w.Value))
|
||||||
|
.ToDictionary(w => w.Key, w => w.Value.Trim());
|
||||||
|
|
||||||
|
// Update or add wallets section
|
||||||
|
settings["wallets"] = validWallets;
|
||||||
|
|
||||||
|
// Save settings
|
||||||
|
await _botService.UpdateBotSettingsAsync(id, new UpdateBotSettingsDto { Settings = settings });
|
||||||
|
|
||||||
|
_logger.LogInformation("Updated {Count} wallet addresses for bot {BotId}", validWallets.Count, id);
|
||||||
|
TempData["Success"] = $"Updated {validWallets.Count} wallet address(es) successfully";
|
||||||
|
|
||||||
|
return RedirectToAction(nameof(Edit), new { id });
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to update wallets for bot {BotId}", id);
|
||||||
|
TempData["Error"] = "Failed to update wallet addresses";
|
||||||
|
return RedirectToAction(nameof(Edit), new { id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GET: Admin/Bots/RegenerateKey/5
|
// GET: Admin/Bots/RegenerateKey/5
|
||||||
public IActionResult RegenerateKey(Guid id)
|
public IActionResult RegenerateKey(Guid id)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -49,6 +49,63 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5 class="mb-0">💰 Payment Wallets</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="text-muted">Configure cryptocurrency wallet addresses for direct payments. These are used as fallback when payment gateway is unavailable.</p>
|
||||||
|
@{
|
||||||
|
var wallets = new Dictionary<string, string>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, System.Text.Json.JsonElement>>(@settingsJson);
|
||||||
|
if (settings != null && settings.ContainsKey("wallets"))
|
||||||
|
{
|
||||||
|
wallets = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(settings["wallets"].GetRawText()) ?? new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
var supportedCurrencies = new[] {
|
||||||
|
new { Code = "BTC", Name = "Bitcoin", Placeholder = "bc1q... or 1... or 3..." },
|
||||||
|
new { Code = "XMR", Name = "Monero", Placeholder = "4... (primary address)" },
|
||||||
|
new { Code = "LTC", Name = "Litecoin", Placeholder = "ltc1q... or L... or M..." },
|
||||||
|
new { Code = "DOGE", Name = "Dogecoin", Placeholder = "D..." },
|
||||||
|
new { Code = "ETH", Name = "Ethereum", Placeholder = "0x..." },
|
||||||
|
new { Code = "ZEC", Name = "Zcash", Placeholder = "t1... or zs1..." },
|
||||||
|
new { Code = "DASH", Name = "Dash", Placeholder = "X..." }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
<form asp-action="UpdateWallets" asp-route-id="@Model.Id" method="post" id="walletsForm">
|
||||||
|
@Html.AntiForgeryToken()
|
||||||
|
@foreach (var currency in supportedCurrencies)
|
||||||
|
{
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="wallet_@currency.Code" class="form-label">
|
||||||
|
<strong>@currency.Code</strong> - @currency.Name
|
||||||
|
</label>
|
||||||
|
<input type="text"
|
||||||
|
name="wallets[@currency.Code]"
|
||||||
|
id="wallet_@currency.Code"
|
||||||
|
class="form-control font-monospace"
|
||||||
|
placeholder="@currency.Placeholder"
|
||||||
|
value="@(wallets.ContainsKey(currency.Code) ? wallets[currency.Code] : "")" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<strong>Note:</strong> Only configured wallets will be available as payment options. Leave blank to disable direct payments for that cryptocurrency.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary w-100">
|
||||||
|
<i class="bi bi-wallet2"></i> Save Wallet Addresses
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h5 class="mb-0">Bot Configuration (JSON)</h5>
|
<h5 class="mb-0">Bot Configuration (JSON)</h5>
|
||||||
|
|||||||
@ -15,6 +15,86 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@{
|
||||||
|
// Detect duplicates by platform username
|
||||||
|
var duplicateGroups = Model
|
||||||
|
.Where(b => !string.IsNullOrEmpty(b.PlatformUsername))
|
||||||
|
.GroupBy(b => b.PlatformUsername)
|
||||||
|
.Where(g => g.Count() > 1)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (duplicateGroups.Any())
|
||||||
|
{
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<h5 class="alert-heading"><i class="bi bi-exclamation-triangle"></i> Duplicate Bots Detected</h5>
|
||||||
|
<p>Found <strong>@duplicateGroups.Count duplicate bot group(s)</strong> with multiple entries for the same Telegram username.</p>
|
||||||
|
<p>This usually happens when the bot container restarts without a saved API key. The system now prevents this automatically.</p>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary" data-bs-toggle="collapse" data-bs-target="#duplicateDetails">
|
||||||
|
Show Details
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div id="duplicateDetails" class="collapse mt-3">
|
||||||
|
@foreach (var group in duplicateGroups)
|
||||||
|
{
|
||||||
|
<div class="card mb-2">
|
||||||
|
<div class="card-body">
|
||||||
|
<h6 class="card-title">@@@group.Key (@group.Count() entries)</h6>
|
||||||
|
<table class="table table-sm">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Created</th>
|
||||||
|
<th>Last Seen</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Sessions</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var bot in group.OrderByDescending(b => b.LastSeenAt ?? b.CreatedAt))
|
||||||
|
{
|
||||||
|
var isNewest = bot == group.OrderByDescending(b => b.LastSeenAt ?? b.CreatedAt).First();
|
||||||
|
<tr class="@(isNewest ? "table-success" : "")">
|
||||||
|
<td>@bot.CreatedAt.ToString("yyyy-MM-dd HH:mm")</td>
|
||||||
|
<td>
|
||||||
|
@if (bot.LastSeenAt.HasValue)
|
||||||
|
{
|
||||||
|
@bot.LastSeenAt.Value.ToString("yyyy-MM-dd HH:mm")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<span class="text-muted">Never</span>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td><span class="badge bg-@(bot.Status == LittleShop.Enums.BotStatus.Active ? "success" : "secondary")">@bot.Status</span></td>
|
||||||
|
<td>@bot.TotalSessions</td>
|
||||||
|
<td>
|
||||||
|
@if (isNewest)
|
||||||
|
{
|
||||||
|
<span class="badge bg-success">Keep (Most Recent)</span>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<form action="/Admin/Bots/Delete/@bot.Id" method="post" style="display:inline;">
|
||||||
|
@Html.AntiForgeryToken()
|
||||||
|
<button type="submit" class="btn btn-sm btn-outline-danger"
|
||||||
|
onclick="return confirm('Delete this duplicate bot entry? Sessions: @bot.TotalSessions')">
|
||||||
|
<i class="bi bi-trash"></i> Delete
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@if (TempData["Success"] != null)
|
@if (TempData["Success"] != null)
|
||||||
{
|
{
|
||||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||||
|
|||||||
@ -54,6 +54,25 @@ public class BotsController : ControllerBase
|
|||||||
return Ok(bot);
|
return Ok(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("by-platform/{platformType}/{platformUsername}")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public async Task<ActionResult<BotDto>> GetBotByPlatformUsername(int platformType, string platformUsername)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bot = await _botService.GetBotByPlatformUsernameAsync(platformType, platformUsername);
|
||||||
|
if (bot == null)
|
||||||
|
return NotFound($"Bot not found for platform {platformType} with username {platformUsername}");
|
||||||
|
|
||||||
|
return Ok(bot);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to find bot by platform username {Platform}/@{Username}", platformType, platformUsername);
|
||||||
|
return StatusCode(500, "Internal server error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Bot Settings
|
// Bot Settings
|
||||||
[HttpGet("settings")]
|
[HttpGet("settings")]
|
||||||
public async Task<ActionResult<Dictionary<string, object>>> GetBotSettings()
|
public async Task<ActionResult<Dictionary<string, object>>> GetBotSettings()
|
||||||
|
|||||||
@ -98,16 +98,31 @@ public class BotWizardDto
|
|||||||
[Required(ErrorMessage = "Bot name is required")]
|
[Required(ErrorMessage = "Bot name is required")]
|
||||||
[StringLength(50)]
|
[StringLength(50)]
|
||||||
public string BotName { get; set; } = string.Empty;
|
public string BotName { get; set; } = string.Empty;
|
||||||
|
|
||||||
[Required(ErrorMessage = "Bot username is required")]
|
[Required(ErrorMessage = "Bot username is required")]
|
||||||
[StringLength(100)]
|
[StringLength(100)]
|
||||||
public string BotUsername { get; set; } = string.Empty;
|
public string BotUsername { get; set; } = string.Empty;
|
||||||
|
|
||||||
[StringLength(500)]
|
[StringLength(500)]
|
||||||
public string Description { get; set; } = string.Empty;
|
public string Description { get; set; } = string.Empty;
|
||||||
|
|
||||||
[StringLength(50)]
|
[StringLength(50)]
|
||||||
public string PersonalityName { get; set; } = string.Empty;
|
public string PersonalityName { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string BotToken { get; set; } = string.Empty;
|
public string BotToken { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateBotWalletsDto
|
||||||
|
{
|
||||||
|
public Dictionary<string, string> Wallets { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BotWalletEntry
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public string Currency { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(500)]
|
||||||
|
public string Address { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
@ -99,6 +99,27 @@ public class BotService : IBotService
|
|||||||
return bot != null ? MapToDto(bot) : null;
|
return bot != null ? MapToDto(bot) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<BotDto?> GetBotByPlatformUsernameAsync(int platformType, string platformUsername)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var bot = await _context.Bots
|
||||||
|
.Include(b => b.Sessions)
|
||||||
|
.Include(b => b.Metrics)
|
||||||
|
.FirstOrDefaultAsync(b =>
|
||||||
|
b.Type == (BotType)platformType &&
|
||||||
|
b.PlatformUsername == platformUsername &&
|
||||||
|
b.Status != BotStatus.Deleted);
|
||||||
|
|
||||||
|
return bot != null ? MapToDto(bot) : null;
|
||||||
|
}
|
||||||
|
catch (Microsoft.Data.Sqlite.SqliteException ex) when (ex.Message.Contains("no such table"))
|
||||||
|
{
|
||||||
|
// Tables don't exist yet - return null
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<BotDto>> GetAllBotsAsync()
|
public async Task<IEnumerable<BotDto>> GetAllBotsAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@ -12,6 +12,7 @@ public interface IBotService
|
|||||||
Task<BotDto?> AuthenticateBotAsync(string botKey);
|
Task<BotDto?> AuthenticateBotAsync(string botKey);
|
||||||
Task<BotDto?> GetBotByIdAsync(Guid id);
|
Task<BotDto?> GetBotByIdAsync(Guid id);
|
||||||
Task<BotDto?> GetBotByKeyAsync(string botKey);
|
Task<BotDto?> GetBotByKeyAsync(string botKey);
|
||||||
|
Task<BotDto?> GetBotByPlatformUsernameAsync(int platformType, string platformUsername);
|
||||||
Task<IEnumerable<BotDto>> GetAllBotsAsync();
|
Task<IEnumerable<BotDto>> GetAllBotsAsync();
|
||||||
Task<IEnumerable<BotDto>> GetActiveBots();
|
Task<IEnumerable<BotDto>> GetActiveBots();
|
||||||
Task<bool> UpdateBotSettingsAsync(Guid botId, UpdateBotSettingsDto dto);
|
Task<bool> UpdateBotSettingsAsync(Guid botId, UpdateBotSettingsDto dto);
|
||||||
|
|||||||
@ -52,11 +52,37 @@ namespace TeleBot.Services
|
|||||||
{
|
{
|
||||||
// Check if bot key exists in configuration
|
// Check if bot key exists in configuration
|
||||||
_botKey = _configuration["BotManager:ApiKey"];
|
_botKey = _configuration["BotManager:ApiKey"];
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_botKey))
|
if (string.IsNullOrEmpty(_botKey))
|
||||||
{
|
{
|
||||||
// Register new bot
|
// Try to find existing bot registration by Telegram username first
|
||||||
await RegisterBotAsync();
|
var botUsername = await GetTelegramBotUsernameAsync();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(botUsername))
|
||||||
|
{
|
||||||
|
var existingBot = await FindExistingBotByPlatformAsync(botUsername);
|
||||||
|
|
||||||
|
if (existingBot != null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Found existing bot registration for @{Username} (ID: {BotId}). Using existing bot.",
|
||||||
|
botUsername, existingBot.Id);
|
||||||
|
_botKey = existingBot.BotKey;
|
||||||
|
_botId = existingBot.Id;
|
||||||
|
|
||||||
|
// Update platform info in case it changed
|
||||||
|
await UpdatePlatformInfoAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("No existing bot found for @{Username}. Registering new bot.", botUsername);
|
||||||
|
await RegisterBotAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Could not determine bot username. Registering new bot.");
|
||||||
|
await RegisterBotAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -125,18 +151,21 @@ namespace TeleBot.Services
|
|||||||
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
var response = await _httpClient.PostAsync($"{apiUrl}/api/bots/register", content);
|
var response = await _httpClient.PostAsync($"{apiUrl}/api/bots/register", content);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
var responseJson = await response.Content.ReadAsStringAsync();
|
var responseJson = await response.Content.ReadAsStringAsync();
|
||||||
var result = JsonSerializer.Deserialize<BotRegistrationResponse>(responseJson);
|
var result = JsonSerializer.Deserialize<BotRegistrationResponse>(responseJson);
|
||||||
|
|
||||||
_botKey = result?.BotKey;
|
_botKey = result?.BotKey;
|
||||||
_botId = result?.BotId;
|
_botId = result?.BotId;
|
||||||
|
|
||||||
_logger.LogInformation("Bot registered successfully. Bot ID: {BotId}", _botId);
|
_logger.LogInformation("Bot registered successfully. Bot ID: {BotId}", _botId);
|
||||||
_logger.LogWarning("IMPORTANT: Save this bot key securely: {BotKey}", _botKey);
|
_logger.LogWarning("IMPORTANT: Save this bot key securely: {BotKey}", _botKey);
|
||||||
|
|
||||||
|
// Update platform info immediately after registration
|
||||||
|
await UpdatePlatformInfoAsync();
|
||||||
|
|
||||||
// Save bot key to configuration or secure storage
|
// Save bot key to configuration or secure storage
|
||||||
// In production, this should be saved securely
|
// In production, this should be saved securely
|
||||||
}
|
}
|
||||||
@ -423,6 +452,118 @@ namespace TeleBot.Services
|
|||||||
_settingsSyncTimer?.Dispose();
|
_settingsSyncTimer?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string?> GetTelegramBotUsernameAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var botToken = _configuration["Telegram:BotToken"];
|
||||||
|
if (string.IsNullOrEmpty(botToken) || botToken == "YOUR_BOT_TOKEN_HERE")
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Bot token not configured in appsettings.json");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call Telegram API to get bot info
|
||||||
|
var response = await _httpClient.GetAsync($"https://api.telegram.org/bot{botToken}/getMe");
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var responseJson = await response.Content.ReadAsStringAsync();
|
||||||
|
var result = JsonSerializer.Deserialize<TelegramGetMeResponse>(responseJson);
|
||||||
|
return result?.Result?.Username;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Failed to get bot info from Telegram: {StatusCode}", response.StatusCode);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error getting Telegram bot username");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<BotDto?> FindExistingBotByPlatformAsync(string platformUsername)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var apiUrl = _configuration["LittleShop:ApiUrl"];
|
||||||
|
const int telegramBotType = 0; // BotType.Telegram enum value
|
||||||
|
|
||||||
|
var response = await _httpClient.GetAsync($"{apiUrl}/api/bots/by-platform/{telegramBotType}/{platformUsername}");
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var responseJson = await response.Content.ReadAsStringAsync();
|
||||||
|
var bot = JsonSerializer.Deserialize<BotDto>(responseJson);
|
||||||
|
return bot;
|
||||||
|
}
|
||||||
|
else if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
return null; // Bot not found - this is expected for first registration
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Failed to check for existing bot: {StatusCode}", response.StatusCode);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error finding existing bot by platform username");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdatePlatformInfoAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var apiUrl = _configuration["LittleShop:ApiUrl"];
|
||||||
|
var botToken = _configuration["Telegram:BotToken"];
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(botToken) || string.IsNullOrEmpty(_botKey))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Get bot info from Telegram
|
||||||
|
var telegramResponse = await _httpClient.GetAsync($"https://api.telegram.org/bot{botToken}/getMe");
|
||||||
|
if (!telegramResponse.IsSuccessStatusCode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var telegramJson = await telegramResponse.Content.ReadAsStringAsync();
|
||||||
|
var telegramResult = JsonSerializer.Deserialize<TelegramGetMeResponse>(telegramJson);
|
||||||
|
|
||||||
|
if (telegramResult?.Result == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update platform info in LittleShop
|
||||||
|
var updateData = new
|
||||||
|
{
|
||||||
|
PlatformUsername = telegramResult.Result.Username,
|
||||||
|
PlatformDisplayName = telegramResult.Result.FirstName ?? telegramResult.Result.Username,
|
||||||
|
PlatformId = telegramResult.Result.Id.ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
var json = JsonSerializer.Serialize(updateData);
|
||||||
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
_httpClient.DefaultRequestHeaders.Clear();
|
||||||
|
_httpClient.DefaultRequestHeaders.Add("X-Bot-Key", _botKey);
|
||||||
|
|
||||||
|
var response = await _httpClient.PutAsync($"{apiUrl}/api/bots/platform-info", content);
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Updated platform info for @{Username}", telegramResult.Result.Username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Failed to update platform info");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DTOs for API responses
|
// DTOs for API responses
|
||||||
private class BotRegistrationResponse
|
private class BotRegistrationResponse
|
||||||
{
|
{
|
||||||
@ -435,11 +576,29 @@ namespace TeleBot.Services
|
|||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string BotKey { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SessionDto
|
private class SessionDto
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TelegramGetMeResponse
|
||||||
|
{
|
||||||
|
public bool Ok { get; set; }
|
||||||
|
public TelegramBotInfo? Result { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TelegramBotInfo
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public bool IsBot { get; set; }
|
||||||
|
public string FirstName { get; set; } = string.Empty;
|
||||||
|
public string Username { get; set; } = string.Empty;
|
||||||
|
public bool? CanJoinGroups { get; set; }
|
||||||
|
public bool? CanReadAllGroupMessages { get; set; }
|
||||||
|
public bool? SupportsInlineQueries { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user