using System.Security.Cryptography;
using System.Text;
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using MktXService.Infrastructure.ExternalServices.Twitter;
namespace MktXService.API.Controllers;
///
/// EN: Controller for Twitter Webhook handling.
/// VI: Controller xử lý Twitter Webhook.
///
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/webhooks/twitter")]
[Produces("application/json")]
[Authorize]
public class WebhooksController : ControllerBase
{
private readonly ITwitterApiClient _twitterClient;
private readonly TwitterApiOptions _options;
private readonly ILogger _logger;
public WebhooksController(
ITwitterApiClient twitterClient,
IOptions options,
ILogger logger)
{
_twitterClient = twitterClient;
_options = options.Value;
_logger = logger;
}
///
/// EN: CRC token verification for Twitter webhook.
/// VI: Xác thực CRC token cho Twitter webhook.
///
[HttpGet]
[AllowAnonymous]
[ProducesResponseType(StatusCodes.Status200OK)]
public IActionResult VerifyCrcToken([FromQuery(Name = "crc_token")] string crcToken)
{
_logger.LogInformation("Received CRC challenge: {Token}", crcToken);
var response = _twitterClient.GenerateCrcResponse(crcToken);
return Ok(new { response_token = response });
}
///
/// EN: Receive Twitter webhook events.
/// VI: Nhận events từ Twitter webhook.
///
[HttpPost]
[AllowAnonymous]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task ReceiveWebhookEvent([FromBody] TwitterWebhookPayload payload)
{
_logger.LogInformation("Received webhook event for user: {UserId}", payload.ForUserId);
// EN: Process Direct Message events
// VI: Xử lý events Direct Message
if (payload.DirectMessageEvents?.Any() == true)
{
foreach (var dmEvent in payload.DirectMessageEvents)
{
_logger.LogInformation("Received DM from {SenderId}: {MessageId}",
dmEvent.MessageCreate?.SenderId, dmEvent.Id);
// EN: In production, queue for async processing
// VI: Trong production, đưa vào hàng đợi để xử lý bất đồng bộ
}
}
// EN: Process follow events
// VI: Xử lý events follow
if (payload.FollowEvents?.Any() == true)
{
foreach (var followEvent in payload.FollowEvents)
{
_logger.LogInformation("New follower: {FollowerId}",
followEvent.Source?.Id);
}
}
return Ok();
}
///
/// EN: Register webhook for an account.
/// VI: Đăng ký webhook cho tài khoản.
///
[HttpPost("register")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task RegisterWebhook([FromBody] RegisterWebhookRequest request)
{
try
{
var webhookId = await _twitterClient.RegisterWebhookAsync(request.WebhookUrl);
return Ok(new { success = true, webhookId });
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to register webhook");
return BadRequest(new { success = false, error = ex.Message });
}
}
///
/// EN: Subscribe to webhook events.
/// VI: Đăng ký nhận webhook events.
///
[HttpPost("subscribe")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task SubscribeToWebhook()
{
try
{
await _twitterClient.SubscribeToWebhookAsync();
return Ok(new { success = true, message = "Subscribed to webhook events" });
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to subscribe to webhook");
return BadRequest(new { success = false, error = ex.Message });
}
}
}
#region Webhook DTOs
public class TwitterWebhookPayload
{
public string? ForUserId { get; set; }
public List? DirectMessageEvents { get; set; }
public List? FollowEvents { get; set; }
public Dictionary? Users { get; set; }
}
public class DirectMessageEvent
{
public string? Id { get; set; }
public string? Type { get; set; }
public string? CreatedTimestamp { get; set; }
public MessageCreate? MessageCreate { get; set; }
}
public class MessageCreate
{
public string? SenderId { get; set; }
public string? Target { get; set; }
public MessageData? MessageData { get; set; }
}
public class MessageData
{
public string? Text { get; set; }
public List