139 lines
5.4 KiB
C#
139 lines
5.4 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using QRRapidoApp.Services;
|
|
using System.Diagnostics;
|
|
|
|
namespace QRRapidoApp.Controllers
|
|
{
|
|
/// <summary>
|
|
/// Controller for tracking QR code scans (Premium feature)
|
|
/// Handles redirect URLs and analytics
|
|
/// </summary>
|
|
[Route("t")]
|
|
public class TrackingController : ControllerBase
|
|
{
|
|
private readonly IUserService _userService;
|
|
private readonly ILogger<TrackingController> _logger;
|
|
|
|
public TrackingController(IUserService userService, ILogger<TrackingController> logger)
|
|
{
|
|
_userService = userService;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Track QR code scan and redirect to original URL
|
|
/// URL format: https://qrrapido.site/t/{trackingId}
|
|
/// </summary>
|
|
[HttpGet("{trackingId}")]
|
|
public async Task<IActionResult> TrackAndRedirect(string trackingId)
|
|
{
|
|
var stopwatch = Stopwatch.StartNew();
|
|
|
|
using (_logger.BeginScope(new Dictionary<string, object>
|
|
{
|
|
["TrackingId"] = trackingId,
|
|
["QRTracking"] = true
|
|
}))
|
|
{
|
|
_logger.LogInformation("QR tracking request - TrackingId: {TrackingId}", trackingId);
|
|
|
|
try
|
|
{
|
|
// Get QR code from database
|
|
var qr = await _userService.GetQRByTrackingIdAsync(trackingId);
|
|
|
|
if (qr == null)
|
|
{
|
|
_logger.LogWarning("QR code not found for tracking - TrackingId: {TrackingId}", trackingId);
|
|
return NotFound("QR code not found");
|
|
}
|
|
|
|
// Increment scan count and update last access (fire and forget for performance)
|
|
_ = Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
await _userService.IncrementQRScanCountAsync(trackingId);
|
|
_logger.LogDebug("QR scan count incremented - TrackingId: {TrackingId}, NewCount: {NewCount}",
|
|
trackingId, qr.ScanCount + 1);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error incrementing scan count - TrackingId: {TrackingId}", trackingId);
|
|
}
|
|
});
|
|
|
|
stopwatch.Stop();
|
|
_logger.LogInformation("QR redirect - TrackingId: {TrackingId}, Destination: {Destination}, ProcessingTime: {ProcessingTimeMs}ms",
|
|
trackingId, qr.Content, stopwatch.ElapsedMilliseconds);
|
|
|
|
// Redirect to original URL (HTTP 302 temporary redirect)
|
|
return Redirect(qr.Content);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
stopwatch.Stop();
|
|
_logger.LogError(ex, "QR tracking failed - TrackingId: {TrackingId}, ProcessingTime: {ProcessingTimeMs}ms",
|
|
trackingId, stopwatch.ElapsedMilliseconds);
|
|
|
|
// Return error page instead of exposing exception details
|
|
return StatusCode(500, "Error processing QR code");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get analytics for a specific QR code (requires authentication)
|
|
/// </summary>
|
|
[HttpGet("analytics/{trackingId}")]
|
|
public async Task<IActionResult> GetAnalytics(string trackingId)
|
|
{
|
|
var userId = User?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
|
|
|
|
if (string.IsNullOrEmpty(userId))
|
|
{
|
|
_logger.LogWarning("Analytics request without authentication - TrackingId: {TrackingId}", trackingId);
|
|
return Unauthorized();
|
|
}
|
|
|
|
try
|
|
{
|
|
var qr = await _userService.GetQRByTrackingIdAsync(trackingId);
|
|
|
|
if (qr == null)
|
|
{
|
|
_logger.LogWarning("Analytics request for non-existent QR - TrackingId: {TrackingId}", trackingId);
|
|
return NotFound();
|
|
}
|
|
|
|
// Verify ownership
|
|
if (qr.UserId != userId)
|
|
{
|
|
_logger.LogWarning("Analytics request for QR owned by different user - TrackingId: {TrackingId}, RequestingUser: {UserId}, Owner: {OwnerId}",
|
|
trackingId, userId, qr.UserId);
|
|
return Forbid();
|
|
}
|
|
|
|
_logger.LogInformation("Analytics retrieved - TrackingId: {TrackingId}, UserId: {UserId}, ScanCount: {ScanCount}",
|
|
trackingId, userId, qr.ScanCount);
|
|
|
|
return Ok(new
|
|
{
|
|
trackingId = qr.TrackingId,
|
|
scanCount = qr.ScanCount,
|
|
createdAt = qr.CreatedAt,
|
|
lastAccessedAt = qr.LastAccessedAt,
|
|
content = qr.Content,
|
|
type = qr.Type
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error retrieving analytics - TrackingId: {TrackingId}, UserId: {UserId}",
|
|
trackingId, userId);
|
|
return StatusCode(500);
|
|
}
|
|
}
|
|
}
|
|
}
|