littleshop/LittleShop/Areas/Admin/Controllers/BotsController.cs

393 lines
13 KiB
C#

using System;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using LittleShop.DTOs;
using LittleShop.Enums;
using LittleShop.Services;
namespace LittleShop.Areas.Admin.Controllers;
[Area("Admin")]
[Authorize(Policy = "AdminOnly")]
public class BotsController : Controller
{
private readonly IBotService _botService;
private readonly IBotMetricsService _metricsService;
private readonly ITelegramBotManagerService _telegramManager;
private readonly ILogger<BotsController> _logger;
public BotsController(
IBotService botService,
IBotMetricsService metricsService,
ITelegramBotManagerService telegramManager,
ILogger<BotsController> logger)
{
_botService = botService;
_metricsService = metricsService;
_telegramManager = telegramManager;
_logger = logger;
}
// GET: Admin/Bots
public async Task<IActionResult> Index()
{
var bots = await _botService.GetAllBotsAsync();
return View(bots);
}
// GET: Admin/Bots/Details/5
public async Task<IActionResult> Details(Guid id)
{
var bot = await _botService.GetBotByIdAsync(id);
if (bot == null)
return NotFound();
// Get metrics summary for the last 30 days
var metricsSummary = await _metricsService.GetMetricsSummaryAsync(id, DateTime.UtcNow.AddDays(-30), DateTime.UtcNow);
ViewData["MetricsSummary"] = metricsSummary;
// Get active sessions
var activeSessions = await _metricsService.GetBotSessionsAsync(id, activeOnly: true);
ViewData["ActiveSessions"] = activeSessions;
return View(bot);
}
// GET: Admin/Bots/Create
public IActionResult Create()
{
return View(new BotRegistrationDto());
}
// GET: Admin/Bots/Wizard
public IActionResult Wizard()
{
return View(new BotWizardDto());
}
// POST: Admin/Bots/Wizard
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Wizard(BotWizardDto dto)
{
Console.WriteLine("=== BOT WIZARD DEBUG ===");
Console.WriteLine($"Received: BotName='{dto?.BotName}', BotUsername='{dto?.BotUsername}', PersonalityName='{dto?.PersonalityName}'");
Console.WriteLine($"ModelState.IsValid: {ModelState.IsValid}");
Console.WriteLine("Raw form data:");
foreach (var key in Request.Form.Keys)
{
Console.WriteLine($" {key} = '{Request.Form[key]}'");
}
Console.WriteLine("========================");
_logger.LogInformation("Wizard POST received - BotName: '{BotName}', BotUsername: '{BotUsername}'", dto.BotName, dto.BotUsername);
if (!ModelState.IsValid)
{
_logger.LogWarning("Validation failed");
foreach (var error in ModelState)
{
_logger.LogWarning("Field {Field}: {Errors}", error.Key, string.Join(", ", error.Value.Errors.Select(e => e.ErrorMessage)));
}
return View(dto);
}
// Auto-assign personality if not selected
if (string.IsNullOrEmpty(dto.PersonalityName))
{
var personalities = new[] { "Alan", "Dave", "Sarah", "Mike", "Emma", "Tom" };
var random = new Random();
dto.PersonalityName = personalities[random.Next(personalities.Length)];
Console.WriteLine($"Auto-assigned personality: {dto.PersonalityName}");
}
// Generate BotFather commands
var commands = GenerateBotFatherCommands(dto);
ViewData["BotFatherCommands"] = commands;
ViewData["ShowCommands"] = true;
_logger.LogInformation("Generated BotFather commands successfully for bot '{BotName}' with personality '{PersonalityName}'", dto.BotName, dto.PersonalityName);
return View(dto);
}
// POST: Admin/Bots/CompleteWizard
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CompleteWizard(BotWizardDto dto)
{
if (string.IsNullOrEmpty(dto.BotToken))
{
ModelState.AddModelError("BotToken", "Bot token is required");
ViewData["BotFatherCommands"] = GenerateBotFatherCommands(dto);
ViewData["ShowCommands"] = true;
return View("Wizard", dto);
}
// Validate token first
if (!await ValidateTelegramToken(dto.BotToken))
{
ModelState.AddModelError("BotToken", "Invalid bot token");
ViewData["BotFatherCommands"] = GenerateBotFatherCommands(dto);
ViewData["ShowCommands"] = true;
return View("Wizard", dto);
}
// Create the bot
var registrationDto = new BotRegistrationDto
{
Name = dto.BotName,
Description = dto.Description,
Type = BotType.Telegram,
Version = "1.0.0",
PersonalityName = dto.PersonalityName,
InitialSettings = new Dictionary<string, object>
{
["telegram"] = new { botToken = dto.BotToken },
["personality"] = new { name = dto.PersonalityName }
}
};
try
{
var result = await _botService.RegisterBotAsync(registrationDto);
// Add bot to Telegram manager
var telegramAdded = await _telegramManager.AddBotAsync(result.BotId, dto.BotToken);
if (telegramAdded)
{
TempData["Success"] = $"Bot '{result.Name}' created successfully and is now running on Telegram!";
}
else
{
TempData["Warning"] = $"Bot '{result.Name}' created but failed to connect to Telegram. Check token.";
}
return RedirectToAction(nameof(Details), new { id = result.BotId });
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create bot");
ModelState.AddModelError("", $"Failed to create bot: {ex.Message}");
return View("Wizard", dto);
}
}
// POST: Admin/Bots/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(BotRegistrationDto dto)
{
_logger.LogInformation("Received bot registration: Name={Name}, Type={Type}, Version={Version}",
dto?.Name, dto?.Type, dto?.Version);
if (!ModelState.IsValid)
{
_logger.LogWarning("Model validation failed for bot registration");
foreach (var error in ModelState.Values.SelectMany(v => v.Errors))
{
_logger.LogWarning("Validation error: {Error}", error.ErrorMessage);
}
return View(dto);
}
try
{
var result = await _botService.RegisterBotAsync(dto);
_logger.LogInformation("Bot registered successfully: {BotId}, Key: {KeyPrefix}...",
result.BotId, result.BotKey.Substring(0, 8));
TempData["BotKey"] = result.BotKey;
TempData["Success"] = $"Bot '{result.Name}' created successfully. Save the API key securely!";
return RedirectToAction(nameof(Details), new { id = result.BotId });
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create bot");
ModelState.AddModelError("", $"Failed to create bot: {ex.Message}");
return View(dto);
}
}
// GET: Admin/Bots/Edit/5
public async Task<IActionResult> Edit(Guid id)
{
var bot = await _botService.GetBotByIdAsync(id);
if (bot == null)
return NotFound();
ViewData["BotSettings"] = JsonSerializer.Serialize(bot.Settings, new JsonSerializerOptions { WriteIndented = true });
return View(bot);
}
// POST: Admin/Bots/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(Guid id, string settingsJson, BotStatus status)
{
try
{
// Parse and update settings
var settings = JsonSerializer.Deserialize<Dictionary<string, object>>(settingsJson) ?? new Dictionary<string, object>();
var updateDto = new UpdateBotSettingsDto { Settings = settings };
await _botService.UpdateBotSettingsAsync(id, updateDto);
await _botService.UpdateBotStatusAsync(id, status);
TempData["Success"] = "Bot updated successfully";
return RedirectToAction(nameof(Details), new { id });
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to update bot");
TempData["Error"] = "Failed to update bot";
return RedirectToAction(nameof(Edit), new { id });
}
}
// GET: Admin/Bots/Metrics/5
public async Task<IActionResult> Metrics(Guid id, DateTime? startDate, DateTime? endDate)
{
var bot = await _botService.GetBotByIdAsync(id);
if (bot == null)
return NotFound();
var start = startDate ?? DateTime.UtcNow.AddDays(-7);
var end = endDate ?? DateTime.UtcNow;
var metricsSummary = await _metricsService.GetMetricsSummaryAsync(id, start, end);
var sessionSummary = await _metricsService.GetSessionSummaryAsync(id, start, end);
ViewData["Bot"] = bot;
ViewData["SessionSummary"] = sessionSummary;
ViewData["StartDate"] = start;
ViewData["EndDate"] = end;
return View(metricsSummary);
}
// POST: Admin/Bots/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Delete(Guid id)
{
var success = await _botService.DeleteBotAsync(id);
if (!success)
{
TempData["Error"] = "Failed to delete bot";
return RedirectToAction(nameof(Index));
}
TempData["Success"] = "Bot deleted successfully";
return RedirectToAction(nameof(Index));
}
// POST: Admin/Bots/Suspend/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Suspend(Guid id)
{
await _botService.UpdateBotStatusAsync(id, BotStatus.Suspended);
TempData["Success"] = "Bot suspended";
return RedirectToAction(nameof(Details), new { id });
}
// POST: Admin/Bots/Activate/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Activate(Guid id)
{
await _botService.UpdateBotStatusAsync(id, BotStatus.Active);
TempData["Success"] = "Bot activated";
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
public IActionResult RegenerateKey(Guid id)
{
// This would require updating the bot model to support key regeneration
TempData["Error"] = "Key regeneration not yet implemented";
return RedirectToAction(nameof(Details), new { id });
}
private string GenerateBotFatherCommands(BotWizardDto dto)
{
var commands = new List<string>
{
"1. Open Telegram and find @BotFather",
"2. Send: /newbot",
$"3. Send bot name: {dto.BotName}",
$"4. Send bot username: {dto.BotUsername}",
"5. Copy the token from BotFather's response",
"6. Paste the token in the field below"
};
if (!string.IsNullOrEmpty(dto.Description))
{
commands.Add($"7. Optional: Send /setdescription and then: {dto.Description}");
}
return string.Join("\n", commands);
}
private async Task<bool> ValidateTelegramToken(string token)
{
try
{
using var httpClient = new HttpClient();
var response = await httpClient.GetAsync($"https://api.telegram.org/bot{token}/getMe");
return response.IsSuccessStatusCode;
}
catch
{
return false;
}
}
}